Search, link preview and starting tag page
This commit is contained in:
parent
e70ab97b8b
commit
08c3a93893
|
|
@ -23,7 +23,7 @@ const results = computed(() => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div class="search-view-outer" ref="">
|
||||
<div class="search-view-outer">
|
||||
<div class="search-view-container">
|
||||
<span class="published-search-icon"></span>
|
||||
<input class="search-bar" type="text" placeholder="Recherche" v-model="input" @input="getPos">
|
||||
|
|
@ -31,7 +31,7 @@ const results = computed(() => {
|
|||
</div>
|
||||
<Teleport to="body" v-if="input !== ''">
|
||||
<div class="search-results" :style="{top: (pos.bottom + 4) + 'px', left: pos.left + 'px'}">
|
||||
<div class="suggestion-item" v-if="results.length > 0" v-for="result of results">
|
||||
<div class="suggestion-item" v-if="results.length > 0" v-for="result of results" :key="result._path" @mouseenter="(e) => (e.target as HTMLElement).classList.add('is-selected')" @mouseleave="(e) => (e.target as HTMLElement).classList.remove('is-selected')" @mousedown="navigateTo(result._path); input = ''">
|
||||
<div class="suggestion-content">
|
||||
<div class="suggestion-title">
|
||||
{{ result.title.substring(0, clear(result.title).indexOf(clear(input))) }}<span class="suggestion-highlight">{{ result.title.substring(clear(result.title).indexOf(clear(input)), clear(result.title).indexOf(clear(input)) + clear(input).length + 1) }}</span>{{ result.title.substring(clear(result.title).indexOf(clear(input)) + clear(input).length + 1) }}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
import type { ContentNavigation } from '#build/components';
|
||||
<script setup lang="ts">
|
||||
import type { ParsedContent } from '@nuxt/content/dist/runtime/types';
|
||||
|
||||
const props = defineProps({
|
||||
href: {
|
||||
type: String,
|
||||
|
|
@ -21,19 +21,63 @@ function sluggify(s: string): string {
|
|||
.join("/") // always use / as sep
|
||||
.replace(/\/$/, "")
|
||||
}
|
||||
function flatten(val: TocLink[]): TocLink[] {
|
||||
return val.flatMap ? val?.flatMap((e: TocLink) => e.children ? [e, ...flatten(e.children)] : e) : val;
|
||||
}
|
||||
|
||||
const href = (props.href.includes('#') ? props.href.substring(0, props.href.indexOf('#')) : props.href).replace(/\..*$/, '');
|
||||
const link = (props.href.includes('#') ? props.href.substring(0, props.href.indexOf('#')) : props.href).replace(/\..*$/, '');
|
||||
const anchor = props.href.includes('#') ? props.href.substring(props.href.indexOf('#'), props.href.length) : '';
|
||||
let content: any;
|
||||
let content: ParsedContent;
|
||||
try {
|
||||
content = await queryContent().where({ _path: new RegExp(sluggify(href) + '$', 'i') }).findOne();
|
||||
} catch(e) {
|
||||
content = await queryContent().where({ _path: new RegExp(sluggify(link) + '$', 'i') }).findOne();
|
||||
if(anchor && !!content && content._type == 'markdown' && content.body && content.body.children)
|
||||
{
|
||||
const id = flatten(content.body.toc?.links).find(e => "#" + sluggify(e.id) === anchor);
|
||||
const tag = `h${id?.depth ?? 0}`;
|
||||
|
||||
const startIdx = content.body.children.findIndex(e => e.tag === tag && e?.props?.id === id?.id) ?? 0;
|
||||
const nbr = content.body.children.findIndex((e, i) => i > startIdx && e.tag?.match(new RegExp(`h[1-${id?.depth ?? 1}]`))) ?? content.body.children.length;
|
||||
|
||||
content.body.children = content.body.children.splice(startIdx, nbr - startIdx);
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
const hovered = ref(false), pos = ref<DOMRect>();
|
||||
let timeout: NodeJS.Timeout;
|
||||
function showPreview(e: Event, bbox: boolean) {
|
||||
clearTimeout(timeout);
|
||||
!!bbox && (pos.value = (e.currentTarget as HTMLElement)?.getBoundingClientRect());
|
||||
hovered.value = true;
|
||||
}
|
||||
function hidePreview(e: Event) {
|
||||
timeout = setTimeout(() => hovered.value = false, 300);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template >
|
||||
<NuxtLink :href="(content?._path ?? href + anchor) ?? href" :target="target">
|
||||
<slot />
|
||||
<NuxtLink custom no-prefetch v-slot="{ href: hrefSlot, navigate }" :to="(content?._path ?? href + anchor) ?? href" :target="target">
|
||||
<a :href="hrefSlot" @click="navigate" @mouseenter="(e) => showPreview(e, true)" @mouseleave="hidePreview" v-bind="$attrs"><slot ></slot></a>
|
||||
</NuxtLink>
|
||||
<Teleport to="body" v-if="hovered && !!content">
|
||||
<div class="popover hover-popover is-loaded" :style="{ top: (pos.bottom + 4) + 'px', left: pos.left + 'px' }" @mouseenter="(e) => showPreview(e, false)" @mouseleave="hidePreview">
|
||||
<div class="markdown-embed" v-if="content._type == 'markdown'">
|
||||
<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>
|
||||
<ContentRenderer :key="content._id" :value="content"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<CanvasRenderer v-else-if="content._type == 'canvas'" :key="content._id" :canvas="content" />
|
||||
<div v-else>
|
||||
<div class="not-found-container">
|
||||
<div class="not-found-image"></div>
|
||||
<div class="not-found-title">Impossible d'afficher</div>
|
||||
<div class="not-found-description">Cette page est actuellement vide et impossible à traiter</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<template>
|
||||
<h1 :id="id"><slot></slot></h1>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{ id?: string }>()
|
||||
</script>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<template>
|
||||
<h2 :id="id"><slot></slot></h2>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{ id?: string }>()
|
||||
</script>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<template>
|
||||
<h3 :id="id"><slot></slot></h3>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{ id?: string }>()
|
||||
</script>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<template>
|
||||
<h4 :id="id"><slot></slot></h4>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{ id?: string }>()
|
||||
</script>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<template>
|
||||
<h5 :id="id"><slot></slot></h5>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{ id?: string }>()
|
||||
</script>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<template>
|
||||
<h6 :id="id"><slot></slot></h6>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{ id?: string }>()
|
||||
</script>
|
||||
|
|
@ -5,13 +5,10 @@ export default defineNuxtConfig({
|
|||
modules: [CanvasModule, "@nuxt/content", "@nuxtjs/color-mode"],
|
||||
css: ['~/assets/global.css'],
|
||||
content: {
|
||||
experimental: {
|
||||
search: true
|
||||
},
|
||||
documentDriven: {
|
||||
injectPage: true,
|
||||
},
|
||||
contentHead: false,
|
||||
contentHead: true,
|
||||
markdown: {
|
||||
toc: { depth: 3, searchDepth: 3 },
|
||||
remarkPlugins: [
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
<script setup lang="ts">
|
||||
const query = await queryContent().where({
|
||||
tags: { $exists: true }
|
||||
}).find();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
<div v-for="article in query" :key="article._path">
|
||||
<h2>{{ article.title }}</h2>
|
||||
<p>{{ article.description }}</p>
|
||||
</div>
|
||||
</template>
|
||||
Loading…
Reference in New Issue