small refactoring and start to support list editing

tiptap
koehr 5 years ago
parent 9856ad8ed1
commit 986560d284

@ -1,6 +1,11 @@
<template>
<ul>
<li :key="param" v-for="param in params">{{ param }}</li>
<li v-for="(param, i) in params"
:key="`param${i}`"
v-editable:[i]="editable"
@keydown="handleKey(i, $event)">
{{ param }}
</li>
</ul>
</template>
@ -10,6 +15,30 @@ import { Component, Prop, Vue } from 'vue-property-decorator'
@Component
export default class DeckCardBulletList extends Vue {
@Prop() public readonly params!: string[]
@Prop() public readonly editable!: boolean
private addEntry (index: number) {
const newParams = [...this.params]
newParams.splice(index + 1, 0, '')
this.$emit('replace', newParams)
}
private removeEntry (index: number) {
const newParams = [...this.params]
newParams.splice(index, 1)
this.$emit('replace', newParams)
}
private handleKey (index: number, event: KeyboardEvent) {
const { key, shiftKey } = event
if (key === 'Enter' && shiftKey) {
event.preventDefault()
this.addEntry(index)
} else if (key === 'Backspace') {
const text = (event.target as HTMLElement).innerText
if (text.trim() === '') this.removeEntry(index)
}
}
}
</script>

@ -15,12 +15,13 @@
<button class="edit-close" @click.self.stop="$emit('close')" v-if="isSelection" />
</header>
<main>
<component v-for="(entry, i) in card.contents"
<component v-for="(entry, i) in card.content"
:is="`deck-card-${entry.type}`"
:key="`e${i}`"
:params="entry.params"
:editable="isSelection"
@edit="editContent(i, $event)"
@edit="editContentFieldParam(i, $event)"
@replace="replaceContentField(i, $event)"
/>
</main>
</section>
@ -89,18 +90,25 @@ export default class DeckCard extends Vue {
this.$emit('edit', payload)
}
private editContent (index: number, event: ContentEditEvent) {
const { param, value } = event
const field = this.card.contents[index]
const newContents = [...this.card.contents]
field.params[param] = value
newContents.splice(index, 1, field)
private replaceContentField (index: number, newParams: Field['params']) {
const newContent = [...this.card.content]
const newField = {
type: newContent[index].type,
params: newParams
}
newContent.splice(index, 1, newField)
const payload = { field: 'contents', value: newContents }
const payload = { field: 'content', value: newContent }
this.$emit('edit', payload)
}
private editContentFieldParam (index: number, event: ContentEditEvent) {
const { param, value } = event
const params = [...this.card.content[index].params]
params[param] = value
this.replaceContentField(index, params)
}
private get icon () {
const icon = this.card.icon || this.deck.icon
return iconPath(icon)

@ -5,7 +5,6 @@ const eventHandlers: { [key: string]: () => void } = {}
Vue.directive('editable', (el, { value, arg }, vnode) => {
const keypressHandler = (event: KeyboardEvent) => {
console.log('keypress', event.code)
// allow line break via Shift + Enter
if (event.keyCode === 13 && !event.shiftKey) {
event.preventDefault()

@ -45,6 +45,6 @@ export function defaultCard (): Card {
count: 1,
tags: [],
icon: 'robe',
contents: []
content: []
}
}

34
src/shims.d.ts vendored

@ -1,10 +1,17 @@
interface Settings {
color: string;
interface Field {
type: string;
params: (string | number)[];
}
interface StoredStuff {
decks: Deck[];
defaults: Settings;
interface Card {
id: string;
name: string;
count: number;
tags: string[];
icon: string;
content: Field[];
backIcon?: string;
color?: string;
}
interface Deck {
@ -19,18 +26,11 @@ interface Deck {
titleFontSize?: number;
}
interface Card {
id: string;
name: string;
count: number;
tags: string[];
icon: string;
contents: CardContent[];
backIcon?: string;
color?: string;
interface Settings {
color: string;
}
interface CardContent {
type: string;
params: (string | number)[];
interface StoredStuff {
decks: Deck[];
defaults: Settings;
}

@ -70,7 +70,7 @@ export default class DeckView extends Vue {
count: 1,
tags: ['foo', 'test'],
icon: 'robe',
contents: [
content: [
{ type: 'subtitle', params: ['1st Level Enchantment'] },
{ type: 'rule', params: ['pointing-right'] },
{ type: 'property', params: ['Casting Time', '1 Action'] },
@ -89,7 +89,7 @@ export default class DeckView extends Vue {
count: 1,
tags: ['fire', 'test'],
icon: 'robe',
contents: [
content: [
{ type: 'subtitle', params: ['1st Level Evocation'] },
{ type: 'rule', params: ['pointing-right'] },
{ type: 'property', params: ['Casting Time', '1 Action'] },
@ -109,7 +109,7 @@ export default class DeckView extends Vue {
count: 1,
tags: ['wand', 'test'],
icon: 'robe',
contents: [
content: [
{ type: 'subtitle', params: ['Wondrous Item'] },
{ type: 'rule', params: ['pointing-right'] },
{ type: 'property', params: ['Maximum charges', '7'] },
@ -128,7 +128,7 @@ export default class DeckView extends Vue {
count: 1,
tags: ['goblin', 'test'],
icon: 'robe',
contents: [
content: [
{ type: 'subtitle', params: ['Small humanoid (goblinoid)'] },
{ type: 'rule', params: ['pointing-right'] },
{ type: 'property', params: ['Armor Class', '15 (leather armor)'] },

Loading…
Cancel
Save