Implement Aspect tab and HP/Mana editor

This commit is contained in:
2026-01-28 21:38:10 +01:00
parent a412116b9c
commit 3081c05b55
13 changed files with 165 additions and 38 deletions

View File

@@ -1,10 +1,10 @@
import type { RouteLocationAsRelativeTyped, RouteLocationRaw, RouteMapGeneric } from "vue-router";
import { type NodeProperties, type Class, type NodeChildren, dom, mergeClasses, text, div, icon, type Node, type HTMLElement } from "#shared/dom";
import { type NodeProperties, type Class, type NodeChildren, dom, mergeClasses, text, div, icon, type Node } from "#shared/dom";
import { contextmenu, followermenu, minimizeBox, popper, teleport, tooltip, type FloatState } from "#shared/floating";
import { clamp } from "#shared/general";
import { Tree } from "#shared/tree";
import type { Placement } from "@floating-ui/dom";
import { type Reactive } from '#shared/reactive';
import { reactivity, type Reactive } from '#shared/reactive';
export function link(children: NodeChildren, properties?: NodeProperties & { active?: Class }, link?: RouteLocationAsRelativeTyped<RouteMapGeneric, string>)
{
@@ -394,9 +394,9 @@ export function input(type: 'text' | 'number' | 'email' | 'password' | 'tel', se
return input;
}
export function numberpicker(settings?: { defaultValue?: number, change?: (value: number) => void, input?: (value: number) => void, focus?: (value: number) => void, blur?: (value: number) => void, class?: Class, min?: number, max?: number, disabled?: boolean }): HTMLInputElement
export function numberpicker(settings?: { defaultValue?: Reactive<number>, change?: (value: number) => void, input?: (value: number) => void, focus?: (value: number) => void, blur?: (value: number) => void, class?: Class, min?: number, max?: number, disabled?: Reactive<boolean> }): HTMLInputElement
{
let storedValue = settings?.defaultValue ?? 0;
let storedValue = settings?.defaultValue ? typeof settings.defaultValue === 'function' ? settings.defaultValue() : settings.defaultValue : 0;
const validateAndChange = (value: number) => {
if(isNaN(value))
field.value = '';
@@ -412,7 +412,7 @@ export function numberpicker(settings?: { defaultValue?: number, change?: (value
}
return false;
}
const field = dom("input", { attributes: { disabled: settings?.disabled }, class: [`w-14 mx-4 caret-light-50 dark:caret-dark-50 text-light-100 dark:text-dark-100 placeholder:text-light-50 dark:placeholder:text-dark-50 bg-light-20 dark:bg-dark-20 appearance-none outline-none px-3 py-1 focus:shadow-raw transition-[box-shadow] focus:shadow-light-40 dark:focus:shadow-dark-40 border border-light-35 dark:border-dark-35 hover:border-light-50 dark:hover:border-dark-50 disabled:shadow-none disabled:bg-light-20 dark:disabled:bg-dark-20 disabled:border-dashed disabled:border-light-30 dark:disabled:border-dark-30`, settings?.class], listeners: {
const field = dom("input", { attributes: { disabled: settings?.disabled }, class: [`w-14 mx-4 caret-light-50 dark:caret-dark-50 text-light-100 dark:text-dark-100 placeholder:text-light-50 dark:placeholder:text-dark-50 bg-light-20 dark:bg-dark-20 outline-none px-3 py-1 focus:shadow-raw transition-[box-shadow] focus:shadow-light-40 dark:focus:shadow-dark-40 border border-light-35 dark:border-dark-35 hover:border-light-50 dark:hover:border-dark-50 disabled:shadow-none disabled:bg-light-20 dark:disabled:bg-dark-20 disabled:border-dashed disabled:border-light-35 dark:disabled:border-dark-35 disabled:border-2`, settings?.class], listeners: {
input: () => validateAndChange(parseInt(field.value.trim().toLowerCase().normalize().replace(/[a-z,.]/g, ""), 10)) && settings?.input && settings.input(storedValue),
keydown: (e: KeyboardEvent) => {
if(field.disabled)
@@ -443,12 +443,18 @@ export function numberpicker(settings?: { defaultValue?: number, change?: (value
focus: () => settings?.focus && settings.focus(storedValue),
blur: () => settings?.blur && settings.blur(storedValue),
}});
if(settings?.defaultValue !== undefined) field.value = storedValue.toString(10);
if(settings?.defaultValue !== undefined)
{
reactivity(settings.defaultValue, (v) => {
field.value = v.toString(10);
storedValue = v;
})
}
return field;
}
// Open by default
export function foldable(content: Reactive<NodeChildren>, title: NodeChildren, settings?: { open?: boolean, class?: { container?: Class, title?: Class, content?: Class, icon?: Class } })
export function foldable(content: Reactive<NodeChildren>, title: NodeChildren, settings?: { open?: boolean, onFold?: (state: boolean) => void, class?: { container?: Class, title?: Class, content?: Class, icon?: Class } })
{
let lazyContent: NodeChildren;
const display = (state: boolean) => {
@@ -460,6 +466,7 @@ export function foldable(content: Reactive<NodeChildren>, title: NodeChildren, s
lazyContent && contentContainer.replaceChildren(...lazyContent.map(e => typeof e ==='function' ? e() : e).filter(e => !!e));
}
}
settings?.onFold && settings.onFold(state);
}
const contentContainer = div(['hidden group-data-[active]:flex', settings?.class?.content]);
const fold = div(['group flex w-full flex-col', settings?.class?.container], [