add dndstats component

master
koehr 4 years ago committed by Norman
parent 600af1679a
commit 136da9d694

@ -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>

@ -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…
Cancel
Save