Several small fixes with rendering and floating components
This commit is contained in:
parent
7021264c11
commit
0eaffcaa04
|
|
@ -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', [
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,26 +44,29 @@ export interface MDProperties
|
||||||
style?: string | Record<string, string>;
|
style?: string | Record<string, string>;
|
||||||
tags?: Record<string, Prose>;
|
tags?: Record<string, Prose>;
|
||||||
}
|
}
|
||||||
|
export function filterMarkdown(data: Root, filter: string)
|
||||||
|
{
|
||||||
|
const start = data?.children.findIndex(e => heading(e) && parseId(e.properties.id as string | undefined) === filter) ?? -1;
|
||||||
|
|
||||||
|
if(start !== -1)
|
||||||
|
{
|
||||||
|
let end = start;
|
||||||
|
const rank = headingRank(data.children[start]!)!;
|
||||||
|
while(end < data.children.length)
|
||||||
|
{
|
||||||
|
end++;
|
||||||
|
if(heading(data.children[end]) && headingRank(data.children[end]!)! <= rank)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return { ...data, children: data.children.slice(start, end) };
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
export function markdownReference(content: string, filter?: string, properties?: MDProperties)
|
export function markdownReference(content: string, filter?: string, properties?: MDProperties)
|
||||||
{
|
{
|
||||||
const state = async('large', useMarkdown().parse(content).then(data => {
|
const state = async('large', useMarkdown().parse(content).then(data => {
|
||||||
if(filter)
|
if(filter) data = filterMarkdown(data, filter);
|
||||||
{
|
|
||||||
const start = data?.children.findIndex(e => heading(e) && parseId(e.properties.id as string | undefined) === filter) ?? -1;
|
|
||||||
|
|
||||||
if(start !== -1)
|
|
||||||
{
|
|
||||||
let end = start;
|
|
||||||
const rank = headingRank(data.children[start]!)!;
|
|
||||||
while(end < data.children.length)
|
|
||||||
{
|
|
||||||
end++;
|
|
||||||
if(heading(data.children[end]) && headingRank(data.children[end]!)! <= rank)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
data = { ...data, children: data.children.slice(start, end) };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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))));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue