Migrate to nuxt content v3. Change articles layout.
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { ParsedContent } from "@nuxt/content/dist/runtime/types";
|
import { formatDate } from "@vueuse/core";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
article: ParsedContent;
|
article: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { article } = defineProps<Props>();
|
const { article } = defineProps<Props>();
|
||||||
@@ -10,8 +10,10 @@ const date = useDateFormat(article.date, "Do of MMMM YYYY");
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ULink class="font-semibold hover:underline" :to="article._path">{{
|
<ULink class="font-semibold hover:underline" :to="article.path">{{
|
||||||
article.title
|
article.title
|
||||||
}}</ULink>
|
}}</ULink>
|
||||||
<div class="text-xs text-slate-500">{{ date }}</div>
|
<div class="text-xs text-slate-500">
|
||||||
|
{{ date }}
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
19
content.config.ts
Normal file
19
content.config.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { defineCollection, defineContentConfig, z } from "@nuxt/content";
|
||||||
|
|
||||||
|
export default defineContentConfig({
|
||||||
|
collections: {
|
||||||
|
articles: defineCollection({
|
||||||
|
source: "articles/**/*.md",
|
||||||
|
type: "page",
|
||||||
|
schema: z.object({
|
||||||
|
title: z.string(),
|
||||||
|
date: z.date(),
|
||||||
|
coverImage: z.object({
|
||||||
|
author: z.string(),
|
||||||
|
authorUrl: z.string().url(),
|
||||||
|
url: z.string().url(),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -12,7 +12,7 @@ export default defineNuxtConfig({
|
|||||||
],
|
],
|
||||||
|
|
||||||
content: {
|
content: {
|
||||||
markdown: {
|
renderer: {
|
||||||
anchorLinks: false,
|
anchorLinks: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
1269
package-lock.json
generated
1269
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -17,12 +17,12 @@
|
|||||||
"vue-router": "^4.2.5"
|
"vue-router": "^4.2.5"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nuxt/content": "^2.9.0",
|
"@nuxt/content": "^3.3.0",
|
||||||
"@nuxt/ui": "^2.11.0",
|
"@nuxt/ui": "^2.11.0",
|
||||||
"@nuxtjs/robots": "^3.0.0",
|
"@nuxtjs/robots": "^3.0.0",
|
||||||
"@vueuse/core": "^10.7.0",
|
"@vueuse/core": "^10.7.0",
|
||||||
"@vueuse/motion": "^2.0.0",
|
"@vueuse/motion": "^3.0.3",
|
||||||
"@vueuse/nuxt": "^10.7.0",
|
"@vueuse/nuxt": "^13.0.0",
|
||||||
"sharp": "^0.33.0"
|
"sharp": "^0.33.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,53 +6,71 @@ definePageMeta({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const { path } = useRoute();
|
const { path } = useRoute();
|
||||||
|
|
||||||
|
const { data: article } = useAsyncData(path, async () => {
|
||||||
|
const article = await queryCollection("articles").path(path).first();
|
||||||
|
|
||||||
|
return article;
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ContentDoc :path="path" v-slot="{ doc }">
|
|
||||||
<UContainer
|
<UContainer
|
||||||
v-motion-fade
|
v-motion-fade
|
||||||
class="flex flex-col gap-3 prose dark:prose-invert"
|
class="flex flex-col gap-3 prose dark:prose-invert"
|
||||||
as="article"
|
as="article"
|
||||||
>
|
>
|
||||||
<div class="text-sm text-slate-500">
|
<div class="text-sm text-slate-500">
|
||||||
{{ formatDate(new Date(doc.date), "Do of MMMM YYYY") }}
|
{{ formatDate(new Date(article.date), "Do of MMMM YYYY") }}
|
||||||
</div>
|
</div>
|
||||||
<h1>{{ doc.title }}</h1>
|
<h1>{{ article.title }}</h1>
|
||||||
</UContainer>
|
</UContainer>
|
||||||
|
|
||||||
<UContainer
|
<UContainer
|
||||||
class="hidden md:block"
|
class="hidden md:block"
|
||||||
as="figure"
|
as="figure"
|
||||||
v-if="doc.coverImage?.url"
|
v-if="article.coverImage?.url"
|
||||||
v-motion-fade
|
v-motion-fade
|
||||||
:delay="500"
|
:delay="500"
|
||||||
>
|
>
|
||||||
<NuxtImg
|
<NuxtImg
|
||||||
placeholder
|
placeholder
|
||||||
:src="doc.coverImage.url ?? ''"
|
:src="article.coverImage?.url ?? ''"
|
||||||
:alt="doc.title"
|
:alt="article.title"
|
||||||
height="1000"
|
height="1000"
|
||||||
width="1700"
|
width="1700"
|
||||||
class="rounded-lg"
|
class="rounded-lg"
|
||||||
/>
|
/>
|
||||||
<ULink
|
<ULink
|
||||||
:to="doc.coverImage.authorUrl"
|
:to="article.coverImage.authorUrl"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
class="text-xs text-slate-500 italic font-serif hover:underline"
|
class="text-xs text-slate-500 italic font-serif hover:underline"
|
||||||
>
|
>
|
||||||
Photo by {{ doc.coverImage.author }}
|
Photo by {{ article.coverImage.author }}
|
||||||
</ULink>
|
</ULink>
|
||||||
</UContainer>
|
</UContainer>
|
||||||
|
|
||||||
<UContainer
|
<UContainer
|
||||||
v-motion-fade
|
v-motion-fade
|
||||||
:delay="500"
|
:delay="500"
|
||||||
class="flex flex-col gap-3 prose dark:prose-invert !pt-0"
|
class="flex flex-col gap-3 prose dark:prose-invert !pt-0"
|
||||||
as="article"
|
as="article"
|
||||||
>
|
>
|
||||||
<ContentRenderer :value="doc" />
|
<ContentRenderer :value="article" />
|
||||||
</UContainer>
|
</UContainer>
|
||||||
</ContentDoc>
|
|
||||||
|
|
||||||
<Footer v-motion-fade :delay="500" />
|
<Footer v-motion-fade :delay="500" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
article.prose {
|
||||||
|
h2 {
|
||||||
|
font-weight: bold !important;
|
||||||
|
|
||||||
|
a {
|
||||||
|
font-weight: bold !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
s
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { formatDate } from "@vueuse/core";
|
||||||
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
layout: "content",
|
layout: "content",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const articles = useAsyncData("articles", async () => {
|
||||||
|
return queryCollection("articles").order("date", "DESC").all();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -9,19 +15,30 @@ definePageMeta({
|
|||||||
<h1>Articles</h1>
|
<h1>Articles</h1>
|
||||||
</UContainer>
|
</UContainer>
|
||||||
|
|
||||||
<UContainer
|
<UContainer v-motion-fade :delay="500" class="grid grid-cols-12 gap-8">
|
||||||
v-motion-fade
|
<UCard class="col-span-6" v-for="article in articles.data.value">
|
||||||
:delay="500"
|
<div class="grid gap-4">
|
||||||
class="flex flex-col md:gap-10 gap-5 !pt-0"
|
<NuxtImg
|
||||||
>
|
class="rounded rounded-lg cursor-pointer"
|
||||||
<ContentList :query="{ sort: [{ date: -1 }] }" v-slot="{ list }">
|
:src="article.coverImage.url"
|
||||||
<div v-for="article in list" :key="article._path">
|
@click="navigateTo(article.path)"
|
||||||
<ArticleListing
|
|
||||||
:article="article"
|
|
||||||
v-if="article._path?.startsWith('/articles')"
|
|
||||||
/>
|
/>
|
||||||
|
<div class="w-full">
|
||||||
|
<NuxtLink :to="article.path" class="font-semibold">{{
|
||||||
|
article.title
|
||||||
|
}}</NuxtLink>
|
||||||
|
<div class="text-sm text-slate-500">
|
||||||
|
{{ formatDate(new Date(article.date), "Do of MMMM YYYY") }}
|
||||||
</div>
|
</div>
|
||||||
</ContentList>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<UButton variant="soft" color="gray" :to="article.path"
|
||||||
|
>Read article</UButton
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</UCard>
|
||||||
</UContainer>
|
</UContainer>
|
||||||
|
|
||||||
<Footer v-motion-fade :delay="500" />
|
<Footer v-motion-fade :delay="500" />
|
||||||
|
|||||||
Reference in New Issue
Block a user