Nearly finished FeatureEditor for choices
This commit is contained in:
parent
06276b3fbc
commit
658499749d
BIN
db.sqlite-shm
BIN
db.sqlite-shm
Binary file not shown.
BIN
db.sqlite-wal
BIN
db.sqlite-wal
Binary file not shown.
File diff suppressed because one or more lines are too long
|
|
@ -63,18 +63,19 @@ export class HomebrewBuilder
|
|||
|
||||
this._content?.replaceChildren(...this._tabsContent[tab]!.dom);
|
||||
}
|
||||
edit(feature: Feature)
|
||||
edit(feature: Feature): Promise<Feature>
|
||||
{
|
||||
const promise = this._editor.edit(feature).then(f => {
|
||||
const promise: Promise<Feature> = this._editor.edit(feature).then(f => {
|
||||
this._config.features[feature.id] = f;
|
||||
}).finally(() => {
|
||||
return f;
|
||||
}).catch(() => feature).finally(() => {
|
||||
setTimeout(popup.close, 150);
|
||||
this._editor.container.setAttribute('data-state', 'inactive');
|
||||
});
|
||||
const popup = fullblocker([this._editor.container], {
|
||||
priority: true, closeWhenOutside: false,
|
||||
});
|
||||
this._editor.container.setAttribute('data-state', 'active');
|
||||
setTimeout(() => this._editor.container.setAttribute('data-state', 'active'), 1);
|
||||
return promise;
|
||||
}
|
||||
private save()
|
||||
|
|
@ -133,9 +134,14 @@ class TrainingEditor extends BuilderTab
|
|||
const statRenderBlock = (stat: MainStat) => {
|
||||
return Object.entries(config.training[stat]).map(
|
||||
(level) => [ div("w-full flex h-px", [div("border-t border-dashed border-light-50 dark:border-dark-50 w-full"), dom('span', { class: "relative" }, [ text(level[0]) ])]),
|
||||
div("flex flex-row gap-4 justify-center", level[1].map((option, j) => dom("div", { class: ["border border-light-40 dark:border-dark-40 cursor-pointer px-2 py-1 w-[400px] hover:border-light-50 dark:hover:border-dark-50"], listeners: { click: e => {
|
||||
this._builder.edit(config.features[option]!);
|
||||
}}}, [ markdownUtil(config.features[option]!.description, undefined, { tags: { a: fakeA } }) ])))
|
||||
div("flex flex-row gap-4 justify-center", level[1].map((option, j) => {
|
||||
let element = dom("div", { class: ["border border-light-40 dark:border-dark-40 cursor-pointer px-2 py-1 w-[400px] hover:border-light-50 dark:hover:border-dark-50"], listeners: { click: e => {
|
||||
this._builder.edit(config.features[option]!).then(e => {
|
||||
element.replaceChildren(markdownUtil(config.features[option]!.description, undefined, { tags: { a: fakeA } }));
|
||||
});
|
||||
}}}, [ markdownUtil(config.features[option]!.description, undefined, { tags: { a: fakeA } }) ]);
|
||||
return element;
|
||||
})),
|
||||
])
|
||||
}
|
||||
|
||||
|
|
@ -357,48 +363,50 @@ export class FeatureEditor
|
|||
switch(effect.category)
|
||||
{
|
||||
case 'value':
|
||||
return flattenFeatureChoices.find(e => e.category === 'value' && e.property === effect.property);
|
||||
return flattenFeatureChoices.findLast(e => e.category === 'value' && e.property === effect.property);
|
||||
case 'choice':
|
||||
return flattenFeatureChoices.find(e => e.category === 'choice');
|
||||
return flattenFeatureChoices.findLast(e => e.category === 'choice');
|
||||
case 'list':
|
||||
return flattenFeatureChoices.find(e => e.category === 'list' && e.list === effect.list);
|
||||
return flattenFeatureChoices.findLast(e => e.category === 'list' && e.list === effect.list);
|
||||
}
|
||||
};
|
||||
const approve = () => {
|
||||
const idx = this._feature!.effect.findIndex(e => e.id === buffer.id);
|
||||
const idx = this._feature!.effect.findIndex(e => e.id === _buffer.id);
|
||||
|
||||
if(idx === -1)
|
||||
this._feature!.effect.push(buffer);
|
||||
this._feature!.effect.push(_buffer);
|
||||
else
|
||||
this._feature!.effect[idx] = buffer;
|
||||
this._feature!.effect[idx] = _buffer;
|
||||
|
||||
this._table.replaceChild(this._renderEffect(buffer), content);
|
||||
this._table.replaceChild(this._renderEffect(_buffer), content);
|
||||
}, reject = () => {
|
||||
const idx = this._feature!.effect.findIndex(e => e.id === buffer.id);
|
||||
const idx = this._feature!.effect.findIndex(e => e.id === _buffer.id);
|
||||
|
||||
if(idx === -1)
|
||||
content.remove();
|
||||
else
|
||||
this._table.replaceChild(this._renderEffect(effect), content);
|
||||
}
|
||||
let buffer = JSON.parse(JSON.stringify(effect)) as FeatureItem;
|
||||
let _buffer = JSON.parse(JSON.stringify(effect)) as FeatureItem;
|
||||
|
||||
const drawByCategory = (buffer: Partial<FeatureItem>) => {
|
||||
let top: NodeChildren = [], bottom: NodeChildren = [];
|
||||
switch(buffer.category)
|
||||
{
|
||||
case 'value':
|
||||
const valueVariable = () => typeof buffer.value === 'number' ? numberpicker({ defaultValue: buffer.value, input: (value) => { (buffer as Extract<FeatureEffect, { category: "value" }>).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<FeatureEffect, { category: "value" }>).value = value; summaryText.textContent = textFromEffect(buffer); } });
|
||||
const summaryText = text(textFromEffect(buffer));
|
||||
let valueSelection = valueVariable();
|
||||
top = [
|
||||
select([ { text: '+', value: 'add' }, (['speed', 'capacity'].includes(buffer.property ?? '') || ['defense/'].some(e => (buffer as Extract<FeatureEffect, { category: "value" }>).property.startsWith(e))) ? { text: '=', value: 'set' } : undefined ], { defaultValue: buffer.operation, change: (value) => { (buffer as Extract<FeatureEffect, { category: "value" }>).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]' } }),
|
||||
typeof buffer.value === 'number' ? numberpicker({ defaultValue: buffer.value, input: (value) => { (buffer as Extract<FeatureEffect, { category: "value" }>).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<FeatureEffect, { category: "value" }>).value = value; summaryText.textContent = textFromEffect(buffer); } }),
|
||||
button(icon('radix-icons:update'), () => {
|
||||
valueSelection,
|
||||
tooltip(button(icon('radix-icons:update'), () => {
|
||||
(buffer as Extract<FeatureEffect, { category: "value" }>).value = (typeof (buffer as Extract<FeatureEffect, { category: "value" }>).value === 'number' ? '' as any as false : 0);
|
||||
const element = redraw();
|
||||
this._table.replaceChild(element, content);
|
||||
content = element;
|
||||
const newValueSelection = valueVariable();
|
||||
valueSelection?.parentElement?.replaceChild(newValueSelection, valueSelection);
|
||||
valueSelection = newValueSelection;
|
||||
summaryText.textContent = textFromEffect(buffer);
|
||||
}, 'px-2 -m-px hover:z-10 border border-light-35 dark:border-dark-35 hover:border-light-50 dark:hover:border-dark-50'),
|
||||
}, 'px-2 -m-px hover:z-10 border border-light-35 dark:border-dark-35 hover:border-light-50 dark:hover:border-dark-50'), 'Changer d\'editeur', 'bottom'),
|
||||
];
|
||||
bottom = [ div('px-2 py-1 flex items-center flex-1', [summaryText]) ];
|
||||
break;
|
||||
|
|
@ -424,23 +432,23 @@ export class FeatureEditor
|
|||
const add = () => {
|
||||
const option: Extract<FeatureItem, { category: 'choice' }>["options"][number] = { id: getID(ID_SIZE), category: 'value', text: '', operation: 'add', property: '', value: 0 };
|
||||
(buffer as Extract<FeatureItem, { category: 'choice' }>).options.push(option);
|
||||
list.appendChild(render(option));
|
||||
list.appendChild(render(option, true));
|
||||
};
|
||||
const remove = (option: FeatureEffect) => {
|
||||
|
||||
};
|
||||
const render = (option: FeatureEffect): HTMLElement => {
|
||||
const render = (option: FeatureEffect & { text: string }, state: boolean): HTMLElement => {
|
||||
const { top: _top, bottom: _bottom } = drawByCategory(option);
|
||||
const combo = combobox(featureChoices.filter(e => (e?.value as FeatureItem)?.category !== 'choice'), { defaultValue: match(option), class: { container: 'bg-light-25 dark:bg-dark-25 w-[300px] -m-px hover:z-10 h-[36px]' }, change: (e) => {
|
||||
option = { id: option.id, ...e } as FeatureEffect;
|
||||
const element = render(option);
|
||||
const combo = combobox([...featureChoices].filter(e => (e?.value as FeatureItem)?.category !== 'choice').map(e => { if(e) e.value = Array.isArray(e.value) ? e.value.filter(f => (f?.value as FeatureItem)?.category !== 'choice') : e.value; return e; }), { defaultValue: match(option), class: { container: 'bg-light-25 dark:bg-dark-25 w-[300px] -m-px hover:z-10 h-[36px]' }, change: (e) => {
|
||||
option = { id: option.id, ...e } as FeatureEffect & { text: string };
|
||||
const element = render(option, true);
|
||||
_content?.parentElement?.replaceChild(element, _content);
|
||||
_content = element;
|
||||
} });
|
||||
let _content: HTMLElement = foldable(_bottom, [ div('flex flex-1 justify-between', [ div('flex flex-row',[ combo, ..._top ]), tooltip(button(icon('radix-icons:trash'), () => remove(option), 'px-2 -m-px hover:z-10 border border-light-35 dark:border-dark-35 hover:border-light-50 dark:hover:border-dark-50'), 'Supprimer', 'bottom') ]) ], { class: { title: 'border-b border-light-35 dark:border-dark-35', icon: 'w-[34px] h-[34px]', content: 'border-b border-light-35 dark:border-dark-35' } });
|
||||
let _content: HTMLElement = foldable(_bottom, [ div('flex flex-1 justify-between', [ div('flex flex-1 flex-row',[ combo, ..._top, input('text', { defaultValue: option.text, input: (value) => option.text = value, class: 'bg-light-25 dark:bg-dark-25 !-m-px hover:z-10 h-[36px] flex-shrink-1', placeholder: 'Description' }) ]), tooltip(button(icon('radix-icons:trash'), () => {
|
||||
_content.remove();
|
||||
(buffer as Extract<FeatureItem, { category: 'choice' }>).options = (buffer as Extract<FeatureItem, { category: 'choice' }>).options.filter(e => e.id !== option.id);
|
||||
}, 'px-2 -m-px hover:z-10 border border-light-35 dark:border-dark-35 hover:border-light-50 dark:hover:border-dark-50'), 'Supprimer', 'bottom') ]) ], { class: { title: 'border-b border-light-35 dark:border-dark-35', icon: 'w-[34px] h-[34px]', content: 'border-b border-light-35 dark:border-dark-35' }, open: state });
|
||||
return _content;
|
||||
}
|
||||
const list = div('flex flex-col flex-1 divide-y divide-light-35 dark:divide-dark-35 gap-2', buffer.options?.map(e => render(e)) ?? []);
|
||||
const list = div('flex flex-col flex-1 divide-y divide-light-35 dark:divide-dark-35 gap-2', buffer.options?.map(e => render(e, false)) ?? []);
|
||||
top = [ input('text', { defaultValue: buffer.text, input: (value) => (buffer as Extract<FeatureItem, { category: 'choice' }>).text = value, class: 'bg-light-25 dark:bg-dark-25 !-m-px hover:z-10 h-[36px] w-full', placeholder: 'Description' }), tooltip(button(icon('radix-icons:plus'), () => add(), 'px-2 -m-px hover:z-10 border border-light-35 dark:border-dark-35 hover:border-light-50 dark:hover:border-dark-50'), 'Ajouter une option', 'bottom') ];
|
||||
bottom = [ list ];
|
||||
break;
|
||||
|
|
@ -449,13 +457,13 @@ export class FeatureEditor
|
|||
return { top, bottom };
|
||||
}
|
||||
const redraw = () => {
|
||||
const { top, bottom } = drawByCategory(buffer);
|
||||
const { top, bottom } = drawByCategory(_buffer);
|
||||
return div('border border-light-30 dark:border-dark-30 col-span-2 row-span-2', [ div('flex justify-between items-stretch', [
|
||||
div('flex flex-row flex-1', [
|
||||
combobox(featureChoices, { defaultValue: match(buffer), class: { container: 'bg-light-25 dark:bg-dark-25 w-[300px] -m-px hover:z-10 h-[36px]' }, change: (e) => {
|
||||
buffer = { id: buffer.id, ...e } as FeatureItem;
|
||||
combobox(featureChoices, { defaultValue: match(_buffer), class: { container: 'bg-light-25 dark:bg-dark-25 w-[300px] -m-px hover:z-10 h-[36px]' }, change: (e) => {
|
||||
_buffer = { id: _buffer.id, ...e } as FeatureItem;
|
||||
const element = redraw();
|
||||
this._table.replaceChild(element, content);
|
||||
content?.parentElement?.replaceChild(element, content);
|
||||
content = element;
|
||||
} }),
|
||||
...top,
|
||||
|
|
@ -511,7 +519,36 @@ const featureChoices: Option<Partial<FeatureItem>>[] = [
|
|||
{ text: 'Modifier d\'intelligence', value: { category: 'value', property: 'modifier/intelligence', operation: 'add', value: 0 } },
|
||||
{ text: 'Modifier de curiosité', value: { category: 'value', property: 'modifier/curiosity', operation: 'add', value: 0 } },
|
||||
{ text: 'Modifier de charisme', value: { category: 'value', property: 'modifier/charisma', operation: 'add', value: 0 } },
|
||||
{ text: 'Modifier de psyché', value: { category: 'value', property: 'modifier/psyche', operation: 'add', value: 0 } }
|
||||
{ text: 'Modifier de psyché', value: { category: 'value', property: 'modifier/psyche', operation: 'add', value: 0 } },
|
||||
//@ts-ignore
|
||||
{ text: 'Modifier au choix', value: { category: 'choice', text: '+1 au modifier de ', options: [
|
||||
{ text: 'Modifier de force', category: 'value', property: 'modifier/strength', operation: 'add', value: 1 },
|
||||
{ text: 'Modifier de dextérité', category: 'value', property: 'modifier/dexterity', operation: 'add', value: 1 },
|
||||
{ text: 'Modifier de constitution', category: 'value', property: 'modifier/constitution', operation: 'add', value: 1 },
|
||||
{ text: 'Modifier d\'intelligence', category: 'value', property: 'modifier/intelligence', operation: 'add', value: 1 },
|
||||
{ text: 'Modifier de curiosité', category: 'value', property: 'modifier/curiosity', operation: 'add', value: 1 },
|
||||
{ text: 'Modifier de charisme', category: 'value', property: 'modifier/charisma', operation: 'add', value: 1 },
|
||||
{ text: 'Modifier de psyché', egory: 'value', property: 'modifier/psyche', operation: 'add', value: 1 }
|
||||
]}}
|
||||
] },
|
||||
{ text: 'Jet de résistance', value: [
|
||||
{ text: 'Force', value: { category: 'value', property: 'bonus/defense/strength', operation: 'add', value: 0 } },
|
||||
{ text: 'Dextérité', value: { category: 'value', property: 'bonus/defense/dexterity', operation: 'add', value: 0 } },
|
||||
{ text: 'Constitution', value: { category: 'value', property: 'bonus/defense/constitution', operation: 'add', value: 0 } },
|
||||
{ text: 'Intelligence', value: { category: 'value', property: 'bonus/defense/intelligence', operation: 'add', value: 0 } },
|
||||
{ text: 'Curiosité', value: { category: 'value', property: 'bonus/defense/curiosity', operation: 'add', value: 0 } },
|
||||
{ text: 'Charisme', value: { category: 'value', property: 'bonus/defense/charisma', operation: 'add', value: 0 } },
|
||||
{ text: 'Psyché', value: { category: 'value', property: 'bonus/defense/psyche', operation: 'add', value: 0 } },
|
||||
//@ts-ignore
|
||||
{ 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 }
|
||||
]}}
|
||||
] },
|
||||
{ text: 'Action', value: { category: 'list', list: 'action', action: 'add' }, },
|
||||
{ text: 'Réaction', value: { category: 'list', list: 'reaction', action: 'add' }, },
|
||||
|
|
@ -623,7 +660,7 @@ function textFromEffect(effect: Partial<FeatureItem>): string
|
|||
}
|
||||
else if(effect.category === 'choice')
|
||||
{
|
||||
return `${effect.text} (${effect.options?.length ?? 0} options)`;
|
||||
return `${effect.text} (${effect.options?.length ?? 0} options).`;
|
||||
}
|
||||
|
||||
return `Inconnu`;
|
||||
|
|
|
|||
Loading…
Reference in New Issue