diff --git a/shared/feature.util.ts b/shared/feature.util.ts index 222d6db..a6f7925 100644 --- a/shared/feature.util.ts +++ b/shared/feature.util.ts @@ -1,4 +1,4 @@ -import type { Ability, AspectConfig, CharacterConfig, Feature, FeatureEffect, FeatureItem, Level, MainStat, RaceConfig, Resistance, SpellConfig, TrainingLevel } from "~/types/character"; +import type { Ability, AspectConfig, CharacterConfig, Feature, FeatureChoice, FeatureEquipment, FeatureItem, FeatureList, FeatureValue, i18nID, Level, MainStat, RaceConfig, Resistance, SpellConfig, TrainingLevel } from "~/types/character"; import { div, dom, icon, text, type NodeChildren } from "#shared/dom.util"; import { MarkdownEditor } from "#shared/editor.util"; import { fakeA } from "#shared/proses"; @@ -458,14 +458,14 @@ export class FeatureEditor switch(buffer.category) { case 'value': - const valueVariable = () => typeof buffer.value === 'number' ? numberpicker({ defaultValue: buffer.value, input: (value) => { (buffer as Extract).value = value; summaryText.textContent = textFromEffect(buffer); }, class: 'bg-light-25 dark:bg-dark-25 !-m-px hover:z-10 h-[36px] w-[80px]' }) : select<`modifier/${MainStat}` | false>([...Object.entries(mainStatShortTexts).map(e => ({ text: 'Mod. de ' + e[1], value: `modifier/${e[0]}` as `modifier/${MainStat}` })), buffer.operation === 'add' ? undefined : { text: 'Interdit', value: false }], { class: { container: 'w-[160px] bg-light-25 dark:bg-dark-25 !-m-px hover:z-10 h-[36px]' }, defaultValue: buffer.value, change: (value) => { (buffer as Extract).value = value; summaryText.textContent = textFromEffect(buffer); } }); + const valueVariable = () => typeof buffer.value === 'number' ? numberpicker({ defaultValue: buffer.value, input: (value) => { (buffer as FeatureValue).value = value; summaryText.textContent = textFromEffect(buffer); }, class: 'bg-light-25 dark:bg-dark-25 !-m-px hover:z-10 h-[36px] w-[80px]' }) : select<`modifier/${MainStat}` | false>([...Object.entries(mainStatShortTexts).map(e => ({ text: 'Mod. de ' + e[1], value: `modifier/${e[0]}` as `modifier/${MainStat}` })), buffer.operation === 'add' ? undefined : { text: 'Interdit', value: false }], { class: { container: 'w-[160px] bg-light-25 dark:bg-dark-25 !-m-px hover:z-10 h-[36px]' }, defaultValue: buffer.value, change: (value) => { (buffer as FeatureValue).value = value; summaryText.textContent = textFromEffect(buffer); } }); const summaryText = text(textFromEffect(buffer)); let valueSelection = valueVariable(); top = [ - select([ (['action', 'reaction'].includes(buffer.property ?? '') ? undefined : { text: '+', value: 'add' }), (['speed', 'capacity', 'action', 'reaction'].includes(buffer.property ?? '') || ['defense/'].some(e => (buffer as Extract).property.startsWith(e))) ? { text: '=', value: 'set' } : undefined ], { defaultValue: buffer.operation, change: (value) => { (buffer as Extract).operation = value as 'add' | 'set'; summaryText.textContent = textFromEffect(buffer); }, class: { container: 'bg-light-25 dark:bg-dark-25 !-m-px hover:z-10 h-[36px] w-[80px]' } }), + select([ (['action', 'reaction'].includes(buffer.property ?? '') ? undefined : { text: '+', value: 'add' }), (['speed', 'capacity', 'action', 'reaction'].includes(buffer.property ?? '') || ['defense/'].some(e => (buffer as FeatureValue).property.startsWith(e))) ? { text: '=', value: 'set' } : undefined ], { defaultValue: buffer.operation, change: (value) => { (buffer as FeatureValue).operation = value as 'add' | 'set'; summaryText.textContent = textFromEffect(buffer); }, class: { container: 'bg-light-25 dark:bg-dark-25 !-m-px hover:z-10 h-[36px] w-[80px]' } }), valueSelection, tooltip(button(icon('radix-icons:update'), () => { - (buffer as Extract).value = (typeof (buffer as Extract).value === 'number' ? '' as any as false : 0); + (buffer as FeatureValue).value = (typeof (buffer as FeatureValue).value === 'number' ? '' as any as false : 0); const newValueSelection = valueVariable(); valueSelection.replaceWith(newValueSelection); valueSelection = newValueSelection; @@ -479,13 +479,13 @@ export class FeatureEditor { if(buffer.list === 'spells') { - bottom = [ combobox(config.spells.map(e => ({ text: e.name, render: () => div('flex flex-col', [ div('flex flex-row justify-between', [ dom('span', { text: e.name, class: 'font-bold' }), div('flex flex-row gap-8', [ dom('span', { class: 'italic', text: `Rang ${e.rank === 4 ? 'spécial' : e.rank}` }), dom('span', { text: spellTypeTexts[e.type] }) ]) ]), div('text-sm text-light-70 dark:text-dark-70', [ text(renderText(e.effect)) ]) ]), value: e.id })), { defaultValue: buffer.item, change: (value) => (buffer as Extract).item = value, class: { container: 'bg-light-25 dark:bg-dark-25 hover:z-10 h-[36px] w-full hover:outline-px outline-light-50 dark:outline-dark-50 !border-none' }, fill: 'contain' }) ]; + bottom = [ combobox(config.spells.map(e => ({ text: e.name, render: () => div('flex flex-col', [ div('flex flex-row justify-between', [ dom('span', { text: e.name, class: 'font-bold' }), div('flex flex-row gap-8', [ dom('span', { class: 'italic', text: `Rang ${e.rank === 4 ? 'spécial' : e.rank}` }), dom('span', { text: spellTypeTexts[e.type] }) ]) ]), div('text-sm text-light-70 dark:text-dark-70', [ text(renderText(e.effect)) ]) ]), value: e.id })), { defaultValue: buffer.item, change: (value) => (buffer as FeatureList).item = value, class: { container: 'bg-light-25 dark:bg-dark-25 hover:z-10 h-[36px] w-full hover:outline-px outline-light-50 dark:outline-dark-50 !border-none' }, fill: 'contain' }) ]; } else { const editor = new MarkdownEditor(); editor.content = getText(buffer.item); - editor.onChange = (item) => (buffer as Extract).item = item; + editor.onChange = (item) => (buffer as FeatureList).item = item; bottom = [ div('px-2 py-1 bg-light-25 dark:bg-dark-25 flex-1 flex items-center', [ editor.dom ]) ]; } @@ -495,7 +495,7 @@ export class FeatureEditor bottom = [ combobox(Object.values(config.features).flatMap(e => e.effect).filter(e => e.category === 'list' && e.list === buffer.list && e.action === 'add').map(e => ({ text: buffer.list !== 'spells' ? renderText(getText((e as Extract).item)) : config.spells.find(f => f.id === (e as Extract).item)?.name ?? '', value: (e as Extract).item })), { defaultValue: buffer.item, change: (item) => buffer.item = item, class: { container: 'bg-light-25 dark:bg-dark-25 !-m-px hover:z-10 h-[36px] w-full overflow-hidden truncate', option: 'max-h-[90px] text-sm' }, fill: 'contain' }) ]; } top = [ select([ { text: 'Ajouter', value: 'add' }, { text: 'Supprimer', value: 'remove' } ], { defaultValue: buffer.action, change: (value) => { - (buffer as Extract).action = value as 'add' | 'remove'; + (buffer as FeatureList).action = value as 'add' | 'remove'; const element = redraw(); content.replaceWith(element); content = element; @@ -601,13 +601,13 @@ const featureChoices: Option>[] = [ { text: 'Modifieur de charisme', value: { category: 'value', property: 'modifier/charisma', operation: 'add', value: 1 } }, { text: 'Modifieur de psyché', value: { category: 'value', property: 'modifier/psyche', operation: 'add', value: 1 } }, { text: 'Modifieur au choix', value: { category: 'choice', text: '+1 au modifieur de ', options: [ - { text: 'Modifieur de force', category: 'value', property: 'modifier/strength', operation: 'add', value: 1 }, - { text: 'Modifieur de dextérité', category: 'value', property: 'modifier/dexterity', operation: 'add', value: 1 }, - { text: 'Modifieur de constitution', category: 'value', property: 'modifier/constitution', operation: 'add', value: 1 }, - { text: 'Modifieur d\'intelligence', category: 'value', property: 'modifier/intelligence', operation: 'add', value: 1 }, - { text: 'Modifieur de curiosité', category: 'value', property: 'modifier/curiosity', operation: 'add', value: 1 }, - { text: 'Modifieur de charisme', category: 'value', property: 'modifier/charisma', operation: 'add', value: 1 }, - { text: 'Modifieur de psyché', egory: 'value', property: 'modifier/psyche', operation: 'add', value: 1 } + { text: 'Modifieur de force', effects: [ { category: 'value', property: 'modifier/strength', operation: 'add', value: 1 } ] }, + { text: 'Modifieur de dextérité', effects: [ { category: 'value', property: 'modifier/dexterity', operation: 'add', value: 1 } ] }, + { text: 'Modifieur de constitution', effects: [ { category: 'value', property: 'modifier/constitution', operation: 'add', value: 1 } ] }, + { text: 'Modifieur d\'intelligence', effects: [ { category: 'value', property: 'modifier/intelligence', operation: 'add', value: 1 } ] }, + { text: 'Modifieur de curiosité', effects: [ { category: 'value', property: 'modifier/curiosity', operation: 'add', value: 1 } ] }, + { text: 'Modifieur de charisme', effects: [ { category: 'value', property: 'modifier/charisma', operation: 'add', value: 1 } ] }, + { text: 'Modifieur de psyché', effects: [ { category: 'value', property: 'modifier/psyche', operation: 'add', value: 1 } ] } ]} as Partial} ] }, { text: 'Jet de résistance', value: [ @@ -619,14 +619,14 @@ const featureChoices: Option>[] = [ { text: 'Charisme', value: { category: 'value', property: 'bonus/defense/charisma', operation: 'add', value: 1 } }, { text: 'Psyché', value: { category: 'value', property: 'bonus/defense/psyche', operation: 'add', value: 1 } }, { text: 'Résistance au choix', value: { category: 'choice', text: '+1 au jet de résistance de ', options: [ - { text: 'Force', category: 'value', property: 'bonus/defense/strength', operation: 'add', value: 1 }, - { text: 'Dextérité', category: 'value', property: 'bonus/defense/dexterity', operation: 'add', value: 1 }, - { text: 'Constitution', category: 'value', property: 'bonus/defense/constitution', operation: 'add', value: 1 }, - { text: 'Intelligence', category: 'value', property: 'bonus/defense/intelligence', operation: 'add', value: 1 }, - { text: 'Curiosité', category: 'value', property: 'bonus/defense/curiosity', operation: 'add', value: 1 }, - { text: 'Charisme', category: 'value', property: 'bonus/defense/charisma', operation: 'add', value: 1 }, - { text: 'Psyché', egory: 'value', property: 'bonus/defense/psyche', operation: 'add', value: 1 } - ]} as Partial} + { text: 'Force', effects: [{ category: 'value', property: 'bonus/defense/strength', operation: 'add', value: 1 }] }, + { text: 'Dextérité', effects: [{ category: 'value', property: 'bonus/defense/dexterity', operation: 'add', value: 1 }] }, + { text: 'Constitution', effects: [{ category: 'value', property: 'bonus/defense/constitution', operation: 'add', value: 1 }] }, + { text: 'Intelligence', effects: [{ category: 'value', property: 'bonus/defense/intelligence', operation: 'add', value: 1 }] }, + { text: 'Curiosité', effects: [{ category: 'value', property: 'bonus/defense/curiosity', operation: 'add', value: 1 }] }, + { text: 'Charisme', effects: [{ category: 'value', property: 'bonus/defense/charisma', operation: 'add', value: 1 }] }, + { text: 'Psyché', effects: [{ category: 'value', property: 'bonus/defense/psyche', operation: 'add', value: 1 }] } + ]} as Partial} ] }, { text: 'Bonus', value: RESISTANCES.map(e => ({ text: resistanceTexts[e as Resistance], value: { category: 'value', property: `resistance/${e}`, operation: 'add', value: 1 } })) }, { text: 'Rang', value: [ @@ -643,7 +643,7 @@ const featureChoices: Option>[] = [ { text: 'Choix', value: { category: 'choice', text: '', options: [] }, }, ]; const flattenFeatureChoices = Tree.accumulate(featureChoices, 'value', (item) => Array.isArray(item.value) ? undefined : item.value).filter(e => !!e) as Partial[]; -function textFromEffect(effect: Partial): string +function textFromEffect(effect: Partial): string { if(effect.category === 'value') {