Raw blog finished

This commit is contained in:
Andrew Illarionov 2024-02-20 21:15:29 +03:00
parent 44c60f7069
commit eadc0b119d
18 changed files with 356 additions and 200 deletions

View File

@ -1 +1 @@
[{"D:\\Software\\Development\\Websites\\enderman.ch\\index\\assets\\styles\\transitions.scss":"1","D:\\Software\\Development\\Websites\\enderman.ch\\index\\app.vue":"2","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\EMail.vue":"3","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\about.vue":"4","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\index.vue":"5","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\projects.vue":"6","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\social.vue":"7","D:\\Software\\Development\\Websites\\enderman.ch\\index\\layouts\\Card.vue":"8","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\Options.vue":"9","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\Flooter.vue":"10","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\SwipeControls.vue":"11","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\Logo.vue":"12","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\Route.vue":"13","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\animations\\Portal.vue":"14","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\ui\\Icon.vue":"15","D:\\Software\\Development\\Websites\\enderman.ch\\index\\assets\\styles\\vuetify.scss":"16","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\[...slug].vue":"17","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\blog\\index.vue":"18","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\blog\\[slug].vue":"19","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\content\\Card.vue":"20"},{"size":165,"mtime":1700688268778,"hashOfConfig":"21"},{"size":1550,"mtime":1700850776284,"hashOfConfig":"21"},{"size":804,"mtime":1700688952880,"hashOfConfig":"21"},{"size":2135,"mtime":1700689265787,"hashOfConfig":"21"},{"size":3117,"mtime":1700689271383,"hashOfConfig":"21"},{"size":2304,"mtime":1700689265769,"hashOfConfig":"21"},{"size":3232,"mtime":1700689265781,"hashOfConfig":"21"},{"size":1623,"mtime":1700748530633,"hashOfConfig":"21"},{"size":3065,"mtime":1708262194629,"hashOfConfig":"22"},{"size":1132,"mtime":1708254584095,"hashOfConfig":"22"},{"size":1269,"mtime":1708255068679,"hashOfConfig":"22"},{"size":1147,"mtime":1708248797872,"hashOfConfig":"22"},{"size":979,"mtime":1706003786966,"hashOfConfig":"22"},{"size":16968,"mtime":1708180277353,"hashOfConfig":"22"},{"size":935,"mtime":1706445231843,"hashOfConfig":"22"},{"size":120,"mtime":1706789613657,"hashOfConfig":"23"},{"size":1988,"mtime":1708191547889,"hashOfConfig":"22"},{"size":2560,"mtime":1708202402381,"hashOfConfig":"22"},{"size":983,"mtime":1708206997656,"hashOfConfig":"22"},{"size":1912,"mtime":1708290866348,"hashOfConfig":"22"},"5tgxr3","1nljphs","1lk8nat"] [{"D:\\Software\\Development\\Websites\\enderman.ch\\index\\assets\\styles\\transitions.scss":"1","D:\\Software\\Development\\Websites\\enderman.ch\\index\\app.vue":"2","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\EMail.vue":"3","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\about.vue":"4","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\index.vue":"5","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\projects.vue":"6","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\social.vue":"7","D:\\Software\\Development\\Websites\\enderman.ch\\index\\layouts\\Card.vue":"8","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\Options.vue":"9","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\Flooter.vue":"10","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\SwipeControls.vue":"11","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\Logo.vue":"12","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\Route.vue":"13","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\animations\\Portal.vue":"14","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\ui\\Icon.vue":"15","D:\\Software\\Development\\Websites\\enderman.ch\\index\\assets\\styles\\vuetify.scss":"16","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\[...slug].vue":"17","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\blog\\index.vue":"18","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\blog\\[slug].vue":"19","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\content\\Card.vue":"20","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\content\\OgImage.vue":"21","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\animations\\NotFound.vue":"22"},{"size":165,"mtime":1700688268778,"hashOfConfig":"23"},{"size":1550,"mtime":1700850776284,"hashOfConfig":"23"},{"size":804,"mtime":1700688952880,"hashOfConfig":"23"},{"size":2135,"mtime":1700689265787,"hashOfConfig":"23"},{"size":3117,"mtime":1700689271383,"hashOfConfig":"23"},{"size":2304,"mtime":1700689265769,"hashOfConfig":"23"},{"size":3232,"mtime":1700689265781,"hashOfConfig":"23"},{"size":1623,"mtime":1700748530633,"hashOfConfig":"23"},{"size":3065,"mtime":1708262194629,"hashOfConfig":"24"},{"size":1132,"mtime":1708254584095,"hashOfConfig":"24"},{"size":1269,"mtime":1708255068679,"hashOfConfig":"24"},{"size":1147,"mtime":1708248797872,"hashOfConfig":"24"},{"size":979,"mtime":1706003786966,"hashOfConfig":"24"},{"size":16968,"mtime":1708180277353,"hashOfConfig":"24"},{"size":935,"mtime":1706445231843,"hashOfConfig":"24"},{"size":120,"mtime":1706789613657,"hashOfConfig":"25"},{"size":2084,"mtime":1708424343371,"hashOfConfig":"24"},{"size":2560,"mtime":1708202402381,"hashOfConfig":"24"},{"size":983,"mtime":1708206997656,"hashOfConfig":"24"},{"size":1912,"mtime":1708290866348,"hashOfConfig":"24"},{"size":976,"mtime":1708431988520,"hashOfConfig":"24"},{"size":1645,"mtime":1708450985689,"hashOfConfig":"24"},"5tgxr3","1nljphs","1lk8nat"]

