Fix Canvas initial position and add tags popover

This commit is contained in:
2024-01-10 18:04:05 +01:00
parent a55b98e07a
commit a228b7d222
11 changed files with 149 additions and 108 deletions

View File

@@ -6,6 +6,7 @@ interface ParsedContentExtended extends Omit<ParsedContent, 'body'> {
body: MarkdownRoot | CanvasContent | null;
}
const tags = inject('tags') as ParsedContent;
const props = defineProps({
href: {
type: String,
@@ -16,7 +17,7 @@ const props = defineProps({
default: undefined,
required: false
}
})
});
function sluggify(s: string): string {
return s
@@ -29,40 +30,59 @@ function sluggify(s: string): string {
function flatten(val: TocLink[]): TocLink[] {
return val.flatMap ? val?.flatMap((e: TocLink) => e.children ? [e, ...flatten(e.children)] : e) : val;
}
function handleResult(result: ParsedContentExtended, tag: boolean = false) {
loading.value = false;
let body: MarkdownRoot | CanvasContent | null = JSON.parse(JSON.stringify(result.body));
if (anchor && result && body) {
if (result._type == 'markdown' && (body as MarkdownRoot).children) {
body = body as MarkdownRoot;
const id = flatten(body?.toc?.links ?? []).find(e => "#" + sluggify(e.id) === anchor.replaceAll('/', ''));
const tag = `h${id?.depth ?? 0}`;
const startIdx = body.children.findIndex(e => e.tag === tag && e?.props?.id === id?.id) ?? 0;
const nbr = body.children.findIndex((e, i) => i > startIdx && e.tag?.match(new RegExp(`h[1-${id?.depth ?? 1}]`)));
body.children = [...body.children].splice(startIdx + (tag ? 1 : 0), (nbr === -1 ? body.children.length : nbr) - (startIdx + (tag ? 1 : 0)));
}
else if (result._type == 'canvas') {
body = body as CanvasContent;
const nodes = body?.groups?.find(e => "#" + sluggify(e.name) === anchor)?.nodes;
body.nodes = body.nodes.filter(e => nodes?.includes(e.id));
body.edges = body.edges.filter(e => nodes?.includes(e.fromNode) && nodes?.includes(e.toNode));
}
}
content.value = JSON.parse(JSON.stringify({ ...result, body: body }));
}
const link = (props.href.startsWith('/') ? '' : '/') + (props.href.includes('#') ? props.href.substring(0, props.href.indexOf('#')) : props.href).replace(/\..*$/, '').replace("/index", '');
const anchor = props.href.includes('#') ? props.href.substring(props.href.indexOf('#'), props.href.length) : '';
let content = ref<ParsedContentExtended>(), loading = ref(true);
let content = ref<ParsedContentExtended | null | undefined>(null), loading = ref(false), isTag = ref(false);
if(props.href !== '')
function loadContent()
{
queryContent().where({ _path: new RegExp("/" + sluggify(link) + '$', 'i') }).findOne().then((result: ParsedContentExtended) => {
content.value = result;
loading.value = false;
let body = result.body;
loading.value = true;
if(props.href !== '' && !props.href.startsWith('/tags#'))
{
queryContent().where({ _path: new RegExp("/" + sluggify(link) + '$', 'i') }).findOne().then(handleResult).catch(() => {
loading.value = false;
content.value = undefined;
});
}
else
{
isTag.value = true;
if (anchor && result && body) {
if (result._type == 'markdown' && (body as MarkdownRoot).children) {
body = body as MarkdownRoot;
const id = flatten(body?.toc?.links ?? []).find(e => "#" + sluggify(e.id) === anchor);
const tag = `h${id?.depth ?? 0}`;
const startIdx = body.children.findIndex(e => e.tag === tag && e?.props?.id === id?.id) ?? 0;
const nbr = body.children.findIndex((e, i) => i > startIdx && e.tag?.match(new RegExp(`h[1-${id?.depth ?? 1}]`)));
body.children = body.children.splice(startIdx, (nbr === -1 ? body.children.length : nbr) - startIdx);
}
else if (result._type == 'canvas') {
body = body as CanvasContent;
const nodes = body?.groups?.find(e => "#" + sluggify(e.name) === anchor)?.nodes;
body.nodes = body.nodes.filter(e => nodes?.includes(e.id));
body.edges = body.edges.filter(e => nodes?.includes(e.fromNode) && nodes?.includes(e.toNode));
}
if(tags.value)
handleResult(tags.value, true);
else
{
loading.value = false;
content.value = undefined;
}
}).catch(() => {
loading.value = false;
});
}
}
const hovered = ref(false), pos = ref<any>();
@@ -81,10 +101,13 @@ function showPreview(e: Event, bbox: boolean) {
if(rect.right + 550 < window.innerWidth)
r.left = rect.left + "px";
else
r.right = (window.innerWidth - rect.left + 4) + "px";
r.right = (window.innerWidth - rect.right + 4) + "px";
pos.value = r;
}
hovered.value = true;
if(content.value === null)
loadContent();
}
function hidePreview(e: Event) {
timeout = setTimeout(() => hovered.value = false, 300);
@@ -93,17 +116,17 @@ function hidePreview(e: Event) {
<template >
<template v-if="href !== ''">
<NuxtLink custom no-prefetch v-slot="{ href: hrefSlot, navigate }" :href="{ path: content?._path ?? link, hash: anchor }" :target="target">
<a :href="hrefSlot" @click="navigate" @mouseenter="(e) => showPreview(e, true)" @mouseleave="hidePreview" v-bind="$attrs"><slot ></slot></a>
<NuxtLink custom no-prefetch v-slot="{ href: hrefSlot, navigate }" :href="isTag ? undefined : { path: content?._path ?? link, hash: anchor }" :target="target">
<a :href="hrefSlot" @click="(isTag ? (e: Event) => e.preventDefault() : navigate)" @mouseenter="(e) => showPreview(e, true)" @mouseleave="hidePreview" v-bind="$attrs"><slot ></slot></a>
</NuxtLink>
<Teleport to="body" v-if="hovered && (loading || !!content)">
<div class="popover hover-popover is-loaded" :style="pos" @mouseenter="(e) => showPreview(e, false)" @mouseleave="hidePreview">
<template v-if="!!content">
<div class="markdown-embed" v-if="content._type == 'markdown' && ((content as ParsedContent)?.body?.children?.length ?? 0) > 0">
<div class="markdown-embed" :class="{'tag-embed': isTag}" v-if="content._type == 'markdown' && ((content as ParsedContent)?.body?.children?.length ?? 0) > 0">
<div class="markdown-embed-content">
<div class="markdown-preview-view markdown-rendered node-insert-event hide-title">
<div class="markdown-preview-sizer markdown-preview-section" style="padding-bottom: 0px;">
<h1 v-if="content?.title">{{ content?.title }}</h1>
<h1 v-if="content?.title && !isTag">{{ content?.title }}</h1>
<ContentRenderer :key="content._id" :value="content"/>
</div>
</div>
@@ -116,12 +139,14 @@ function hidePreview(e: Event) {
<div class="not-found-container">
<div class="not-found-image"></div>
<div class="not-found-title">Impossible de prévisualiser</div>
<div class="not-found-description">Cliquez sur le lien pour accéder au contenu</div>
<div v-if="!isTag" class="not-found-description">Cliquez sur le lien pour accéder au contenu</div>
</div>
</div>
</template>
<div v-else>
<div v-else class="preload" style="text-align:center">
<svg style="width:50px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<path style="transform-origin:50px 50px;animation:1s linear infinite rotate" fill="currentColor" d="M73,50c0-12.7-10.3-23-23-23S27,37.3,27,50 M30.9,50c0-10.5,8.5-19.1,19.1-19.1S69.1,39.5,69.1,50"/>
</svg>
</div>
</div>
</Teleport>