Fixes and responsive character sheet.

This commit is contained in:
2026-06-16 11:14:46 +02:00
parent bc1839c5e3
commit a5317d6156
5 changed files with 293 additions and 138 deletions

View File

@@ -743,29 +743,54 @@ export function checkbox(settings?: { defaultValue?: boolean, change?: (this: HT
}, [ icon('radix-icons:check', { width: 14, height: 14, class: ['hidden group-data-[state="checked"]:block data-[disabled]:text-light-50 dark:data-[disabled]:text-dark-50', settings?.class?.icon] }), ]);
return element;
}
export function tabgroup(tabs: Array<{ id: string, title: NodeChildren, content: Reactive<NodeChildren> }>, settings?: { focused?: string, class?: { container?: Class, tabbar?: Class, title?: Class, content?: Class }, switch?: (tab: string) => void | boolean }): HTMLElement
export function tabgroup(tabs: Array<Reactive<{ id: string, title: NodeChildren, content: Reactive<NodeChildren> } | undefined>>, settings?: { focused?: string, class?: { container?: Class, tabbar?: Class, title?: Class, content?: Class }, switch?: (tab: string) => void | boolean }): HTMLElement
{
let focus = settings?.focused ?? tabs[0]?.id;
const titles = tabs.map(e => dom('div', { class: ['px-2 py-1 border-b border-transparent hover:border-accent-blue data-[focus]:border-accent-blue data-[focus]:border-b-[3px] cursor-pointer', settings?.class?.title], attributes: { 'data-focus': e.id === focus }, listeners: { click: function() {
if(this.hasAttribute('data-focus'))
return;
let focus = settings?.focused ?? '';
if(settings?.switch && settings.switch(e.id) === false)
return;
const resolveTab = (t: typeof tabs[number]) => typeof t === 'function' ? t() : t;
titles.forEach(e => e.toggleAttribute('data-focus', false));
this.toggleAttribute('data-focus', true);
focus = e.id;
const lazyContent = typeof e.content === 'function' ? e.content() : e.content;
lazyContent && content.replaceChildren(...lazyContent?.map(e => typeof e === 'function' ? e() : e)?.filter(e => !!e));
}}}, e.title));
const _content = tabs.find(e => e.id === focus)?.content;
const content = div(['', settings?.class?.content], typeof _content === 'function' ? _content() : _content);
const tabbar = div(['flex flex-row items-center gap-1', settings?.class?.tabbar]);
const content = div(['', settings?.class?.content]);
const container = div(['flex flex-col', settings?.class?.container], [tabbar, content]);
const render = () => {
const resolved = tabs.map(resolveTab).filter((t): t is NonNullable<typeof t> => !!t);
if (!resolved.find(t => t.id === focus))
focus = resolved[0]?.id ?? '';
const titles = resolved.map(t => dom('div', {
class: ['px-2 py-1 border-b border-transparent hover:border-accent-blue data-[focus]:border-accent-blue data-[focus]:border-b-[3px] cursor-pointer', settings?.class?.title],
attributes: focus === t.id ? { 'data-focus': '' } : {},
listeners: { click: function() {
if (this.hasAttribute('data-focus'))
return;
if (settings?.switch && settings.switch(t.id) === false)
return;
tabbar.querySelectorAll('[data-focus]').forEach(e => e.removeAttribute('data-focus'));
this.setAttribute('data-focus', '');
focus = t.id;
const lazyContent = typeof t.content === 'function' ? t.content() : t.content;
lazyContent && content.replaceChildren(...lazyContent.map(e => typeof e === 'function' ? e() : e).filter(e => !!e));
} }
}, t.title));
tabbar.replaceChildren(...titles);
const active = resolved.find(t => t.id === focus);
if (active) {
const lazyContent = typeof active.content === 'function' ? active.content() : active.content;
lazyContent && content.replaceChildren(...lazyContent.map(e => typeof e === 'function' ? e() : e).filter(e => !!e));
}
};
reactivity(() => {
const resolved = tabs.map(resolveTab);
return resolved.map(t => t?.id).join(',');
}, render);
const container = div(['flex flex-col', settings?.class?.container], [
div(['flex flex-row items-center gap-1', settings?.class?.tabbar], titles),
content
]);
return container as HTMLElement;
}
export function floater(container: HTMLElement, content: NodeChildren | (() => NodeChildren), settings?: { delay?: number, href?: RouteLocationRaw, class?: Class, style?: Record<string, string | undefined | boolean | number> | string, position?: Placement, pinned?: boolean | { width: number, height: number }, minimizable?: boolean, cover?: 'width' | 'height' | 'all' | 'none', events?: { show: Array<keyof HTMLElementEventMap>, hide: Array<keyof HTMLElementEventMap>, onshow?: (state: FloatState) => boolean, onhide?: (state: FloatState) => boolean }, title?: string })