add dndstats component
parent
600af1679a
commit
136da9d694
@ -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
|
Loading…
Reference in New Issue