Several small fixes with rendering and floating components

This commit is contained in:
Clément Pons 2026-01-06 17:40:01 +01:00
parent 7021264c11
commit 0eaffcaa04
8 changed files with 66 additions and 50 deletions

BIN
db.sqlite

Binary file not shown.

View File

@ -1,17 +1,19 @@
import type { Ability, Alignment, ArmorConfig, ArmorState, Character, CharacterConfig, CharacterVariables, CompiledCharacter, DamageType, EnchantementConfig, FeatureItem, ItemConfig, ItemState, Level, MainStat, MundaneState, Resistance, SpellConfig, SpellElement, SpellType, TrainingLevel, WeaponConfig, WeaponState, WeaponType, WondrousState } from "~/types/character"; import type { Ability, Alignment, ArmorConfig, ArmorState, Character, CharacterConfig, CharacterVariables, CompiledCharacter, DamageType, EnchantementConfig, FeatureItem, ItemConfig, ItemState, Level, MainStat, MundaneState, Resistance, SpellConfig, SpellElement, SpellType, TrainingLevel, WeaponConfig, WeaponState, WeaponType, WondrousState } from "~/types/character";
import { z } from "zod/v4"; import { z } from "zod/v4";
import characterConfig from '#shared/character-config.json'; import characterConfig from '#shared/character-config.json';
import proses, { preview } from "#shared/proses"; import proses, { a, preview } from "#shared/proses";
import { button, buttongroup, checkbox, floater, foldable, input, loading, multiselect, numberpicker, select, tabgroup, Toaster, toggle } from "#shared/components.util"; import { async, button, buttongroup, checkbox, floater, foldable, input, loading, multiselect, numberpicker, select, tabgroup, Toaster, toggle } from "#shared/components.util";
import { div, dom, icon, span, text, type RedrawableHTML } from "#shared/dom.util"; import { div, dom, icon, span, text, type RedrawableHTML } from "#shared/dom.util";
import { followermenu, fullblocker, tooltip } from "#shared/floating.util"; import { followermenu, fullblocker, tooltip } from "#shared/floating.util";
import { clamp } from "#shared/general.util"; import { clamp } from "#shared/general.util";
import markdown from "#shared/markdown.util"; import markdown, { defaultProses, filterMarkdown, renderMarkdown } from "#shared/markdown.util";
import { getText } from "#shared/i18n"; import { getText } from "#shared/i18n";
import type { User } from "~/types/auth"; import type { User } from "~/types/auth";
import { MarkdownEditor } from "#shared/editor.util"; import { MarkdownEditor } from "#shared/editor.util";
import { Socket } from "#shared/websocket.util"; import { Socket } from "#shared/websocket.util";
import { raw, reactive } from '#shared/reactive'; import { raw, reactive } from '#shared/reactive';
import { Content, type ContentMap, type LocalContent } from "./content.util";
import type { Root } from "hast";
const config = characterConfig as CharacterConfig; const config = characterConfig as CharacterConfig;
@ -558,6 +560,7 @@ export class CharacterBuilder extends CharacterCompiler
private _content?: RedrawableHTML; private _content?: RedrawableHTML;
private _stepsHeader: RedrawableHTML[] = []; private _stepsHeader: RedrawableHTML[] = [];
private _steps: Array<BuilderTabConstructor> = []; private _steps: Array<BuilderTabConstructor> = [];
private _stepContent: Array<BuilderTab> = [];
private _currentStep: number = 0; private _currentStep: number = 0;
private _helperText!: Text; private _helperText!: Text;
private id?: string; private id?: string;
@ -613,9 +616,9 @@ export class CharacterBuilder extends CharacterCompiler
AspectPicker, AspectPicker,
]; ];
this._stepsHeader = this._steps.map((e, i) => this._stepsHeader = this._steps.map((e, i) =>
dom("div", { class: "group flex items-center", }, [ dom("div", { class: "group/header flex items-center", }, [
i !== 0 ? icon("radix-icons:chevron-right", { class: "w-6 h-6 flex justify-center items-center group-data-[disabled]:text-light-50 dark:group-data-[disabled]:text-dark-50 group-data-[disabled]:hover:border-transparent me-4" }) : undefined, i !== 0 ? icon("radix-icons:chevron-right", { class: "w-6 h-6 flex justify-center items-center group-data-[disabled]/header:text-light-50 dark:group-data-[disabled]/header:text-dark-50 group-data-[disabled]/header:hover:border-transparent me-4" }) : undefined,
dom("div", { class: "px-2 py-1 border-b border-transparent hover:border-accent-blue disabled:text-light-50 dark:disabled:text-dark-50 disabled:hover:border-transparent group-data-[state=active]:text-accent-blue cursor-pointer", listeners: { click: () => this.display(i) } }, [text(e.header)]), dom("div", { class: "px-2 py-1 border-b border-transparent hover:border-accent-blue disabled:text-light-50 dark:disabled:text-dark-50 disabled:hover:border-transparent group-data-[state=active]/header:text-accent-blue cursor-pointer", listeners: { click: () => this.display(i) } }, [text(e.header)]),
]) ])
); );
this._helperText = text("Choisissez un peuple afin de définir la progression de votre personnage au fil des niveaux.") this._helperText = text("Choisissez un peuple afin de définir la progression de votre personnage au fil des niveaux.")
@ -656,7 +659,8 @@ export class CharacterBuilder extends CharacterCompiler
this._currentStep = step; this._currentStep = step;
this._content?.replaceChildren(...(new this._steps[step]!(this)).dom); this._stepContent[step] ??= (new this._steps[step]!(this));
this._content?.replaceChildren(...this._stepContent[step].dom);
this._helperText.textContent = this._steps[step]!.description; this._helperText.textContent = this._steps[step]!.description;
} }
@ -1334,7 +1338,7 @@ export class CharacterSheet
private character?: CharacterCompiler; private character?: CharacterCompiler;
container: RedrawableHTML = div('flex flex-1 h-full w-full items-start justify-center'); container: RedrawableHTML = div('flex flex-1 h-full w-full items-start justify-center');
private tabs?: RedrawableHTML; private tabs?: RedrawableHTML;
private tab: string = 'abilities'; private tab: string = 'actions';
ws?: Socket; ws?: Socket;
constructor(id: string, user: ComputedRef<User | null>) constructor(id: string, user: ComputedRef<User | null>)
@ -1591,7 +1595,7 @@ export class CharacterSheet
]), ]),
() => character.mastery.strength + character.mastery.dexterity > 0 ? div("grid grid-cols-2 gap-x-3 gap-y-1 text-sm", [ () => character.mastery.strength + character.mastery.dexterity > 0 ? div("grid grid-cols-2 gap-x-3 gap-y-1 text-sm", [
() => character.mastery.strength + character.mastery.dexterity > 0 ? proses('a', preview, [ text('Arme légère') ], { href: 'regles/annexes/equipement#Les armes légères', label: 'Arme légère' }) : undefined, () => character.mastery.strength + character.mastery.dexterity > 0 ? proses('a', preview, [ text('Arme légère') ], { href: 'regles/annexes/equipement#Les armes légères', label: 'Arme légère', }) : undefined,
() => character.mastery.strength + character.mastery.dexterity > 0 ? proses('a', preview, [ text('Arme de jet') ], { href: 'regles/annexes/equipement#Les armes de jet', label: 'Arme de jet' }) : undefined, () => character.mastery.strength + character.mastery.dexterity > 0 ? proses('a', preview, [ text('Arme de jet') ], { href: 'regles/annexes/equipement#Les armes de jet', label: 'Arme de jet' }) : undefined,
() => character.mastery.strength + character.mastery.dexterity > 0 ? proses('a', preview, [ text('Arme naturelle') ], { href: 'regles/annexes/equipement#Les armes naturelles', label: 'Arme naturelle' }) : undefined, () => character.mastery.strength + character.mastery.dexterity > 0 ? proses('a', preview, [ text('Arme naturelle') ], { href: 'regles/annexes/equipement#Les armes naturelles', label: 'Arme naturelle' }) : undefined,
() => character.mastery.strength > 1 ? proses('a', preview, [ text('Arme standard') ], { href: 'regles/annexes/equipement#Les armes', label: 'Arme standard' }) : undefined, () => character.mastery.strength > 1 ? proses('a', preview, [ text('Arme standard') ], { href: 'regles/annexes/equipement#Les armes', label: 'Arme standard' }) : undefined,
@ -1634,11 +1638,11 @@ export class CharacterSheet
div("flex flex-row items-center justify-center gap-4", [ div("flex flex-row items-center justify-center gap-4", [
div("flex flex-row items-center justify-center gap-2", [ dom("div", { class: 'text-lg font-semibold', text: "Actions" }), proses('a', preview, [ icon('radix-icons:question-mark-circled', { width: 16, height: 16, class: 'text-light-70 dark:text-dark-70' }) ], { href: 'regles/le-combat/actions-en-combat#Actions', class: 'h-4' }) ]), div("flex flex-row items-center justify-center gap-2", [ dom("div", { class: 'text-lg font-semibold', text: "Actions" }), proses('a', preview, [ icon('radix-icons:question-mark-circled', { width: 16, height: 16, class: 'text-light-70 dark:text-dark-70' }) ], { href: 'regles/le-combat/actions-en-combat#Actions', class: 'h-4' }) ]),
div("flex flex-1 border-t border-dashed border-light-50 dark:border-dark-50"), div("flex flex-1 border-t border-dashed border-light-50 dark:border-dark-50"),
div('flex flex-row items-center gap-2', [ ...Array(3).fill(undefined).map(e => div('border border-dashed border-light-50 dark:border-dark-50 w-5 h-5')), dom('span', { class: 'tracking-tight', text: '/ round' }) ]), div('flex flex-row items-center gap-2', [ ...Array(3).fill(undefined).map(e => div('border border-dashed border-light-50 dark:border-dark-50 w-5 h-5')), dom('span', { class: 'tracking-tight', text: '/ tour' }) ]),
]), ]),
div('flex flex-col gap-2', [ div('flex flex-col gap-2', [
div('flex flex-row flex-wrap gap-2 text-light-60 dark:text-dark-60', ["Attaquer", "Désarmer", "Saisir", "Faire chuter", "Déplacer", "Courir", "Pas de coté", "Charger", "Lancer un sort", "S'interposer", "Se transformer", "Utiliser un objet", "Anticiper une action", "Improviser"].map(e => dom('span', { text: e, class: 'cursor-pointer text-sm decoration-dotted underline' }))), div('flex flex-row flex-wrap gap-2', ["Attaquer", "Désarmer", "Saisir", "Faire chuter", "Déplacer", "Courir", "Pas de coté", "Charger", "Lancer un sort", "S'interposer", "Se transformer", "Utiliser un objet", "Anticiper une action", "Improviser"].map(e => proses('a', a, [ span('cursor-pointer text-sm decoration-dotted underline', e) ], { href: 'regles/le-combat/actions-en-combat#' + e, label: e, trigger: 'hover', navigate: false, class: 'text-light-60 dark:text-dark-60' }))),
div('flex flex-col gap-2', { render: (e) => div('flex flex-col gap-1', [ div('flex flex-col gap-2', { render: (e) => div('flex flex-col gap-1', [
div('flex flex-row justify-between', [dom('span', { class: 'text-lg', text: config.action[e]?.name }), config.action[e]?.cost ? div('flex flex-row gap-1', [dom('span', { class: 'font-bold', text: config.action[e]?.cost?.toString() }), text(`point${config.action[e]?.cost > 1 ? 's' : ''} d'action`)]) : undefined]), div('flex flex-row justify-between', [dom('span', { class: 'text-lg', text: config.action[e]?.name }), config.action[e]?.cost ? div('flex flex-row gap-1', [dom('span', { class: 'font-bold', text: config.action[e]?.cost?.toString() }), text(`point${config.action[e]?.cost > 1 ? 's' : ''} d'action`)]) : undefined]),
markdown(getText(config.action[e]?.description), undefined, { tags: { a: preview } }), markdown(getText(config.action[e]?.description), undefined, { tags: { a: preview } }),
@ -1649,7 +1653,7 @@ export class CharacterSheet
div("flex flex-row items-center justify-center gap-4", [ div("flex flex-row items-center justify-center gap-4", [
div("flex flex-row items-center justify-center gap-2", [ dom("div", { class: 'text-lg font-semibold', text: "Réactions" }), proses('a', preview, [ icon('radix-icons:question-mark-circled', { width: 16, height: 16, class: 'text-light-70 dark:text-dark-70' }) ], { href: 'regles/le-combat/actions-en-combat#Réaction', class: 'h-4' }) ]), div("flex flex-row items-center justify-center gap-2", [ dom("div", { class: 'text-lg font-semibold', text: "Réactions" }), proses('a', preview, [ icon('radix-icons:question-mark-circled', { width: 16, height: 16, class: 'text-light-70 dark:text-dark-70' }) ], { href: 'regles/le-combat/actions-en-combat#Réaction', class: 'h-4' }) ]),
div("flex flex-1 border-t border-dashed border-light-50 dark:border-dark-50"), div("flex flex-1 border-t border-dashed border-light-50 dark:border-dark-50"),
div('flex flex-row items-center gap-2', [ ...Array(2).fill(undefined).map(e => div('border border-dashed border-light-50 dark:border-dark-50 w-5 h-5')), dom('span', { class: 'tracking-tight', text: '/ round' }) ]), div('flex flex-row items-center gap-2', [ ...Array(2).fill(undefined).map(e => div('border border-dashed border-light-50 dark:border-dark-50 w-5 h-5')), dom('span', { class: 'tracking-tight', text: '/ tour' }) ]),
]), ]),
div('flex flex-col gap-2', [ div('flex flex-col gap-2', [

View File

@ -537,7 +537,7 @@ export function tabgroup(tabs: Array<{ id: string, title: NodeChildren, content:
]); ]);
return container as RedrawableHTML; return container as RedrawableHTML;
} }
export function floater(container: RedrawableHTML, content: NodeChildren | (() => NodeChildren), settings?: { href?: RouteLocationRaw, class?: Class, style?: Record<string, string | undefined | boolean | number> | string, position?: Placement, pinned?: boolean, 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 }) export function floater(container: RedrawableHTML, 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 })
{ {
let viewport = document.getElementById('mainContainer') ?? undefined; let viewport = document.getElementById('mainContainer') ?? undefined;
let diffX, diffY; let diffX, diffY;
@ -622,9 +622,10 @@ export function floater(container: RedrawableHTML, content: NodeChildren | (() =
Object.assign(floating.content.style, { Object.assign(floating.content.style, {
left: `${clamp(box.left, viewbox.left, viewbox.right)}px`, left: `${clamp(box.left, viewbox.left, viewbox.right)}px`,
top: `${clamp(box.top, viewbox.top, viewbox.bottom)}px`, top: `${clamp(box.top, viewbox.top, viewbox.bottom)}px`,
width: `${box.width + 21}px`, width: `${typeof settings?.pinned === 'object' ? settings.pinned.width : settings?.pinned === false ? box.width + 21 : 400}px`,
height: `${box.height + 21}px`, height: `${typeof settings?.pinned === 'object' ? settings.pinned.height : settings?.pinned === false ? box.height + 21 : 300}px`,
}); });
floating.content.attributeStyleMap.delete('bottom'); floating.content.attributeStyleMap.delete('bottom');
floating.content.attributeStyleMap.delete('right'); floating.content.attributeStyleMap.delete('right');
floating.stop(); floating.stop();
@ -671,7 +672,7 @@ export function floater(container: RedrawableHTML, content: NodeChildren | (() =
const floating = popper(container, { const floating = popper(container, {
arrow: true, arrow: true,
delay: settings?.pinned ? 0 : 150, delay: settings?.pinned ? 0 : settings?.delay ?? 150,
offset: 12, offset: 12,
cover: settings?.cover, cover: settings?.cover,
placement: settings?.position, placement: settings?.position,

View File

@ -178,6 +178,7 @@ export class Content
} }
static async getContent(id: string): Promise<LocalContent | undefined> static async getContent(id: string): Promise<LocalContent | undefined>
{ {
await Content.ready;
const overview = Content._overview[id]; const overview = Content._overview[id];
if(!overview) if(!overview)

View File

@ -249,7 +249,7 @@ export class MarkdownEditor
} }
constructor() constructor()
{ {
this._dom = div('flex h-full relative', [ div('absolute -top-1 -left-1 -translate-x-px -translate-y-px z-10 group', [ div('group-hover:hidden group-data-[focused]:hidden w-0 h-0 border-8 border-transparent border-l-light-40 dark:border-l-dark-40 border-t-light-40 dark:border-t-dark-40'), button([icon('radix-icons:gear')], MarkdownEditor.settings, 'p-1 hidden group-data-[focused]:block group-hover:block') ]), ]); this._dom = div('flex h-full relative', [ div('absolute -top-1 -left-1 -translate-x-px -translate-y-px z-10 group/editor', [ div('group-hover/editor:hidden group-data-[focused]/editor:hidden w-0 h-0 border-8 border-transparent border-l-light-40 dark:border-l-dark-40 border-t-light-40 dark:border-t-dark-40'), button([icon('radix-icons:gear')], MarkdownEditor.settings, 'p-1 hidden group-data-[focused]/editor:block group-hover/editor:block') ]), ]);
this._decoratorVisible = ViewPlugin.fromClass(Decorator, { this._decoratorVisible = ViewPlugin.fromClass(Decorator, {
decorations: undefined, decorations: undefined,
}).of(undefined); }).of(undefined);

View File

@ -160,7 +160,7 @@ export function popper(container: RedrawableHTML, properties?: PopperProperties)
clearTimeout(timeout); clearTimeout(timeout);
state = 'showing'; state = 'showing';
timeout = setTimeout(() => { const _show = () => {
if(state !== 'shown') if(state !== 'shown')
{ {
teleport!.appendChild(floater); teleport!.appendChild(floater);
@ -179,7 +179,11 @@ export function popper(container: RedrawableHTML, properties?: PopperProperties)
}); });
} }
state = 'shown'; state = 'shown';
}, properties?.delay ?? 0); };
if(properties?.delay === 0)
_show();
else
timeout = setTimeout(_show, properties?.delay ?? 0);
} }
} }
@ -190,7 +194,7 @@ export function popper(container: RedrawableHTML, properties?: PopperProperties)
clearTimeout(timeout); clearTimeout(timeout);
state = 'hiding'; state = 'hiding';
timeout = setTimeout(() => { const _hide = () => {
floater.remove(); floater.remove();
_stop && _stop(); _stop && _stop();
@ -198,7 +202,11 @@ export function popper(container: RedrawableHTML, properties?: PopperProperties)
floater.classList.toggle('hidden', true); floater.classList.toggle('hidden', true);
state = 'hidden'; state = 'hidden';
}, properties?.delay ?? 0); }
if(properties?.delay === 0)
_hide();
else
timeout = setTimeout(_hide, properties?.delay ?? 0);
} }
} }

View File

@ -1,4 +1,4 @@
import type { Root, RootContent } from "hast"; import type { Element, Root, RootContent } from "hast";
import { dom, text, type Class, type Node } from "#shared/dom.util"; import { dom, text, type Class, type Node } from "#shared/dom.util";
import prose, { a, blockquote, tag, h1, h2, h3, h4, h5, hr, li, small, table, td, th, callout, type Prose } from "#shared/proses"; import prose, { a, blockquote, tag, h1, h2, h3, h4, h5, hr, li, small, table, td, th, callout, type Prose } from "#shared/proses";
import { heading } from "hast-util-heading"; import { heading } from "hast-util-heading";
@ -6,6 +6,7 @@ import { headingRank } from "hast-util-heading-rank";
import { parseId } from "#shared/general.util"; import { parseId } from "#shared/general.util";
import { async } from "#shared/components.util"; import { async } from "#shared/components.util";
export const defaultProses = { a, blockquote, tag, callout, h1, h2, h3, h4, h5, hr, li, small, table, td, th };
export function renderMarkdown(markdown: Root, proses: Record<string, Prose>) export function renderMarkdown(markdown: Root, proses: Record<string, Prose>)
{ {
return dom('div', {}, markdown.children.map(e => renderContent(e, proses))); return dom('div', {}, markdown.children.map(e => renderContent(e, proses)));
@ -43,10 +44,7 @@ export interface MDProperties
style?: string | Record<string, string>; style?: string | Record<string, string>;
tags?: Record<string, Prose>; tags?: Record<string, Prose>;
} }
export function markdownReference(content: string, filter?: string, properties?: MDProperties) export function filterMarkdown(data: Root, filter: string)
{
const state = async('large', useMarkdown().parse(content).then(data => {
if(filter)
{ {
const start = data?.children.findIndex(e => heading(e) && parseId(e.properties.id as string | undefined) === filter) ?? -1; const start = data?.children.findIndex(e => heading(e) && parseId(e.properties.id as string | undefined) === filter) ?? -1;
@ -60,9 +58,15 @@ export function markdownReference(content: string, filter?: string, properties?:
if(heading(data.children[end]) && headingRank(data.children[end]!)! <= rank) if(heading(data.children[end]) && headingRank(data.children[end]!)! <= rank)
break; break;
} }
data = { ...data, children: data.children.slice(start, end) }; return { ...data, children: data.children.slice(start, end) };
} }
return data;
} }
export function markdownReference(content: string, filter?: string, properties?: MDProperties)
{
const state = async('large', useMarkdown().parse(content).then(data => {
if(filter) data = filterMarkdown(data, filter);
const el = dom('div', properties, data.children.map(e => renderContent(e, Object.assign({}, { a, blockquote, tag, callout, h1, h2, h3, h4, h5, hr, li, small, table, td, th }, properties?.tags)))); const el = dom('div', properties, data.children.map(e => renderContent(e, Object.assign({}, { a, blockquote, tag, callout, h1, h2, h3, h4, h5, hr, li, small, table, td, th }, properties?.tags))));

View File

@ -5,7 +5,6 @@ import { Canvas } from "#shared/canvas.util";
import { Content, iconByType, type LocalContent } from "#shared/content.util"; import { Content, iconByType, type LocalContent } from "#shared/content.util";
import { unifySlug } from "#shared/general.util"; import { unifySlug } from "#shared/general.util";
import { async, floater } from "./components.util"; import { async, floater } from "./components.util";
import type { FloatState } from "./floating.util";
export type CustomProse = (properties: any, children: NodeChildren) => Node; export type CustomProse = (properties: any, children: NodeChildren) => Node;
@ -20,7 +19,7 @@ export const a: Prose = {
const link = overview ? { name: 'explore-path', params: { path: overview.path }, hash: hash } : href, nav = router.resolve(link); const link = overview ? { name: 'explore-path', params: { path: overview.path }, hash: hash } : href, nav = router.resolve(link);
const element = dom('a', { class: ['text-accent-blue inline-flex items-center', properties?.class], attributes: { href: nav.href }, listeners: { const element = properties?.navigate ?? true ? dom('a', { class: ['text-accent-blue inline-flex items-center', properties?.class], attributes: { href: nav.href }, listeners: {
'click': (e) => { 'click': (e) => {
e.preventDefault(); e.preventDefault();
router.push(link); router.push(link);
@ -30,6 +29,9 @@ export const a: Prose = {
...(children ?? []), ...(children ?? []),
overview && overview.type !== 'markdown' ? icon(iconByType[overview.type], { class: 'w-4 h-4 inline-block', inline: true }) : undefined overview && overview.type !== 'markdown' ? icon(iconByType[overview.type], { class: 'w-4 h-4 inline-block', inline: true }) : undefined
]) ])
]) : dom('span', { class: ['cursor-pointer text-accent-blue inline-flex items-center', properties?.class] }, [
...(children ?? []),
overview && overview.type !== 'markdown' ? icon(iconByType[overview.type], { class: 'w-4 h-4 inline-block', inline: true }) : undefined
]); ]);
return !!overview ? floater(element, () => [async('large', Content.getContent(overview.id).then((_content) => { return !!overview ? floater(element, () => [async('large', Content.getContent(overview.id).then((_content) => {
@ -44,11 +46,11 @@ export const a: Prose = {
return dom('div', { class: 'w-[600px] h-[600px] group-data-[pinned]:h-full group-data-[pinned]:w-full h-[600px] relative w-[600px] relative' }, [canvas.container]); return dom('div', { class: 'w-[600px] h-[600px] group-data-[pinned]:h-full group-data-[pinned]:w-full h-[600px] relative w-[600px] relative' }, [canvas.container]);
} }
return div(''); return div('');
})).current], { position: 'bottom-start', pinned: false, title: properties?.label, href: nav.href }) : element; })).current], { events: { show: properties?.trigger !== 'click' ? ['mouseenter', 'mousemove', 'focus'] : ['click'], hide: properties?.trigger !== 'click' ? ['mouseleave', 'blur'] : ['click'] }, position: 'bottom-start', pinned: false, title: properties?.label, href: nav.href }) : element;
} }
} }
export const preview: Prose = { export const preview: Prose = {
custom(properties: { href: string, class?: Class, label: string }, children) { custom(properties: { href: string, class?: Class, label?: string, trigger?: 'hover' | 'click', navigate?: boolean }, children) {
const href = properties.href as string; const href = properties.href as string;
const { hash, pathname } = parseURL(href); const { hash, pathname } = parseURL(href);
const router = useRouter(); const router = useRouter();
@ -60,7 +62,6 @@ export const preview: Prose = {
overview && overview.type !== 'markdown' ? icon(iconByType[overview.type], { class: 'w-4 h-4 inline-block', inline: true }) : undefined overview && overview.type !== 'markdown' ? icon(iconByType[overview.type], { class: 'w-4 h-4 inline-block', inline: true }) : undefined
]); ]);
const magicKeys = useMagicKeys();
return !!overview ? floater(element, () => [async('large', Content.getContent(overview.id).then((_content) => { return !!overview ? floater(element, () => [async('large', Content.getContent(overview.id).then((_content) => {
if(_content?.type === 'markdown') if(_content?.type === 'markdown')
{ {
@ -73,13 +74,10 @@ export const preview: Prose = {
return dom('div', { class: 'w-[600px] h-[600px] group-data-[pinned]:h-full group-data-[pinned]:w-full h-[600px] relative w-[600px] relative' }, [canvas.container]); return dom('div', { class: 'w-[600px] h-[600px] group-data-[pinned]:h-full group-data-[pinned]:w-full h-[600px] relative w-[600px] relative' }, [canvas.container]);
} }
return div(); return div();
})).current], { position: 'bottom-start', pinned: false, })).current], { position: 'bottom-start', pinned: true,
events: { events: {
show: ['mouseenter', 'mousemove'], show: ['click'],
hide: ['mouseleave'], hide: ['click'],
onshow(state: FloatState) {
return state === 'shown' || state === 'hiding' || magicKeys.current.has('control') || magicKeys.current.has('meta');
}
}, title: properties?.label, href: { name: 'explore-path', params: { path: overview.path }, hash: hash } }) : element; }, title: properties?.label, href: { name: 'explore-path', params: { path: overview.path }, hash: hash } }) : element;
} }
} }