Fix content read pages and proses getting content. Start working on CanvasEditor.

This commit is contained in:
Clément Pons 2025-04-01 17:23:26 +02:00
parent 1d41514b26
commit 6100fd9411
7 changed files with 222 additions and 88 deletions

Binary file not shown.

Binary file not shown.

View File

@ -57,6 +57,7 @@ import { hasPermissions } from '#shared/auth.util';
import { TreeDOM } from '#shared/tree';
import { Content, iconByType } from '#shared/content.util';
import { dom, icon, text } from '#shared/dom.util';
import { unifySlug } from '#shared/general.util';
import { popper } from '#shared/floating.util';
import { link } from '#shared/proses';
@ -77,7 +78,7 @@ const { fetch } = useContent();
await fetch(false);
const route = useRouter().currentRoute;
const path = computed(() => route.value.params.path ? decodeURIComponent(Array.isArray(route.value.params.path) ? route.value.params.path[0] : route.value.params.path) : undefined);
const path = computed(() => route.value.params.path ? decodeURIComponent(unifySlug(route.value.params.path)) : undefined);
await Content.init();
const tree = new TreeDOM((item, depth) => {
@ -100,7 +101,7 @@ const unmount = useRouter().afterEach((to, from, failure) => {
if(failure)
return;
to.name === 'explore-path' && ((to.params.path as string).split('/').map((e, i, a) => a.slice(0, i).join('/')) ?? []).forEach(e => tree.toggle(e, true));
to.name === 'explore-path' && (unifySlug(to.params.path).split('/').map((e, i, a) => a.slice(0, i).join('/')) ?? []).forEach(e => tree.toggle(e, true));
});
watch(route, () => {

View File

@ -7,16 +7,16 @@
</template>
<script setup lang="ts">
import { Content } from '~/shared/content.util';
import { Content } from '#shared/content.util';
import { unifySlug } from '#shared/general.util';
const element = useTemplateRef('element'), overview = ref();
const route = useRouter().currentRoute;
const path = computed(() => Array.isArray(route.value.params.path) ? route.value.params.path[0] : route.value.params.path);
const path = computed(() => unifySlug(route.value.params.path));
onMounted(async () => {
if(element.value && path.value)
if(element.value && path.value && await Content.ready)
{
await Content.init()
overview.value = Content.render(element.value, path.value);
}
});

View File

@ -4,6 +4,8 @@ import { dom, icon, svg, text } from "./dom.util";
import render from "./markdown.util";
import { popper } from "#shared/floating.util";
import { Content } from "./content.util";
import type { History } from "./history.util";
import { EventEmitter } from "nodemailer/lib/xoauth2";
export type Direction = 'bottom' | 'top' | 'left' | 'right';
export type Position = { x: number, y: number };
@ -127,29 +129,36 @@ function distance(touches: TouchList): number
return Math.hypot(B.clientX - A.clientX, B.clientY - A.clientY);
}
export class Node
export class Node extends EventEmitter
{
properties: CanvasNode;
nodeDom: HTMLDivElement;
nodeDom!: HTMLDivElement;
constructor(properties: CanvasNode)
{
super();
this.properties = properties;
this.getDOM()
}
protected getDOM()
{
const style = this.style;
this.nodeDom = dom('div', { class: ['absolute', {'-z-10': properties.type === 'group', 'z-10': properties.type !== 'group'}], style: { transform: `translate(${properties.x}px, ${properties.y}px)`, width: `${properties.width}px`, height: `${properties.height}px`, '--canvas-color': properties.color?.hex } }, [
this.nodeDom = dom('div', { class: ['absolute', {'-z-10': this.properties.type === 'group', 'z-10': this.properties.type !== 'group'}], style: { transform: `translate(${this.properties.x}px, ${this.properties.y}px)`, width: `${this.properties.width}px`, height: `${this.properties.height}px`, '--canvas-color': this.properties.color?.hex } }, [
dom('div', { class: ['outline-0 transition-[outline-width] border-2 bg-light-20 dark:bg-dark-20 w-full h-full hover:outline-4', style.border] }, [
dom('div', { class: ['w-full h-full py-2 px-4 flex !bg-opacity-[0.07] overflow-auto', style.bg] }, [properties.text ? dom('div', { class: 'flex items-center' }, [render(properties.text)]) : undefined])
dom('div', { class: ['w-full h-full py-2 px-4 flex !bg-opacity-[0.07] overflow-auto', style.bg] }, [this.properties.text ? dom('div', { class: 'flex items-center' }, [render(this.properties.text)]) : undefined])
])
]);
if(properties.type === 'group')
if(this.properties.type === 'group')
{
if(properties.label !== undefined)
if(this.properties.label !== undefined)
{
this.nodeDom.appendChild(dom('div', { class: ['origin-bottom-left tracking-wider border-4 truncate inline-block text-light-100 dark:text-dark-100 absolute bottom-[100%] mb-2 px-2 py-1 font-thin', style.border], style: 'max-width: 100%; font-size: calc(18px * var(--zoom-multiplier))', text: properties.label }));
this.nodeDom.appendChild(dom('div', { class: ['origin-bottom-left tracking-wider border-4 truncate inline-block text-light-100 dark:text-dark-100 absolute bottom-[100%] mb-2 px-2 py-1 font-thin', style.border], style: 'max-width: 100%; font-size: calc(18px * var(--zoom-multiplier))', text: this.properties.label }));
}
}
}
@ -162,46 +171,49 @@ export class Node
{ border: `border-light-40 dark:border-dark-40`, bg: `bg-light-40 dark:bg-dark-40` }
}
}
export class Edge
export class NodeEditable extends Node {
constructor(properties: CanvasNode)
{
super(properties);
}
protected override getDOM()
{
super.getDOM();
}
}
export class Edge extends EventEmitter
{
properties: CanvasEdge;
edgeDom: HTMLDivElement;
#from: CanvasNode;
#to: CanvasNode;
#path: Path;
#labelPos: string;
edgeDom!: HTMLDivElement;
protected from: CanvasNode;
protected to: CanvasNode;
protected path: Path;
protected labelPos: string;
constructor(properties: CanvasEdge, nodes: CanvasNode[])
{
super();
this.properties = properties;
this.#from = nodes.find(f => f.id === properties.fromNode)!;
this.#to = nodes.find(f => f.id === properties.toNode)!;
this.#path = getPath(this.#from, properties.fromSide, this.#to, properties.toSide)!;
this.#labelPos = labelCenter(this.#from, properties.fromSide, this.#to, properties.toSide);
this.from = nodes.find(f => f.id === properties.fromNode)!;
this.to = nodes.find(f => f.id === properties.toNode)!;
this.path = getPath(this.from, properties.fromSide, this.to, properties.toSide)!;
this.labelPos = labelCenter(this.from, properties.fromSide, this.to, properties.toSide);
}
protected getDOM()
{
const style = this.style;
/* <div class="absolute overflow-visible">
<div v-if="edge.label" :style="{ transform: `${labelPos} translate(-50%, -50%)` }" class="relative bg-light-20 dark:bg-dark-20 border border-light-35 dark:border-dark-35 px-4 py-2 z-20">{{ edge.label }}</div>
<svg class="absolute top-0 overflow-visible h-px w-px">
<g :style="{'--canvas-color': edge.color?.hex}" class="z-0">
<g :style="`transform: translate(${this.#path!.to.x}px, ${this.#path!.to.y}px) scale(var(--zoom-multiplier)) rotate(${rotation[this.#path!.side]}deg);`">
<polygon :class="style.fill" points="0,0 6.5,10.4 -6.5,10.4"></polygon>
</g>
<path :style="`stroke-width: calc(3px * var(--zoom-multiplier));`" style="stroke-linecap: butt;" :class="style.stroke" class="fill-none stroke-[4px]" :d="this.#path!.path"></path>
</g>
</svg>
</div> */
this.edgeDom = dom('div', { class: 'absolute overflow-visible' }, [
properties.label ? dom('div', { style: { transform: `${this.#labelPos} translate(-50%, -50%)` }, class: 'relative bg-light-20 dark:bg-dark-20 border border-light-35 dark:border-dark-35 px-4 py-2 z-20', text: properties.label }) : undefined,
this.properties.label ? dom('div', { style: { transform: `${this.labelPos} translate(-50%, -50%)` }, class: 'relative bg-light-20 dark:bg-dark-20 border border-light-35 dark:border-dark-35 px-4 py-2 z-20', text: this.properties.label }) : undefined,
svg('svg', { class: 'absolute top-0 overflow-visible h-px w-px' }, [
svg('g', { style: {'--canvas-color': properties.color?.hex}, class: 'z-0' }, [
svg('g', { style: `transform: translate(${this.#path!.to.x}px, ${this.#path!.to.y}px) scale(var(--zoom-multiplier)) rotate(${rotation[this.#path!.side]}deg);` }, [
svg('g', { style: {'--canvas-color': this.properties.color?.hex}, class: 'z-0' }, [
svg('g', { style: `transform: translate(${this.path!.to.x}px, ${this.path!.to.y}px) scale(var(--zoom-multiplier)) rotate(${rotation[this.path!.side]}deg);` }, [
svg('polygon', { class: style.fill, attributes: { points: '0,0 6.5,10.4 -6.5,10.4' } }),
]),
svg('path', { style: `stroke-width: calc(3px * var(--zoom-multiplier)); stroke-linecap: butt;`, class: [style.stroke, 'fill-none stroke-[4px]'], attributes: { d: this.#path!.path } }),
svg('path', { style: `stroke-width: calc(3px * var(--zoom-multiplier)); stroke-linecap: butt;`, class: [style.stroke, 'fill-none stroke-[4px]'], attributes: { d: this.path!.path } }),
]),
]),
]);
@ -215,26 +227,61 @@ export class Edge
{ stroke: `stroke-light-40 dark:stroke-dark-40`, fill: `fill-light-40 dark:fill-dark-40` }
}
}
export class EdgeEditable extends Edge
{
private static input: HTMLInputElement = dom('input', { class: 'relative bg-light-20 dark:bg-dark-20 border border-light-35 dark:border-dark-35 px-4 py-2 z-20 -translate-x-1/2 -translate-y-1/2', listeners: { click: e => e.stopImmediatePropagation() } });
private focusing: boolean = false;
private editing: boolean = false;
private pathDom!: SVGPathElement;
private inputDom!: HTMLDivElement;
constructor(properties: CanvasEdge, nodes: CanvasNode[])
{
super(properties, nodes);
}
protected override getDOM()
{
const style = this.style;
this.pathDom = svg('path', { style: { 'stroke-width': `calc(3px * var(--zoom-multiplier))`, 'stroke-linecap': 'butt' }, class: ['transition-[stroke-width] fill-none stroke-[4px]', style.stroke], listeners: { click: e => this.emit('select', e), dblclick: e => this.emit('edit', e) } });
this.inputDom = dom('div', { class: ['relative bg-light-20 dark:bg-dark-20 border border-light-35 dark:border-dark-35 px-4 py-2 z-20 -translate-x-1/2 -translate-y-1/2', { 'hidden': this.properties.label === undefined }], style: { transform: this.labelPos }, text: this.properties.label });
this.edgeDom = dom('div', { class: 'absolute overflow-visible group' }, [
this.inputDom,
svg('svg', { class: 'absolute top-0 overflow-visible h-px w-px' }, [
svg('g', { style: { '--canvas-color': this.properties.color?.hex } }, [
svg('g', { style: { transform: `translate(${this.path.to.x}px, ${this.path.to.y}px) scale(var(--zoom-multiplier)) rotate(${rotation[this.path.side]}deg)` } }, [
svg('polygon', { class: style.fill, attributes: { 'points': '0,0 6.5,10.4 -6.5,10.4' } }),
]),
this.pathDom,
svg('path', { style: { 'stroke-width': `calc(22px * var(--zoom-multiplier))` }, class: ['fill-none transition-opacity z-30 opacity-0 hover:opacity-25', style.stroke], attributes: { d: this.path.path } }),
]),
]),
]);
}
}
export class Canvas
{
static minZoom: number = 0.3;
static maxZoom: number = 3;
private content: Required<CanvasContent>;
private zoom: number = 0.5;
private x: number = 0;
private y: number = 0;
protected content: Required<CanvasContent>;
protected zoom: number = 0.5;
protected x: number = 0;
protected y: number = 0;
private visualZoom: number = this.zoom;
private visualX: number = this.x;
private visualY: number = this.y;
private centerX: number = 0;
private centerY: number = 0;
private containZoom: number = 0.5;
private tweener: Tweener = new Tweener();
protected visualZoom: number = this.zoom;
protected visualX: number = this.x;
protected visualY: number = this.y;
protected tweener: Tweener = new Tweener();
private debouncedTimeout: Timer = setTimeout(() => {}, 0);
private transform: HTMLDivElement;
container: HTMLDivElement;
protected transform!: HTMLDivElement;
container!: HTMLDivElement;
constructor(content?: CanvasContent)
{
@ -252,6 +299,16 @@ export class Canvas
this.content = content as Required<CanvasContent>;
this.createDOM();
this.computeLimits();
this.reset();
this.mount();
}
protected createDOM()
{
this.transform = dom('div', { class: 'origin-center h-full' }, [
dom('div', { class: 'absolute top-0 left-0 w-full h-full pointer-events-none *:pointer-events-auto *:select-none touch-none' }, [
...this.content.nodes.map(e => new Node(e).nodeDom), ...this.content.edges.map(e => new Edge(e, this.content.nodes).edgeDom),
@ -275,7 +332,8 @@ export class Canvas
}),
]), //dom('a') Edition link
]), this.transform,
])
]);
/*
<NuxtLink v-if="overview && isOwner || hasPermissions(user?.permissions ?? [], ['admin', 'editor'])" :to="{ name: 'explore-edit', hash: `#${encodeURIComponent(overview!.path)}` }" class="border border-light-35 dark:border-dark-35 bg-light-10 dark:bg-dark-10">
<Tooltip message="Modifier" side="right">
@ -283,8 +341,23 @@ export class Canvas
</Tooltip>
</NuxtLink>
*/
}
this.mount();
private computeLimits()
{
const box = this.container.getBoundingClientRect();
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
this.content.nodes.forEach(e => {
minX = Math.min(minX, e.x);
minY = Math.min(minY, e.y);
maxX = Math.max(maxX, e.x);
maxY = Math.max(maxY, e.y);
});
this.centerX = minX + (maxX - minX) / 2;
this.centerY = minY + (maxY - minY) / 2;
this.containZoom = Math.min((maxX - minX) / box.width, (maxY - minY) / box.height);
}
mount()
@ -400,7 +473,7 @@ export class Canvas
this.container.style.setProperty('--zoom-multiplier', (1 / Math.pow(this.visualZoom, 0.7)).toFixed(3));
}
private zoomTo(x: number, y: number, zoom: number)
protected zoomTo(x: number, y: number, zoom: number)
{
const oldX = this.x, oldY = this.y, oldZoom = this.zoom;
this.x = x;
@ -416,16 +489,62 @@ export class Canvas
}, 50);
}
private reset()
protected reset()
{
this.tweener.stop();
this.zoom = this.visualZoom = 0.5;
this.x = this.visualX = 0;
this.y = this.visualY = 0;
this.updateTransform();
this.updateScale();
this.zoomTo(this.centerX, this.centerY, this.containZoom);
}
}
export class CanvasEditor extends Canvas
{
private history: History;
private selection: Array<NodeEditable | EdgeEditable> = [];
constructor(history: History, content?: CanvasContent)
{
super(content);
this.history = history;
}
protected override createDOM()
{
this.transform = dom('div', { class: 'origin-center h-full' }, [
dom('div', { class: 'absolute top-0 left-0 w-full h-full pointer-events-none *:pointer-events-auto *:select-none touch-none' }, [
...this.content.nodes.map(e => new NodeEditable(e).nodeDom), ...this.content.edges.map(e => new EdgeEditable(e, this.content.nodes).edgeDom),
])
]);
//TODO: --zoom-multiplier dynamic
this.container = dom('div', { class: 'absolute top-0 left-0 overflow-hidden w-full h-full touch-none' }, [
dom('div', { class: 'flex flex-col absolute sm:top-2 top-10 left-2 z-[35] overflow-hidden gap-4' }, [
dom('div', { class: 'border border-light-35 dark:border-dark-35 bg-light-10 dark:bg-dark-10' }, [
popper(dom('span', { class: 'w-8 h-8 flex justify-center items-center p-2 hover:bg-light-30 dark:hover:bg-dark-30 cursor-pointer', listeners: { click: () => this.zoomTo(this.x, this.y, clamp(this.zoom * 1.1, Canvas.minZoom, Canvas.maxZoom)) } }, [icon('radix-icons:plus')]), {
delay: 120, arrow: true, placement: 'right', offset: 8, content: [text('Zoom avant')], class: 'TooltipContent border border-light-30 dark:border-dark-30 px-2 py-1 bg-light-10 dark:bg-dark-10 text-light-70 dark:text-dark-70 z-50'
}),
popper(dom('span', { class: 'w-8 h-8 flex justify-center items-center p-2 hover:bg-light-30 dark:hover:bg-dark-30 cursor-pointer', listeners: { click: (e: MouseEvent) => { this.reset(); } } }, [icon('radix-icons:reload')]), {
delay: 120, arrow: true, placement: 'right', offset: 8, content: [text('Reset')], class: 'TooltipContent border border-light-30 dark:border-dark-30 px-2 py-1 bg-light-10 dark:bg-dark-10 text-light-70 dark:text-dark-70 z-50'
}),
popper(dom('span', { class: 'w-8 h-8 flex justify-center items-center p-2 hover:bg-light-30 dark:hover:bg-dark-30 cursor-pointer', listeners: { click: (e: MouseEvent) => { this.zoomTo(this.x, this.y, Canvas.minZoom); } } }, [icon('radix-icons:corners')]), {
delay: 120, arrow: true, placement: 'right', offset: 8, content: [text('Tout contenir')], class: 'TooltipContent border border-light-30 dark:border-dark-30 px-2 py-1 bg-light-10 dark:bg-dark-10 text-light-70 dark:text-dark-70 z-50'
}),
popper(dom('span', { class: 'w-8 h-8 flex justify-center items-center p-2 hover:bg-light-30 dark:hover:bg-dark-30 cursor-pointer', listeners: { click: () => this.zoomTo(this.x, this.y, clamp(this.zoom / 1.1, Canvas.minZoom, Canvas.maxZoom)) } }, [icon('radix-icons:minus')]), {
delay: 120, arrow: true, placement: 'right', offset: 8, content: [text('Zoom arrière')], class: 'TooltipContent border border-light-30 dark:border-dark-30 px-2 py-1 bg-light-10 dark:bg-dark-10 text-light-70 dark:text-dark-70 z-50'
}),
]),
dom('div', { class: 'border border-light-35 dark:border-dark-35 bg-light-10 dark:bg-dark-10' }, [
popper(dom('span', { class: 'w-8 h-8 flex justify-center items-center p-2 hover:bg-light-30 dark:hover:bg-dark-30 cursor-pointer', listeners: { click: () => this.history.undo() } }, [icon('ph:arrow-bend-up-left')]), {
delay: 120, arrow: true, placement: 'right', offset: 8, content: [text('Annuler (Ctrl+Z)')], class: 'TooltipContent border border-light-30 dark:border-dark-30 px-2 py-1 bg-light-10 dark:bg-dark-10 text-light-70 dark:text-dark-70 z-50'
}),
popper(dom('span', { class: 'w-8 h-8 flex justify-center items-center p-2 hover:bg-light-30 dark:hover:bg-dark-30 cursor-pointer', listeners: { click: () => this.history.redo() } }, [icon('ph:arrow-bend-up-right')]), {
delay: 120, arrow: true, placement: 'right', offset: 8, content: [text('Rétablir (Ctrl+Y)')], class: 'TooltipContent border border-light-30 dark:border-dark-30 px-2 py-1 bg-light-10 dark:bg-dark-10 text-light-70 dark:text-dark-70 z-50'
}),
]),
dom('div', { class: 'border border-light-35 dark:border-dark-35 bg-light-10 dark:bg-dark-10' }, [
popper(dom('span', { class: 'w-8 h-8 flex justify-center items-center p-2 hover:bg-light-30 dark:hover:bg-dark-30 cursor-pointer', listeners: { click: () => this.history.undo() } }, [icon('radix-icons:gear')]), {
delay: 120, arrow: true, placement: 'right', offset: 8, content: [text('Préférences')], class: 'TooltipContent border border-light-30 dark:border-dark-30 px-2 py-1 bg-light-10 dark:bg-dark-10 text-light-70 dark:text-dark-70 z-50'
}),
popper(dom('span', { class: 'w-8 h-8 flex justify-center items-center p-2 hover:bg-light-30 dark:hover:bg-dark-30 cursor-pointer', listeners: { click: () => this.history.redo() } }, [icon('radix-icons:question-mark-circled')]), {
delay: 120, arrow: true, placement: 'right', offset: 8, content: [text('Aide')], class: 'TooltipContent border border-light-30 dark:border-dark-30 px-2 py-1 bg-light-10 dark:bg-dark-10 text-light-70 dark:text-dark-70 z-50'
}),
]),
]), this.transform,
]);
}
}

View File

@ -153,13 +153,24 @@ export class Content
return Content.initPromise;
}
static async get(id: string, content: boolean): Promise<LocalContent | undefined>
static getFromPath(path: string, content: boolean = false)
{
return Object.values(Content._overview).find(e => e.path === path);
}
static get(id: string, content: boolean = false)
{
return Content._overview[id];
}
static async getContent(id: string): Promise<LocalContent | undefined>
{
const overview = Content._overview[id];
return overview ? { ...overview, content: content ? Content.fromString(overview, await Content.read(id) ?? '') : undefined } as LocalContent : undefined;
if(!overview)
return;
return { ...overview, content: Content.fromString(overview, (await Content.read(id, { create: true }))!) };
}
static async set(id: string, overview?: Omit<LocalContent, 'content'> | Recursive<Omit<LocalContent, 'content'>>)
static set(id: string, overview?: Omit<LocalContent, 'content'> | Recursive<Omit<LocalContent, 'content'>>)
{
if(overview === undefined)
{
@ -231,9 +242,9 @@ export class Content
continue;
Content.queue.queue(() => {
return useRequestFetch()(`/api/file/content/${file.id}`, { cache: 'no-cache' }).then(async (content: ContentMap[FileType] | undefined) => {
return useRequestFetch()(`/api/file/content/${file.id}`, { cache: 'no-cache' }).then(async (content: string | undefined) => {
if(content)
Content.queue.queue(() => Content.write(file.id, Content.toString({ ...file, content }), { create: true }));
Content.queue.queue(() => Content.write(file.id, content, { create: true }));
else
Content._overview[file.id].error = true;
}).catch(e => {
@ -319,7 +330,7 @@ export class Content
static render(parent: HTMLElement, path: string): Omit<LocalContent, 'content'> | undefined
{
const overview = Content.overview(path);
const overview = Content.getFromPath(path);
if(!!overview)
{
@ -332,7 +343,7 @@ export class Content
el && parent.replaceChild(el, load);
}
Content.content(path).then(content => _render(content!));
Content.getContent(overview.id).then(content => _render(content!));
}
else
{
@ -423,7 +434,7 @@ const handlers: { [K in FileType]: ContentTypeHandler<K> } = {
else
{
element = loading("large");
Content.get(content.id, true).then(e => {
Content.getContent(content.id).then(e => {
if(!e)
return element.parentElement?.replaceChild(dom('div', { class: '', text: 'Une erreur est survenue.' }), element);
@ -783,6 +794,7 @@ export class Editor
{
if(this.selected && item)
{
console.log(this.selected.content);
Content.save(this.selected);
}
if(this.selected === item)

View File

@ -1,10 +1,11 @@
import { dom, icon, type NodeChildren, type Node, type NodeProperties, type Class, mergeClasses } from "./dom.util";
import { dom, icon, type NodeChildren, type Node, type NodeProperties, type Class, mergeClasses } from "#shared/dom.util";
import { parseURL } from 'ufo';
import render from "./markdown.util";
import render from "#shared/markdown.util";
import { popper } from "#shared/floating.util";
import { Canvas } from "./canvas.util";
import { Content, iconByType, type LocalContent } from "./content.util";
import { Canvas } from "#shared/canvas.util";
import { Content, iconByType, type LocalContent } from "#shared/content.util";
import type { RouteLocationAsRelativeTyped, RouteMapGeneric } from "vue-router";
import { unifySlug } from "#shared/general.util";
export type CustomProse = (properties: any, children: NodeChildren) => Node;
export type Prose = { class: string } | { custom: CustomProse };
@ -12,7 +13,7 @@ export const tag: Prose = {
custom(properties, children) {
const tag = properties.tag as string;
const el = dom('span', { class: "before:content-['#'] cursor-default bg-accent-blue bg-opacity-10 hover:bg-opacity-20 text-accent-blue text-sm px-1 ms-1 pb-0.5 rounded-full rounded-se-none border border-accent-blue border-opacity-30" }, children);
const overview = Content.overview('tags');
const overview = Content.getFromPath('tags');
let rendered = false;
@ -28,8 +29,8 @@ export const tag: Prose = {
onShow(content: HTMLDivElement) {
if(!rendered)
{
Content.content('tags').then((overview) => {
content.replaceChild(render((overview as LocalContent<'markdown'>).content ?? '', tag, { class: 'max-w-[600px] max-h-[600px] w-full overflow-auto py-4 px-6' }), content.children[0]);
Content.getContent(overview.id).then((_content) => {
content.replaceChild(render((_content as LocalContent<'markdown'>).content ?? '', tag, { class: 'max-w-[600px] max-h-[600px] w-full overflow-auto py-4 px-6' }), content.children[0]);
});
rendered = true;
}
@ -46,7 +47,7 @@ export const a: Prose = {
const { hash, pathname } = parseURL(href);
const router = useRouter();
const overview = Content.overview(pathname === '' && hash.length > 0 ? router.currentRoute.value.params.path[0] : pathname);
const overview = Content.getFromPath(pathname === '' && hash.length > 0 ? unifySlug(router.currentRoute.value.params.path) : pathname);
const link = overview ? { name: 'explore-path', params: { path: overview.path }, hash: hash } : href, nav = router.resolve(link);
@ -76,14 +77,15 @@ export const a: Prose = {
onShow(content: HTMLDivElement) {
if(!rendered)
{
Content.content(overview.path).then((overview) => {
if(overview?.type === 'markdown')
console.log('')
Content.getContent(overview.id).then((_content) => {
if(_content?.type === 'markdown')
{
content.replaceChild(render((overview as LocalContent<'markdown'>).content ?? '', hash.length > 0 ? hash.substring(1) : undefined, { class: 'min-w-[200px] min-h-[150px] max-w-[600px] max-h-[600px] w-full overflow-auto py-4 px-6' }), content.children[0]);
content.replaceChild(render((_content as LocalContent<'markdown'>).content ?? '', hash.length > 0 ? hash.substring(1) : undefined, { class: 'min-w-[200px] min-h-[150px] max-w-[600px] max-h-[600px] w-full overflow-auto py-4 px-6' }), content.children[0]);
}
if(overview?.type === 'canvas')
if(_content?.type === 'canvas')
{
const canvas = new Canvas((overview as LocalContent<'canvas'>).content);
const canvas = new Canvas((_content as LocalContent<'canvas'>).content);
content.replaceChild(dom('div', { class: 'w-[600px] h-[600px] relative' }, [canvas.container]), content.children[0]);
canvas.mount();
}
@ -103,7 +105,7 @@ export const fakeA: Prose = {
const { hash, pathname } = parseURL(href);
const router = useRouter();
const overview = Content.overview(pathname === '' && hash.length > 0 ? router.currentRoute.value.params.path[0] : pathname);
const overview = Content.getFromPath(pathname === '' && hash.length > 0 ? unifySlug(router.currentRoute.value.params.path) : pathname);
const el = dom('span', { class: 'cursor-pointer text-accent-blue inline-flex items-center' }, [
dom('span', {}, [
@ -127,14 +129,14 @@ export const fakeA: Prose = {
return false;
content.replaceChild(loading("large"), content.children[0]);
Content.content(overview.path).then((overview) => {
if(overview?.type === 'markdown')
Content.getContent(overview.id).then((_content) => {
if(_content?.type === 'markdown')
{
content.replaceChild(render((overview as LocalContent<'markdown'>).content ?? '', hash.length > 0 ? hash.substring(1) : undefined, { class: 'min-w-[200px] min-h-[150px] max-w-[600px] max-h-[600px] w-full overflow-auto py-4 px-6' }), content.children[0]);
content.replaceChild(render((_content as LocalContent<'markdown'>).content ?? '', hash.length > 0 ? hash.substring(1) : undefined, { class: 'min-w-[200px] min-h-[150px] max-w-[600px] max-h-[600px] w-full overflow-auto py-4 px-6' }), content.children[0]);
}
if(overview?.type === 'canvas')
if(_content?.type === 'canvas')
{
const canvas = new Canvas((overview as LocalContent<'canvas'>).content);
const canvas = new Canvas((_content as LocalContent<'canvas'>).content);
content.replaceChild(dom('div', { class: 'w-[600px] h-[600px] relative' }, [canvas.container]), content.children[0]);
canvas.mount();
}