feat: add tag navigation
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
import dayjs from "dayjs";
|
||||
import utc from "dayjs/plugin/utc.js";
|
||||
import type { BlogParsedContent } from "@/shared/types";
|
||||
import { calcReadingTime } from "@/shared/readingTime";
|
||||
|
||||
dayjs.extend(utc);
|
||||
|
||||
@@ -26,33 +27,28 @@ const prettyDate = latestDate.format("DD MMM YYYY");
|
||||
>
|
||||
<h2 class="m-0 mt-4 mb-1">{{ latest.title }}</h2>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400 m-0">
|
||||
{{ prettyDate }} · {{ latest.readingTime.text }}
|
||||
{{ prettyDate }} · {{ calcReadingTime(latest).minutes }} min read
|
||||
</p>
|
||||
<div class="tag-list mt-1">
|
||||
<Tag
|
||||
v-for="(tag, index) in latest.tags"
|
||||
:key="index"
|
||||
:dest="`/blog/tags/${tag}`"
|
||||
:dest="`/tags/blog/${tag}`"
|
||||
>
|
||||
{{ tag }}
|
||||
</Tag>
|
||||
</div>
|
||||
<!--
|
||||
<ContentRenderer
|
||||
tag="article"
|
||||
:value="latest"
|
||||
:excerpt="true"
|
||||
class="pt-0 w-full"
|
||||
class="text-gray-600 dark:text-gray-300 text-base m-0 mt-5"
|
||||
>
|
||||
<ContentRendererMarkdown :value="latest" :excerpt="true" />
|
||||
<template #empty>
|
||||
<p>No description found.</p>
|
||||
</template>
|
||||
</ContentRenderer>
|
||||
-->
|
||||
<p class="excerpt text-gray-600 dark:text-gray-300 text-base m-0 mt-5">
|
||||
{{ latest.description }} …
|
||||
</p>
|
||||
</HomeStatBox>
|
||||
</div>
|
||||
</template>
|
||||
|
69
components/PostPreviewCard.vue
Normal file
69
components/PostPreviewCard.vue
Normal file
@@ -0,0 +1,69 @@
|
||||
<script setup lang="ts">
|
||||
import type { StoryParsedContent, BlogParsedContent } from "@/shared/types";
|
||||
import { calcReadingTime } from "@/shared/readingTime";
|
||||
import dayjs from "dayjs";
|
||||
import utc from "dayjs/plugin/utc.js";
|
||||
|
||||
dayjs.extend(utc);
|
||||
|
||||
const { post, type, highlighttags } = defineProps<{
|
||||
post: StoryParsedContent | BlogParsedContent;
|
||||
type: "stories" | "blog";
|
||||
highlighttags?: string[];
|
||||
}>();
|
||||
|
||||
const getPrettyDate = (story: StoryParsedContent) => {
|
||||
const date = dayjs(story.date).utc();
|
||||
return date.format("DD MMM YYYY");
|
||||
};
|
||||
|
||||
const readingTime = calcReadingTime(post);
|
||||
const descText =
|
||||
type === "stories"
|
||||
? `${readingTime.words.total} words`
|
||||
: `${readingTime.minutes} min read`;
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="story-card p-4">
|
||||
<h3 class="m-0">
|
||||
<a
|
||||
:href="post._path"
|
||||
class="no-underline text-left text-2xl sm:text-2xl font-bold hover:text-blue-700 dark:hover:text-blue-400 leading-tight transition"
|
||||
>
|
||||
{{ post.title }}
|
||||
</a>
|
||||
</h3>
|
||||
<p class="my-1 text-sm">{{ getPrettyDate(post) }} · {{ descText }}</p>
|
||||
<div class="flex flex-wrap">
|
||||
<Tag
|
||||
:dest="`/tags/${type}/${tag}`"
|
||||
v-for="(tag, index) in post.tags"
|
||||
:key="index"
|
||||
:highlight="highlighttags?.includes(tag)"
|
||||
>
|
||||
{{ tag }}
|
||||
</Tag>
|
||||
</div>
|
||||
<ContentRenderer :value="post" :excerpt="true" tag="article">
|
||||
<template #empty>No excerpt available.</template>
|
||||
</ContentRenderer>
|
||||
<div class="text-right">
|
||||
<a
|
||||
:href="post._path"
|
||||
class="no-underline hover:underline font-semibold text-blue-700 dark:text-blue-400"
|
||||
>
|
||||
Continue reading →
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.story-card {
|
||||
border: 0.1rem solid gray;
|
||||
max-width: 100%;
|
||||
border-radius: 0.5rem;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
</style>
|
@@ -2,6 +2,7 @@
|
||||
import dayjs from "dayjs";
|
||||
import utc from "dayjs/plugin/utc.js";
|
||||
import { type StoryParsedContent } from "@/shared/types";
|
||||
import { calcReadingTime } from "@/shared/readingTime";
|
||||
|
||||
dayjs.extend(utc);
|
||||
|
||||
@@ -26,35 +27,28 @@ const prettyDate = latestDate.format("DD MMM YYYY");
|
||||
>
|
||||
<h2 class="m-0 mt-4 mb-1">{{ latest.title }}</h2>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400 m-0">
|
||||
{{ prettyDate }} · {{ latest.readingTime.words }} words
|
||||
{{ prettyDate }} · {{ calcReadingTime(latest).words.total }} words
|
||||
</p>
|
||||
<div class="tag-list mt-1">
|
||||
<Tag
|
||||
v-for="(tag, index) in latest.tags"
|
||||
:key="index"
|
||||
:dest="`/stories/tags/${tag}`"
|
||||
:dest="`/tags/stories/${tag}`"
|
||||
>
|
||||
{{ tag }}
|
||||
</Tag>
|
||||
</div>
|
||||
<!--
|
||||
<ContentRenderer
|
||||
tag="article"
|
||||
:value="latest"
|
||||
:excerpt="true"
|
||||
class="pt-0 w-full"
|
||||
class="text-gray-600 dark:text-gray-300 text-base m-0 mt-5 text-ellipsis"
|
||||
>
|
||||
<ContentRendererMarkdown :value="latest" :excerpt="true" />
|
||||
<template #empty>
|
||||
<p>No description found.</p>
|
||||
</template>
|
||||
</ContentRenderer>
|
||||
-->
|
||||
<p
|
||||
class="excerpt text-gray-600 dark:text-gray-300 text-base m-0 mt-5 text-ellipsis"
|
||||
>
|
||||
{{ latest.description }} ...
|
||||
</p>
|
||||
</HomeStatBox>
|
||||
</div>
|
||||
</template>
|
||||
|
@@ -1,11 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
const { dest } = defineProps<{ dest: string }>();
|
||||
const { dest, highlight = false } = defineProps<{
|
||||
dest: string;
|
||||
highlight?: boolean;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<a :href="dest">
|
||||
<div
|
||||
class="inline-block text-xs rounded-full py-1 px-2 mt-1 mr-1 bg-gray-300 dark:bg-gray-500 transition"
|
||||
:class="[
|
||||
'inline-block text-xs rounded-full py-1 px-2 mt-1 mr-1 bg-gray-300 dark:bg-gray-500 transition',
|
||||
{ 'bg-yellow-200 dark:bg-yellow-700 shadow-lg': highlight },
|
||||
]"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
|
Reference in New Issue
Block a user