62 lines
2.1 KiB
Vue

<script setup lang="ts">
import { useDebounce, useLocalStorage } from '@vueuse/core';
import marked from 'marked';
import { extractMetadata } from '#shared/blog/metadata.ts';
import type { Post } from '#shared/blog/metadata.ts';
import { PermissionAreas } from '#shared/helpers.ts';
import parseMarkdown from '#shared/parseMarkdown.ts';
import type { MarkdownInfo } from '#shared/parseMarkdown.ts';
const content = useLocalStorage(
'admin/blog/editor',
'# title\n<small>YYYY-MM-DD | author</small>\n\n![alt text for image](/img/{locale}/blog/slug.png)\n\ncontent',
{ initOnMounted: true },
);
const debouncedContent = useDebounce(content, 500, { maxWait: 5_000 });
const post = ref<Post | undefined>();
const parsed = ref<MarkdownInfo | undefined>();
const { $translator: translator } = useNuxtApp();
const config = useConfig();
watch(debouncedContent, async () => {
const metadata = extractMetadata(config, debouncedContent.value);
post.value = metadata ? { slug: 'slug', ...metadata } : undefined;
const markdown = marked(debouncedContent.value);
parsed.value = await parseMarkdown(markdown, translator);
});
const { data: moderation } = await useFetch('/api/admin/moderation', { pick: ['blog'] });
</script>
<template>
<Page>
<NotFound v-if="!$isGranted(PermissionAreas.Panel)" />
<template v-else>
<p>
<nuxt-link to="/admin">
<Icon v="user-cog" />
<T>admin.header</T>
</nuxt-link>
</p>
<h2>
<Icon v="pen-nib" />
Blog editor
</h2>
<div v-html="moderation?.blog"></div>
<textarea v-model="content" class="form-control" rows="10"></textarea>
<template v-if="post">
<hr>
<BlogEntry class="col-12 col-sm-6 col-md-4" :post details />
</template>
<hr>
<div class="blog-post">
<Spelling v-if="parsed?.content" :text="parsed.content" />
</div>
</template>
</Page>
</template>