mirror of
https://github.com/directus/directus.git
synced 2026-04-25 03:00:53 -04:00
Transpile docs to vue components at build time (#8743)
This commit is contained in:
committed by
GitHub
parent
3712892e79
commit
2908063d86
@@ -1,608 +0,0 @@
|
||||
<template>
|
||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
<div class="md" :class="pageClass" @click="onClick" v-html="html" />
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, onMounted, onUpdated, inject } from 'vue';
|
||||
|
||||
import MarkdownIt from 'markdown-it';
|
||||
import markdownItTableOfContents from 'markdown-it-table-of-contents';
|
||||
import markdownItAnchor from 'markdown-it-anchor';
|
||||
import markdownItContainer from 'markdown-it-container';
|
||||
import fm from 'front-matter';
|
||||
|
||||
import hljs from 'highlight.js';
|
||||
import hljsGraphQL from '@/utils/hljs-graphql';
|
||||
|
||||
import { getRootPath } from '@/utils/get-root-path';
|
||||
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
hljs.registerLanguage('graphql', hljsGraphQL);
|
||||
|
||||
const md = new MarkdownIt({
|
||||
html: true,
|
||||
highlight(str, lang) {
|
||||
if (lang && hljs.getLanguage(lang)) {
|
||||
try {
|
||||
return hljs.highlight(str, { language: lang }).value;
|
||||
} catch (err: any) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn('There was an error highlighting in Markdown');
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
});
|
||||
|
||||
md.use(markdownItTableOfContents, { includeLevel: [2] });
|
||||
md.use(markdownItAnchor, { permalink: true, permalinkSymbol: '#' });
|
||||
|
||||
function hintRenderer(type: string) {
|
||||
return (tokens: any[], idx: number) => {
|
||||
const token = tokens[idx];
|
||||
let title = token.info.trim().slice(type.length).trim() || '';
|
||||
|
||||
if (title) title = `<div class="hint-title">${title}</div>`;
|
||||
|
||||
if (token.nesting === 1) {
|
||||
return `<div class="${type} hint">${title}\n`;
|
||||
} else {
|
||||
return '</div>\n';
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
md.use(markdownItContainer, 'tip', { render: hintRenderer('tip') });
|
||||
md.use(markdownItContainer, 'warning', { render: hintRenderer('warning') });
|
||||
md.use(markdownItContainer, 'danger', { render: hintRenderer('danger') });
|
||||
|
||||
export default defineComponent({
|
||||
setup(props, { slots }) {
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
||||
const html = ref('');
|
||||
const pageClass = ref<string>();
|
||||
|
||||
onMounted(generateHTML);
|
||||
onUpdated(generateHTML);
|
||||
|
||||
return { html, onClick, pageClass };
|
||||
|
||||
function generateHTML() {
|
||||
const source = slots.default?.()[0].children;
|
||||
|
||||
if (!source || typeof source !== 'string') {
|
||||
html.value = '';
|
||||
return;
|
||||
}
|
||||
|
||||
const { attributes, body } = fm<{ pageClass?: string }>(source);
|
||||
|
||||
let markdown = body;
|
||||
|
||||
const rawImages = body.matchAll(/!\[[^\]]*\]\((?<filename>.*?)(?="|\))(?<optionalpart>".*")?\)/g) ?? [];
|
||||
const rootPath = getRootPath();
|
||||
|
||||
for (const rawImage of rawImages) {
|
||||
const filenameParts = rawImage.groups!.filename.split('/');
|
||||
|
||||
while (filenameParts.includes('assets')) {
|
||||
filenameParts.shift();
|
||||
}
|
||||
|
||||
const newFilename = `${rootPath}admin/img/docs/${filenameParts.join('/')}`;
|
||||
const newImage = rawImage[0].replace(rawImage.groups!.filename, newFilename);
|
||||
markdown = markdown.replace(rawImage[0], newImage);
|
||||
}
|
||||
|
||||
pageClass.value = attributes?.pageClass;
|
||||
|
||||
const htmlString = md.render(markdown);
|
||||
|
||||
html.value = htmlString;
|
||||
|
||||
// The Markdown is fetched async on page transition, which means the # link already exists before the markdown does
|
||||
// This will force the main el to scroll down to the targetted element on updates of the content
|
||||
const mainElement = inject('main-element', ref<Element | null>(null));
|
||||
|
||||
if (route.hash) {
|
||||
const linkedEl = document.querySelector(route.hash) as HTMLElement;
|
||||
|
||||
if (linkedEl) {
|
||||
mainElement.value?.scrollTo({ top: linkedEl.offsetTop - 100 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onClick(event: MouseEvent) {
|
||||
if (
|
||||
event.target &&
|
||||
(event.target as HTMLElement).tagName.toLowerCase() === 'a' &&
|
||||
(event.target as HTMLAnchorElement).href
|
||||
) {
|
||||
const link = (event.target as HTMLAnchorElement).getAttribute('href')!;
|
||||
|
||||
if (link.startsWith('http') || link.startsWith('#')) return;
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
const parts = link.split('#');
|
||||
|
||||
parts[0] = parts[0].endsWith('/') ? parts[0].slice(0, -1) : parts[0];
|
||||
|
||||
router.push({
|
||||
path: `/docs${parts[0]}`,
|
||||
hash: `#${parts[1]}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.error {
|
||||
padding: 20vh 0;
|
||||
}
|
||||
|
||||
.md {
|
||||
max-width: 740px;
|
||||
color: var(--foreground-normal-alt);
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
line-height: 27px;
|
||||
}
|
||||
|
||||
.md > :deep(*:first-child) {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.md > :deep(*:last-child) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.md :deep(a) {
|
||||
color: var(--primary-110);
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.md :deep(h1),
|
||||
.md :deep(h2),
|
||||
.md :deep(h3),
|
||||
.md :deep(h4),
|
||||
.md :deep(h5),
|
||||
.md :deep(h6) {
|
||||
position: relative;
|
||||
margin: 40px 0 8px;
|
||||
padding: 0;
|
||||
color: var(--foreground-normal-alt);
|
||||
font-weight: 700;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.md :deep(h1 a),
|
||||
.md :deep(h2 a),
|
||||
.md :deep(h3 a),
|
||||
.md :deep(h4 a),
|
||||
.md :deep(h5 a),
|
||||
.md :deep(h6 a) {
|
||||
position: absolute;
|
||||
right: 100%;
|
||||
padding-right: 4px;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.md :deep(h1) {
|
||||
margin-bottom: 40px;
|
||||
font-size: 35px;
|
||||
line-height: 44px;
|
||||
}
|
||||
|
||||
.md :deep(h2) {
|
||||
margin-top: 60px;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 4px;
|
||||
font-size: 24px;
|
||||
line-height: 34px;
|
||||
border-bottom: 2px solid var(--border-subdued);
|
||||
}
|
||||
|
||||
.md :deep(h3) {
|
||||
margin-bottom: 0px;
|
||||
font-size: 19px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.md :deep(h4) {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.md :deep(h5) {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.md :deep(h6) {
|
||||
color: var(--foreground-normal);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.md :deep(pre) {
|
||||
padding: 16px 20px;
|
||||
overflow: auto;
|
||||
font-size: 13px;
|
||||
line-height: 24px;
|
||||
background-color: var(--background-normal);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.md :deep(code),
|
||||
.md :deep(tt) {
|
||||
margin: 0 1px;
|
||||
padding: 0 4px;
|
||||
font-size: 15px;
|
||||
font-family: var(--family-monospace);
|
||||
white-space: nowrap;
|
||||
background-color: var(--background-page);
|
||||
border: 1px solid var(--background-normal);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.md :deep(pre code) {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
white-space: pre;
|
||||
background: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.md :deep(p) {
|
||||
margin-block-start: 1em;
|
||||
margin-block-end: 1em;
|
||||
margin-inline-start: 0px;
|
||||
margin-inline-end: 0px;
|
||||
}
|
||||
|
||||
.md :deep(h3 + p) {
|
||||
margin-block-start: 0.5em;
|
||||
}
|
||||
|
||||
.md > :deep(h2:first-child) {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.md > :deep(h1:first-child) {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.md > :deep(h3:first-child),
|
||||
.md > :deep(h4:first-child),
|
||||
.md > :deep(h5:first-child),
|
||||
.md > :deep(h6:first-child) {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.md :deep(blockquote) {
|
||||
max-width: 740px;
|
||||
margin-bottom: 4rem;
|
||||
padding: 0.25rem 0 0.25rem 1rem;
|
||||
color: var(--foreground-subdued);
|
||||
font-size: 18px;
|
||||
border-left: 2px solid var(--background-normal);
|
||||
}
|
||||
|
||||
.md :deep(blockquote > :first-child) {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.md :deep(blockquote > :last-child) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.md :deep(table) {
|
||||
min-width: 100%;
|
||||
margin: 40px 0;
|
||||
padding: 0;
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
.md :deep(img) {
|
||||
max-width: 100%;
|
||||
margin: 20px 0;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.md :deep(table img) {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.md :deep(table tr) {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border-top: 1px solid var(--border-normal);
|
||||
}
|
||||
|
||||
.md :deep(table tr:nth-child(2n)) {
|
||||
background-color: var(--background-page);
|
||||
}
|
||||
|
||||
.md :deep(table tr th) {
|
||||
margin: 0;
|
||||
padding: 8px 20px;
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
border: 1px solid var(--border-normal);
|
||||
}
|
||||
|
||||
.md :deep(table tr td) {
|
||||
margin: 0;
|
||||
padding: 8px 20px;
|
||||
text-align: left;
|
||||
border: 1px solid var(--border-normal);
|
||||
}
|
||||
|
||||
.md :deep(a:first-child h1),
|
||||
.md :deep(a:first-child h2),
|
||||
.md :deep(a:first-child h3),
|
||||
.md :deep(a:first-child h4),
|
||||
.md :deep(a:first-child h5),
|
||||
.md :deep(a:first-child h6) {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.md :deep(table tr th :first-child),
|
||||
.md :deep(table tr td :first-child) {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.md :deep(table tr th :last-child),
|
||||
.md :deep(table tr td :last-child) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.md :deep(h1 a:hover),
|
||||
.md :deep(h2 a:hover),
|
||||
.md :deep(h3 a:hover),
|
||||
.md :deep(h4 a:hover),
|
||||
.md :deep(h5 a:hover),
|
||||
.md :deep(h6 a:hover) {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.md :deep(h1:hover a),
|
||||
.md :deep(h2:hover a),
|
||||
.md :deep(h3:hover a),
|
||||
.md :deep(h4:hover a),
|
||||
.md :deep(h5:hover a),
|
||||
.md :deep(h6:hover a) {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.md :deep(pre code),
|
||||
.md :deep(pre tt) {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.md :deep(h1 tt),
|
||||
.md :deep(h1 code),
|
||||
.md :deep(h2 tt),
|
||||
.md :deep(h2 code),
|
||||
.md :deep(h3 tt),
|
||||
.md :deep(h3 code),
|
||||
.md :deep(h4 tt),
|
||||
.md :deep(h4 code),
|
||||
.md :deep(h5 tt),
|
||||
.md :deep(h5 code),
|
||||
.md :deep(h6 tt),
|
||||
.md :deep(h6 code) {
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
.md :deep(h1 p),
|
||||
.md :deep(h2 p),
|
||||
.md :deep(h3 p),
|
||||
.md :deep(h4 p),
|
||||
.md :deep(h5 p),
|
||||
.md :deep(h6 p) {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.md :deep(ul),
|
||||
.md :deep(ol) {
|
||||
margin: 20px 0;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.md :deep(ul li),
|
||||
.md :deep(ol li) {
|
||||
margin: 8px 0;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.md :deep(ul ul),
|
||||
.md :deep(ul ol),
|
||||
.md :deep(ol ul),
|
||||
.md :deep(ol ol) {
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.md :deep(ul ul li),
|
||||
.md :deep(ul ol li),
|
||||
.md :deep(ol ul li),
|
||||
.md :deep(ol ol li) {
|
||||
margin: 4px 0;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.md :deep(img.no-margin) {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.md :deep(img.full) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.md :deep(img.shadow) {
|
||||
box-shadow: 0px 5px 10px 0px rgba(23, 41, 64, 0.1), 0px 2px 40px 0px rgba(23, 41, 64, 0.05);
|
||||
}
|
||||
|
||||
.md.page-reference {
|
||||
max-width: 1200px;
|
||||
}
|
||||
|
||||
.md.page-reference :deep(hr) {
|
||||
position: relative;
|
||||
left: -2.5rem;
|
||||
width: calc(100% + 5rem);
|
||||
margin: 3rem 0;
|
||||
}
|
||||
|
||||
.md.page-reference :deep(h2) {
|
||||
margin-top: 3rem;
|
||||
font-size: 2rem;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.md.page-reference :deep(h3) {
|
||||
margin-top: 3rem;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.md.page-reference :deep(h4) {
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.md :deep(.heading-link) {
|
||||
color: var(--foreground-subdued);
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.md :deep(.heading-link:hover) {
|
||||
color: var(--primary-110);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.md :deep(li p.first) {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.md :deep(.table-of-contents ul),
|
||||
.md :deep(.table-of-contents ol) {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.md :deep(.table-of-contents ul li),
|
||||
.md :deep(.table-of-contents ol li) {
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.md :deep(.hint) {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
margin: 20px 0;
|
||||
padding: 0 20px;
|
||||
background-color: var(--background-subdued);
|
||||
border-left: 2px solid var(--primary);
|
||||
}
|
||||
|
||||
.md :deep(.two-up) {
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
.md :deep(.table-of-contents) {
|
||||
margin-top: -20px;
|
||||
}
|
||||
|
||||
.md :deep(.hint-title) {
|
||||
margin-block-start: 1em;
|
||||
margin-block-end: 1em;
|
||||
margin-inline-start: 0px;
|
||||
margin-inline-end: 0px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.md :deep(.hint.tip) {
|
||||
border-left: 2px solid var(--primary);
|
||||
}
|
||||
|
||||
.md :deep(.hint.warning) {
|
||||
background-color: var(--warning-10);
|
||||
border-left: 2px solid var(--warning);
|
||||
}
|
||||
|
||||
.md :deep(.hint.danger) {
|
||||
background-color: var(--danger-10);
|
||||
border-left: 2px solid var(--danger);
|
||||
}
|
||||
|
||||
.md :deep(.two-up .right) {
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
.md :deep(.two-up .right h5) {
|
||||
margin-top: 20px;
|
||||
color: var(--foreground-subdued);
|
||||
}
|
||||
|
||||
.md.page-reference :deep(.definitions) {
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.5rem;
|
||||
}
|
||||
|
||||
.md.page-reference :deep(.definitions > p) {
|
||||
margin: 0;
|
||||
padding: 0.8rem 0;
|
||||
border-bottom: 2px solid var(--border-subdued);
|
||||
}
|
||||
|
||||
.md.page-reference :deep(.definitions > p:first-child) {
|
||||
border-top: 2px solid var(--border-subdued);
|
||||
}
|
||||
|
||||
.md.page-reference :deep(.definitions > p > code:first-child) {
|
||||
margin-right: 0.2rem;
|
||||
padding: 0;
|
||||
font-weight: 700;
|
||||
font-size: 0.9rem;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.md.page-reference :deep(.definitions > p > strong) {
|
||||
color: var(--foreground-subdued);
|
||||
}
|
||||
|
||||
@media (min-width: 1000px) {
|
||||
.md :deep(.two-up) {
|
||||
display: grid;
|
||||
grid-gap: 40px;
|
||||
grid-template-columns: minmax(0, 4fr) minmax(0, 3fr);
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.md :deep(.two-up .right) {
|
||||
position: sticky;
|
||||
top: 100px;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.md :deep(.two-up .left > *:first-child),
|
||||
.md :deep(.two-up .right > *:first-child) {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -11,9 +11,15 @@ export default defineModule({
|
||||
routes: [
|
||||
{
|
||||
path: '',
|
||||
redirect: '/docs/getting-started/introduction/',
|
||||
component: StaticDocs,
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
redirect: '/docs/getting-started/introduction/',
|
||||
},
|
||||
...getRoutes(docs),
|
||||
],
|
||||
},
|
||||
...getRoutes(docs),
|
||||
{
|
||||
path: ':_(.+)+',
|
||||
component: NotFound,
|
||||
@@ -29,15 +35,12 @@ function getRoutes(routes: DocsRoutes): RouteRecordRaw[] {
|
||||
updatedRoutes.push({
|
||||
name: `docs-${route.path.replace('/', '-')}`,
|
||||
path: route.path,
|
||||
component: StaticDocs,
|
||||
meta: {
|
||||
import: route.import,
|
||||
},
|
||||
component: route.import,
|
||||
});
|
||||
} else {
|
||||
updatedRoutes.push({
|
||||
path: route.path,
|
||||
redirect: `/docs${route.children[0].path}`,
|
||||
redirect: `/docs/${route.children[0].path}`,
|
||||
});
|
||||
|
||||
updatedRoutes.push(...getRoutes(route.children));
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
</template>
|
||||
|
||||
<div class="docs-content selectable">
|
||||
<markdown>{{ markdownWithoutTitle }}</markdown>
|
||||
<router-view @update:title="title = $event" @update:modular-extension="modularExtension = $event" />
|
||||
</div>
|
||||
|
||||
<template #sidebar>
|
||||
@@ -29,65 +29,22 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { defineComponent, defineAsyncComponent, ref, computed, watch } from 'vue';
|
||||
import { useRoute, RouteLocation } from 'vue-router';
|
||||
import { defineComponent, ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import DocsNavigation from '../components/navigation.vue';
|
||||
|
||||
const Markdown = defineAsyncComponent(() => import('../components/markdown.vue'));
|
||||
|
||||
async function getMarkdownForRoute(route: RouteLocation): Promise<string> {
|
||||
const importDocs = route.meta.import as () => Promise<{ default: string }>;
|
||||
|
||||
const mdModule = await importDocs();
|
||||
return mdModule.default;
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: 'StaticDocs',
|
||||
components: { DocsNavigation, Markdown },
|
||||
components: { DocsNavigation },
|
||||
setup() {
|
||||
const { t } = useI18n();
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const markdown = ref('');
|
||||
const title = computed(() => {
|
||||
const lines = markdown.value.split('\n');
|
||||
const line = lines.find((line) => line.startsWith('# '));
|
||||
const title = ref('Test');
|
||||
const modularExtension = ref(false);
|
||||
|
||||
if (line === undefined) return null;
|
||||
|
||||
return line.substring(2).replaceAll('<small></small>', '').trim();
|
||||
});
|
||||
|
||||
const modularExtension = computed(() => {
|
||||
const lines = markdown.value.split('\n');
|
||||
const line = lines.find((line) => line.startsWith('# '));
|
||||
return line?.includes('<small></small>') || false;
|
||||
});
|
||||
|
||||
const markdownWithoutTitle = computed(() => {
|
||||
const lines = markdown.value.split('\n');
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
if (lines[i].startsWith('# ')) {
|
||||
lines.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return lines.join('\n');
|
||||
});
|
||||
|
||||
watch(
|
||||
() => route.path,
|
||||
async () => {
|
||||
markdown.value = await getMarkdownForRoute(route);
|
||||
},
|
||||
{ immediate: true, flush: 'post' }
|
||||
);
|
||||
|
||||
return { t, route, markdown, title, markdownWithoutTitle, modularExtension };
|
||||
return { t, route, title, modularExtension };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user