View File

@ -8,9 +8,6 @@ const route = useRoute()
useHead({ useHead({
titleTemplate: (chunk?) => { titleTemplate: (chunk?) => {
if (route.fullPath === '/') return config.title.full if (route.fullPath === '/') return config.title.full
console.log(route.fullPath.split('/'))
if (route.fullPath.split('/').length === 2) if (route.fullPath.split('/').length === 2)
switch (route.fullPath.split('/')[1]) { switch (route.fullPath.split('/')[1]) {
case 'blog': case 'blog':

View File

@ -314,6 +314,11 @@ body {
scroll-snap-type: both mandatory; scroll-snap-type: both mandatory;
scroll-snap-stop: normal; scroll-snap-stop: normal;
&::after {
content: '';
scroll-snap-align: start;
}
&-box { &-box {
position: relative; position: relative;
@ -397,19 +402,18 @@ body {
filter: drop-shadow(1px 2px 3px rgb(0 0 0 / 100%)); filter: drop-shadow(1px 2px 3px rgb(0 0 0 / 100%));
} }
&-share { &-control {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
} }
&-control { &-share {
position: absolute; position: absolute;
top: 0; top: 0;
right: 0; right: 0;
} }
} }

View File

@ -0,0 +1,69 @@
<script setup lang="ts">
const config = useAppConfig()
const meta = {
title: 'Page not found',
description:
'The page you are looking for does not exist. It might have been removed, had its name changed, or is temporarily unavailable.',
image: `${config.url}/images/logo.png`,
url: config.url,
}
let slug = useRoute().params.slug
if (Array.isArray(slug)) slug = slug.join('/')
const error = {
http_code: 200,
title: config.title,
url: config.url + '/' + slug,
locale: config.locale || 'en',
data: {
path: '/error.vue',
content: {
title: 'Page not found!',
description:
"The page you are looking for does not exist. However, no 404 error has occurred, as you're browsing through a web application loaded into memory and HTTP error codes make no sense here.",
},
},
slug: useRoute().params.slug,
build: config.build,
hint: 'Use the navigation bar to get back to the main page.',
}
const errorString = JSON.stringify(error, null, 2)
const buffer = ref('')
const startTime = Date.now()
const dt = 20
let i = 0
function type() {
if (Date.now() > startTime + dt * i) buffer.value += errorString[i++]
if (i < errorString.length) requestAnimationFrame(type)
}
onMounted(() => setTimeout(type, 1500))
</script>
<template>
<section>
<h3 class="alex">Page not found!</h3>
<pre class="pre-wrap">{{ buffer }}<span class="blinker">&#9610;</span></pre>
</section>
</template>
<style scoped lang="scss">
.blinker {
animation: blinker 1s steps(2, start) infinite;
}
@keyframes blinker {
from {
visibility: visible;
}
to {
visibility: hidden;
}
}
</style>

View File

@ -0,0 +1,58 @@
<script setup lang="ts">
import type { PropType } from 'vue'
const props = defineProps({
title: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
logo: {
type: String,
required: true,
},
sectionLogo: {
type: null as unknown as PropType<string | null>,
default: null,
required: false,
},
thumbnail: {
type: String,
required: true,
},
alt: {
type: String,
required: true,
},
})
const sentence = computed(() => {
return props.description.split('.')[0] + '...'
})
</script>
<template>
<div class="w-full h-full flex flex-col justify-end text-white relative">
<img
:src="thumbnail"
:alt="alt"
class="w-full h-full object-cover absolute top-0 left-0"
/>
<div class="absolute top-0 left-0 p-5">
<img :src="logo" alt="Logo" class="w-[100] h-[100]" />
</div>
<div v-if="sectionLogo" class="absolute top-0 right-0 p-5">
<img :src="sectionLogo" alt="Logo" class="w-[100] h-[100]" />
</div>
<div class="mb-5 px-5" style="text-shadow: black 1px 1px 10px">
<h1 class="m-0 text-[60px]">{{ title }}</h1>
<strong class="min-h-[90px] m-0 text-[24px]" style="font-family: Lato">{{
sentence
}}</strong>
</div>
</div>
</template>

View File

@ -1,13 +1,13 @@
--- ---
title: Hello World! title: Hello World!
description: I created this post to test @nuxt/content. description: I created this post to test @nuxt/content.
authors: ['Enderman']
created: 2023-08-12T16:40:09Z created: 2023-08-12T16:40:09Z
updated: 2024-02-18T20:31:54Z updated: 2024-02-18T20:31:54Z
draft: false draft: false
tags: ['hello', 'world'] tags: ['hello', 'world']
thumbnail: '/images/blog/thumbnails/hello.jpg'
--- ---
# Hello! # Hello!
This is an example piece of content This is an example piece of content.

View File

@ -6,11 +6,6 @@ created: 2023-08-13T15:51:19Z
updated: 2024-02-18T21:32:12Z updated: 2024-02-18T21:32:12Z
draft: false draft: false
tags: ['windows', 'context menu', 'customization', 'registry', 'windows tweaks', 'shell', 'shell extensions', 'shell components', 'context menu handlers', 'windows 10', 'windows 11'] tags: ['windows', 'context menu', 'customization', 'registry', 'windows tweaks', 'shell', 'shell extensions', 'shell components', 'context menu handlers', 'windows 10', 'windows 11']
thumbnail: /images/blog/thumbnails/the-windows-context-menu.png
ogImage:
component: BlogImage
props:
image: /images/blog/thumbnails/the-windows-context-menu.png
--- ---
# The Windows context menu is... poorly made. # The Windows context menu is... poorly made.

View File

@ -44,7 +44,7 @@ const swipe = useSwipe(card, {
class="dimensions background h-animated overflow-auto d-flex flex-column gap-3 gap-sm-2 px-4 pt-4 pb-3" class="dimensions background h-animated overflow-auto d-flex flex-column gap-3 gap-sm-2 px-4 pt-4 pb-3"
:class="{ :class="{
'rounded-1-sm': !reader, 'rounded-1-sm': !reader,
'mh-0': reader, 'mh-0 h-100': reader,
}" }"
> >
<Options /> <Options />

View File

@ -1,4 +1,4 @@
export default defineNuxtRouteMiddleware((to, from) => { export default defineNuxtRouteMiddleware((to, _from) => {
const { reader } = storeToRefs(usePageStore()) const { reader } = storeToRefs(usePageStore())
reader.value = /\/blog\/(.*)/.test(to.path) reader.value = /\/blog\/(.*)/.test(to.path)

View File

@ -34,6 +34,9 @@ export default defineNuxtConfig({
features: { features: {
inlineStyles: false, inlineStyles: false,
}, },
experimental: {
inlineRouteRules: true,
},
components: { components: {
dirs: [ dirs: [
{ {
@ -59,7 +62,6 @@ export default defineNuxtConfig({
'nuxt-link-checker', 'nuxt-link-checker',
], ],
content: { content: {
documentDriven: true,
markdown: { markdown: {
remarkPlugins: ['remark-reading-time'], remarkPlugins: ['remark-reading-time'],
}, },
@ -169,33 +171,34 @@ export default defineNuxtConfig({
markdown: true, markdown: true,
}, },
}, },
routeRules: { // routeRules: {
'/': { // '/': {
sitemap: { // sitemap: {
changefreq: 'yearly', // changefreq: 'yearly',
priority: 1, // priority: 1,
}, // },
}, // },
'/about': { // '/about': {
sitemap: { // sitemap: {
changefreq: 'yearly', // changefreq: 'yearly',
priority: 0.8, // priority: 0.6,
}, // },
}, // },
'/projects': { // '/projects': {
sitemap: { // sitemap: {
changefreq: 'monthly', // changefreq: 'monthly',
priority: 0.8, // priority: 0.7,
}, // },
}, // },
'/social': { // '/social': {
sitemap: { // sitemap: {
changefreq: 'yearly', // changefreq: 'yearly',
priority: 0.8, // priority: 0.7,
}, // },
}, // },
}, // },
sitemap: { sitemap: {
sources: ['/api/__sitemap__/content'],
cacheMaxAgeSeconds: 360, cacheMaxAgeSeconds: 360,
exclude: [], exclude: [],
credits: false, credits: false,
@ -209,11 +212,11 @@ export default defineNuxtConfig({
width: '12.5%', width: '12.5%',
}, },
], ],
// defaults: { ← Defaults override route rules... defaults: {
// changefreq: 'monthly', changefreq: 'yearly',
// priority: 0.7, priority: 0.7,
// lastmod: buildDate, lastmod: config.build.date,
// }, },
}, },
robots: { robots: {
enabled: true, enabled: true,

View File

@ -35,58 +35,8 @@ useHead({
}, },
], ],
}) })
const error = {
http_code: 200,
title: config.title,
url: config.url,
locale: config.locale || 'en',
data: {
path: '/error.vue',
content: {
title: 'Page not found!',
description:
"The page you are looking for does not exist. However, no 404 error has occurred, as you're browsing through a web application loaded into memory and HTTP error codes make no sense here.",
},
},
slug: useRoute().params.slug,
build: config.build,
}
const errorString = JSON.stringify(error, null, 2)
const buffer = ref('')
const startTime = Date.now()
const dt = 20
let i = 0
function type() {
if (Date.now() > startTime + dt * i) buffer.value += errorString[i++]
if (i < errorString.length) requestAnimationFrame(type)
}
onMounted(() => setTimeout(type, 1500))
</script> </script>
<template> <template>
<div> <NotFound />
<h3 class="alex">Page not found!</h3>
<pre class="pre-wrap">{{ buffer }}<span class="blinker">&#9610;</span></pre>
</div>
</template> </template>
<style scoped lang="scss">
.blinker {
animation: blinker 1s steps(2, start) infinite;
}
@keyframes blinker {
from {
visibility: visible;
}
to {
visibility: hidden;
}
}
</style>

View File

@ -1,21 +1,64 @@
<script setup lang="ts"> <script setup lang="ts">
import { formatDate } from 'date-fns' import { formatDate } from 'date-fns'
const { slug } = useRoute().params import { useAsyncData } from '#app'
const config = useAppConfig() const config = useAppConfig()
const content = useContent()
let thumbnail: string | null = null
let slug = useRoute().params.slug
if (Array.isArray(slug)) slug = slug.join('/')
const { data } = await useAsyncData('home', () =>
queryContent(`/blog/${slug}`).findOne(),
)
const meta = { const meta = {
title: `${content.page.title}`, title: data.value ? data.value.title : 'Page not found',
description: content.page.description, description: data.value
image: content.page.thumbnail, ? data.value.description
: 'The page you are looking for does not exist. It might have been removed, had its name changed, or is temporarily unavailable.',
url: `${config.url}/blog`, url: `${config.url}/blog`,
} }
defineOgImage() // When defineOgImage is used, useSeoMeta must exclude ogImage and twitterImage properties.
useSeoMeta({
title: meta.title,
description: meta.description,
ogTitle: meta.title,
ogDescription: meta.description,
// ogImage: EXCLUDED
ogUrl: meta.url,
ogType: 'article',
twitterTitle: meta.title,
twitterDescription: meta.description,
// twitterImage: EXCLUDED
twitterCard: 'summary_large_image',
})
// Hydrate the rendered items. if (data.value) {
onMounted(() => { thumbnail =
data.value.thumbnail ??
`/images/blog/thumbnails/${data.value._path!.split('/').at(-1)}.png`
// Generate the article's Open Graph image.
defineOgImageComponent(
'OgImage',
{
title: data.value.title,
description: data.value.description,
logo: '/images/logo.png',
sectionLogo: '/images/chest.png',
thumbnail,
alt: data.value.title,
},
{
fonts: ['Alexandria:700', 'Lato:700'],
},
)
// Hydrate the rendered items.
onMounted(() => {
document.querySelectorAll('pre').forEach((pre) => { document.querySelectorAll('pre').forEach((pre) => {
const icon = document.createElement('iconify-icon') const icon = document.createElement('iconify-icon')
@ -53,9 +96,9 @@ onMounted(() => {
} }
} }
}) })
}) })
onUnmounted(() => { onUnmounted(() => {
document.querySelectorAll('code').forEach((code) => { document.querySelectorAll('code').forEach((code) => {
code.onclick = null code.onclick = null
}) })
@ -63,38 +106,52 @@ onUnmounted(() => {
document.querySelectorAll('pre').forEach((pre) => { document.querySelectorAll('pre').forEach((pre) => {
pre.querySelector('.clipboard')?.remove() pre.querySelector('.clipboard')?.remove()
}) })
})
}
useHead({
title: 'Page not found',
htmlAttrs: {
lang: config.locale || 'en',
},
link: [
{
rel: 'icon',
type: 'image/x-icon',
href: '/favicon.ico',
},
],
}) })
</script> </script>
<template> <template>
<article <article
v-if="data"
class="post scrollbar fade-mask-sm d-flex flex-column gap-3 flex-grow-1 overflow-x-hidden overflow-y-auto py-sm-4 pe-sm-3" class="post scrollbar fade-mask-sm d-flex flex-column gap-3 flex-grow-1 overflow-x-hidden overflow-y-auto py-sm-4 pe-sm-3"
> >
<ContentDoc :path="`/blog/${slug}`">
<template #default="{ doc }">
<div <div
class="post-preamble" class="post-preamble"
:style="{ backgroundImage: 'url(' + doc.thumbnail + ')' }" :style="{ backgroundImage: 'url(' + thumbnail + ')' }"
> >
<div class="p-2"> <div class="p-2">
<h3 class="alex">{{ doc.title }}</h3> <h3 class="alex">{{ data.title }}</h3>
<div class="d-flex flex-row row-gap-0 column-gap-2 flex-wrap"> <div class="d-flex flex-row row-gap-0 column-gap-2 flex-wrap">
<div class="d-flex flex-row gap-1 align-items-center"> <div class="d-flex flex-row gap-1 align-items-center">
<iconify-icon icon="mdi:calendar" /> <iconify-icon icon="mdi:calendar" />
<strong class="nobr font-small"> <strong class="nobr font-small">
{{ formatDate(doc.created, 'LLLL do, y &ndash; HH:mm') }} {{ formatDate(data.created, 'LLLL do, y &ndash; HH:mm') }}
</strong> </strong>
</div> </div>
<div class="d-flex flex-row gap-1 align-items-center"> <div class="d-flex flex-row gap-1 align-items-center">
<iconify-icon icon="mdi:clock-outline" /> <iconify-icon icon="mdi:clock-outline" />
<strong class="nobr font-small"> <strong class="nobr font-small">
{{ doc.readingTime.text.split(' ')[0] + ' minutes to read' }} {{ data!.readingTime.text.split(' ')[0] + ' minutes to read' }}
</strong> </strong>
</div> </div>
</div> </div>
</div> </div>
<NuxtLink <NuxtLink
:href="`https://twitter.com/share?url=${config.url}/blog/${slug}&text=${doc.title}&hashtags=${doc.tags.slice(0, 3).join(',').replace(/ /g, '')}`" :href="`https://twitter.com/share?url=${config.url}/blog/${slug}&text=${data.title}&hashtags=${data.tags.slice(0, 3).join(',').replace(/ /g, '')}`"
target="_blank" target="_blank"
class="link post-preamble-share px-2 py-1" class="link post-preamble-share px-2 py-1"
> >
@ -106,20 +163,10 @@ onUnmounted(() => {
</div> </div>
<div class="post-content"> <div class="post-content">
<Separator class="mt-0" /> <Separator class="mt-0" />
<ContentRenderer :value="doc" /> <ContentRenderer :value="data" />
</div> </div>
</template>
<template #not-found>
<div
class="d-flex flex-column justify-content-center align-items-center gap-3"
>
<span>Blog post not found 🙁</span>
<NuxtLink to="/blog" class="link-hi">Back to blog</NuxtLink>
</div>
</template>
</ContentDoc>
</article> </article>
<NotFound v-else />
</template> </template>
<style scoped lang="scss"></style> <style scoped lang="scss"></style>

View File

@ -41,7 +41,12 @@ useHead({
<template> <template>
<section> <section>
<h3 class="alex">Recent posts</h3> <h3 class="alex">The Enderchest</h3>
<p>
You're browsing the enderchest a blog about software development,
scientific research and Windows quirks.
</p>
<h4 class="alex">Recent posts</h4>
<ContentList <ContentList
:query="{ :query="{
path: '/blog', path: '/blog',
@ -64,7 +69,10 @@ useHead({
<div class="post-thumb"> <div class="post-thumb">
<img <img
draggable="false" draggable="false"
:src="post.thumbnail" :src="
post.thumbnail ??
`/images/blog/thumbnails/${post._path!.split('/').at(-1)}.png`
"
:alt="post.title" :alt="post.title"
class="rounded-4" class="rounded-4"
/> />

View File

@ -1,4 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { defineRouteRules } from '#imports'
const config = useAppConfig() const config = useAppConfig()
const meta = { const meta = {
title: 'Enderman', title: 'Enderman',
@ -34,6 +36,13 @@ useHead({
}, },
], ],
}) })
defineRouteRules({
sitemap: {
changefreq: 'yearly',
priority: 1,
},
})
</script> </script>
<template> <template>

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

View File

@ -0,0 +1,16 @@
import type { ParsedContent } from '@nuxt/content/dist/runtime/types'
import { formatDate } from 'date-fns'
import { serverQueryContent } from '#content/server'
export default defineSitemapEventHandler(async (e) => {
const contentList = (await serverQueryContent(e).find()) as ParsedContent[]
return contentList.map((c) => {
return asSitemapUrl({
loc: c._path,
lastmod: formatDate(c.updated, 'yyyy-MM-dd'),
changefreq: 'monthly',
priority: 0.9,
})
})
})

View File

@ -15,7 +15,7 @@
"~/*": ["./*"], "~/*": ["./*"],
"@/*": ["./*"] "@/*": ["./*"]
}, },
"types": ["@nuxt/types", "@nuxtjs/axios", "@nuxt/content", "@types/node"] "types": ["@nuxt/types", "@nuxtjs/axios", "@nuxt/content", "nuxt-simple-sitemap", "@types/node"]
}, },
"exclude": ["node_modules", ".nuxt", "dist"] "exclude": ["node_modules", ".nuxt", "dist"]
} }