add dndstats component
This commit is contained in:
parent
600af1679a
commit
136da9d694
3 changed files with 142 additions and 2 deletions
|
@ -7,7 +7,7 @@ import { Component, Prop, Vue } from 'vue-property-decorator'
|
||||||
|
|
||||||
import Editor from '@editorjs/editorjs'
|
import Editor from '@editorjs/editorjs'
|
||||||
import List from '@editorjs/list'
|
import List from '@editorjs/list'
|
||||||
import { Heading, Delimiter, Charges } from '@/editor'
|
import { Heading, Delimiter, Charges, DnDStats } from '@/editor'
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
export default class DeckCardEditor extends Vue {
|
export default class DeckCardEditor extends Vue {
|
||||||
|
@ -30,7 +30,8 @@ export default class DeckCardEditor extends Vue {
|
||||||
list: { class: List, inlineToolbar: true },
|
list: { class: List, inlineToolbar: true },
|
||||||
heading: { class: Heading, inlineToolbar: true },
|
heading: { class: Heading, inlineToolbar: true },
|
||||||
delimiter: { class: Delimiter, inlineToolbar: false },
|
delimiter: { class: Delimiter, inlineToolbar: false },
|
||||||
charges: { class: Charges, inlineToolbar: false }
|
charges: { class: Charges, inlineToolbar: false },
|
||||||
|
dndstats: { class: DnDStats, inlineToolbar: false }
|
||||||
},
|
},
|
||||||
data: this.content,
|
data: this.content,
|
||||||
placeholder: 'Click here to write your card.',
|
placeholder: 'Click here to write your card.',
|
||||||
|
@ -126,5 +127,37 @@ export default class DeckCardEditor extends Vue {
|
||||||
.card-content .card-charges-wrapper > .card-charge-size-3 { width: 1.4em; height: 1.4em; }
|
.card-content .card-charges-wrapper > .card-charge-size-3 { width: 1.4em; height: 1.4em; }
|
||||||
.card-content .card-charges-wrapper > .card-charge-size-4 { width: 1.6em; height: 1.6em; }
|
.card-content .card-charges-wrapper > .card-charge-size-4 { width: 1.6em; height: 1.6em; }
|
||||||
.card-content .card-charges-wrapper > .card-charge-size-5 { width: 1.8em; height: 1.8em; }
|
.card-content .card-charges-wrapper > .card-charge-size-5 { width: 1.8em; height: 1.8em; }
|
||||||
|
|
||||||
|
.card-content .card-dnd-stats {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
justify-content: space-around;
|
||||||
|
align-items: center;
|
||||||
|
color: var(--highlight-color);
|
||||||
|
}
|
||||||
|
.card-content .dnd-stat-block {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row wrap;
|
||||||
|
font-size: .8em;
|
||||||
|
}
|
||||||
|
.card-content .dnd-stat-block > .dnd-stat-title {
|
||||||
|
width: 100%;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.card-content .dnd-stat-block > input {
|
||||||
|
width: 50%;
|
||||||
|
background: white;
|
||||||
|
color: var(--highlight-color);
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.card-content .dnd-stat-block {
|
||||||
|
}
|
||||||
|
|
||||||
[contenteditable="true"] { outline: none; }
|
[contenteditable="true"] { outline: none; }
|
||||||
</style>
|
</style>
|
||||||
|
|
106
src/editor/dnd-stats.ts
Normal file
106
src/editor/dnd-stats.ts
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
import { ContentlessBlock, BlockToolArgs } from './contentless-block'
|
||||||
|
import icon from '../assets/editor/charges-circle.svg.txt'
|
||||||
|
|
||||||
|
const title = 'DnDStats'
|
||||||
|
|
||||||
|
interface DnDStatsData {
|
||||||
|
text: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
class DnDStats extends ContentlessBlock {
|
||||||
|
static _toolboxConfig = { icon, title }
|
||||||
|
private _stats = [10, 10, 10, 10, 10, 10]
|
||||||
|
|
||||||
|
constructor (args: BlockToolArgs) {
|
||||||
|
super(args)
|
||||||
|
this.data = args.data as DnDStatsData
|
||||||
|
this._element = this._render()
|
||||||
|
}
|
||||||
|
|
||||||
|
public get data () {
|
||||||
|
return {
|
||||||
|
text: this._stats.join(',')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public set data (data: DnDStatsData) {
|
||||||
|
if (data.text === undefined) data.text = ''
|
||||||
|
|
||||||
|
const newStats = data.text.split(',')
|
||||||
|
.map(x => parseInt(x, 10))
|
||||||
|
.filter(x => !Number.isNaN(x))
|
||||||
|
|
||||||
|
while (newStats.length < 6) newStats.push(10) // fill missing stats
|
||||||
|
|
||||||
|
this._stats = newStats
|
||||||
|
}
|
||||||
|
|
||||||
|
// creates a random four character long id
|
||||||
|
private randomId (): string {
|
||||||
|
const min = 46656 // '1000'
|
||||||
|
const max = 1679615 /* 'zzzz' */ - 46656 /* '1000' */
|
||||||
|
return (min + Math.floor(max * Math.random())).toString(36)
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderStatMod (value: number): string {
|
||||||
|
const mod = Math.floor((value - 10) / 2.0)
|
||||||
|
const sign = mod < 0 ? '' : '+'
|
||||||
|
return ` (${sign}${mod})`
|
||||||
|
}
|
||||||
|
|
||||||
|
private createStatBlock (title: string, value: number, changeHandler: (newValue: number) => void): HTMLElement {
|
||||||
|
const id = `dnd-stat-${title}-${this.randomId()}`
|
||||||
|
|
||||||
|
const labelWrapper = document.createElement('label')
|
||||||
|
const titleEl = document.createElement('span')
|
||||||
|
const statInputEl = document.createElement('input')
|
||||||
|
const statModEl = document.createElement('span')
|
||||||
|
|
||||||
|
// should allow focussing block with tab
|
||||||
|
labelWrapper.setAttribute('z-index', '1')
|
||||||
|
labelWrapper.classList.add('dnd-stat-block')
|
||||||
|
labelWrapper.setAttribute('for', id)
|
||||||
|
|
||||||
|
titleEl.classList.add('dnd-stat-title')
|
||||||
|
titleEl.innerText = title
|
||||||
|
|
||||||
|
statInputEl.id = id
|
||||||
|
statInputEl.value = `${value}`
|
||||||
|
statInputEl.addEventListener('input', () => {
|
||||||
|
const value = parseInt(statInputEl.value, 10)
|
||||||
|
statModEl.innerText = this.renderStatMod(value)
|
||||||
|
changeHandler(value)
|
||||||
|
})
|
||||||
|
|
||||||
|
statModEl.innerText = this.renderStatMod(value)
|
||||||
|
|
||||||
|
labelWrapper.appendChild(titleEl)
|
||||||
|
labelWrapper.appendChild(statInputEl)
|
||||||
|
labelWrapper.appendChild(statModEl)
|
||||||
|
|
||||||
|
return labelWrapper
|
||||||
|
}
|
||||||
|
|
||||||
|
protected _render (): HTMLElement {
|
||||||
|
const el = document.createElement('div')
|
||||||
|
el.classList.add('card-dnd-stats')
|
||||||
|
const stats = this._stats || [10, 10, 10, 10, 10, 10]
|
||||||
|
const titles = ['STR', 'DEX', 'CON', 'INT', 'WIS', 'CHA']
|
||||||
|
|
||||||
|
stats.forEach((stat, i) => {
|
||||||
|
const title = titles[i]
|
||||||
|
const block = this.createStatBlock(title, stat, newValue => {
|
||||||
|
this._stats[i] = newValue
|
||||||
|
})
|
||||||
|
el.appendChild(block)
|
||||||
|
})
|
||||||
|
|
||||||
|
return el
|
||||||
|
}
|
||||||
|
|
||||||
|
public save (): DnDStatsData {
|
||||||
|
return this.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DnDStats
|
|
@ -2,3 +2,4 @@ export { default as Delimiter } from './delimiter'
|
||||||
export { default as Heading } from './heading'
|
export { default as Heading } from './heading'
|
||||||
export { default as List } from './list'
|
export { default as List } from './list'
|
||||||
export { default as Charges } from './charges'
|
export { default as Charges } from './charges'
|
||||||
|
export { default as DnDStats } from './dnd-stats'
|
||||||
|
|
Loading…
Add table
Reference in a new issue