1
0
mirror of https://github.com/sendevia/website.git synced 2026-03-05 23:32:45 +08:00

初始化全部文章/搜索文章页面

This commit is contained in:
2025-09-22 22:20:02 +08:00
parent 89fe1bfd77
commit df8f461f70
9 changed files with 172 additions and 91 deletions

View File

@@ -21,12 +21,14 @@
<script setup lang="ts">
import { computed } from "vue";
import { useData } from "vitepress";
const { theme, page } = useData();
import { useGlobalData } from "../composables/useGlobalData";
const { page } = useGlobalData();
const navItems = computed(() => [
{ text: "首页", icon: "home", link: "/" },
{ text: "所有文章", icon: "list", link: "/posts" },
{ text: "搜索文章", icon: "search", link: "/search.html" },
{ text: "Markdown 示例", icon: "counter_1", link: "/posts/markdown-examples" },
{ text: "API 示例", icon: "counter_2", link: "/posts/api-examples" },
]);

View File

@@ -0,0 +1,28 @@
import { ref, onMounted } from "vue";
export interface PostItem {
url: string;
title: string;
date?: string;
content?: string;
}
export function useAllPosts(withContent = false) {
const posts = ref<PostItem[]>([]);
onMounted(async () => {
// @ts-ignore
const modules = import.meta.glob("../../../posts/*.md", { eager: true });
posts.value = Object.entries(modules)
.map(([path, mod]: any) => {
const fm = mod?.frontmatter || {};
return {
url: "/posts/" + path.split("/").pop().replace(/\.md$/, ".html"),
title: fm.title || mod.title || path.split("/").pop().replace(/\.md$/, ""),
date: fm.date || "",
content: withContent ? mod?.default?.toString() || "" : undefined,
};
})
.sort((a, b) => (b.date || "").localeCompare(a.date || ""));
});
return posts;
}

View File

@@ -0,0 +1,6 @@
import { useData } from "vitepress";
export function useGlobalData() {
const { site, page, frontmatter, theme } = useData();
return { site, page, frontmatter, theme };
}

View File

@@ -0,0 +1,16 @@
<template>
<div class="all-posts-page">
<h1>所有文章</h1>
<ul>
<li v-for="post in posts" :key="post.url">
<a :href="post.url">{{ post.title }}</a>
<span v-if="post.date"> - {{ post.date }}</span>
</li>
</ul>
</div>
</template>
<script setup lang="ts">
import { useAllPosts } from "../composables/useAllPosts";
const posts = useAllPosts();
</script>

View File

@@ -0,0 +1,27 @@
<template>
<div class="search-posts-page">
<h1>搜索文章</h1>
<input v-model="query" placeholder="输入关键词..." class="search-input" />
<ul v-if="filteredPosts.length">
<li v-for="post in filteredPosts" :key="post.url">
<a :href="post.url">{{ post.title }}</a>
<span v-if="post.date"> - {{ post.date }}</span>
</li>
</ul>
<p v-else>没有找到相关文章</p>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from "vue";
import { useAllPosts } from "../composables/useAllPosts";
const posts = useAllPosts(true);
const query = ref("");
const filteredPosts = computed(() => {
if (!query.value) return posts.value;
const q = query.value.toLowerCase();
return posts.value.filter((post) => post.title.toLowerCase().includes(q) || (post.content && post.content.toLowerCase().includes(q)));
});
</script>

View File

@@ -4,7 +4,7 @@
#main-layout {
display: grid;
grid-template-columns: 96px 0px auto;
grid-template-columns: 96px auto;
position: relative;
@@ -19,7 +19,8 @@
align-items: start;
gap: 24px;
grid-column: 3;
grid-template-columns: repeat(12, minmax(72px, 84px));
grid-template-columns: repeat(12, minmax(72px, 100vw));
justify-content: center;
position: relative;
@@ -34,9 +35,82 @@
scrollbar-width: thin;
transition: var(--md-sys-motion-duration-medium1) var(--md-sys-motion-easing-emphasized);
& > {
h1 {
@include mixin.typescale-style("display-large");
display: flex;
align-items: center;
grid-column: span 9;
height: 100%;
}
h6 {
grid-column: span 9;
}
img {
grid-column: 11 / span 2;
grid-row: 2 / span 2;
margin: auto;
height: 120px;
width: 120px;
-webkit-mask: var(--via-svg-mask) no-repeat 0 / 100%;
mask: var(--via-svg-mask) no-repeat 0 / 100%;
}
}
#main-layout-content-filler {
display: grid;
display: flex;
flex-flow: column wrap;
grid-column: span 12;
height: 100%;
padding: 24px;
background-color: var(--md-sys-color-surface-container-lowest);
border-radius: var(--md-sys-shape-corner-extra-extra-large);
&::before,
&::after {
content: "";
flex-basis: 100%;
width: 0;
order: 2;
}
div.card[spec="feed"] {
width: calc(50% - 12px);
border-radius: var(--md-sys-shape-corner-extra-large-increased);
&:nth-child(2n + 4),
&[size="large"] {
margin-inline-end: 12px;
order: 1;
}
&:nth-child(2n + 3),
&[size="small"] {
margin-inline-start: 12px;
order: 2;
}
& > a {
width: 100%;
color: var(--md-sys-color-on-surface);
text-decoration: none;
}
}
}
#main-layout-scrolltop {
@@ -642,92 +716,6 @@
}
}
&[spec="feed"] {
#main-layout-content-flow {
gap: 24px;
grid-template-rows: minmax(90px, 240px) minmax(180px, 360px) auto;
justify-content: center;
padding-block-end: 68px;
& > {
h1 {
@include mixin.typescale-style("display-large");
display: flex;
align-items: center;
grid-column: span 9;
height: 100%;
}
h6 {
grid-column: span 9;
}
img {
grid-column: 11 / span 2;
grid-row: 2 / span 2;
margin: auto;
height: 120px;
width: 120px;
-webkit-mask: var(--via-svg-mask) no-repeat 0 / 100%;
mask: var(--via-svg-mask) no-repeat 0 / 100%;
}
}
#main-layout-content-filler {
display: flex;
flex-flow: column wrap;
height: 100%;
padding: 24px;
background-color: var(--md-sys-color-surface-container-lowest);
border-radius: var(--md-sys-shape-corner-extra-extra-large);
&::before,
&::after {
content: "";
flex-basis: 100%;
width: 0;
order: 2;
}
div.card[spec="feed"] {
width: calc(50% - 12px);
border-radius: var(--md-sys-shape-corner-extra-large-increased);
&:nth-child(2n + 4),
&[size="large"] {
margin-inline-end: 12px;
order: 1;
}
&:nth-child(2n + 3),
&[size="small"] {
margin-inline-start: 12px;
order: 2;
}
& > a {
width: 100%;
color: var(--md-sys-color-on-surface);
text-decoration: none;
}
}
}
}
}
@media screen and (max-width: 1600px) {
$columns: 9;

View File

@@ -143,6 +143,8 @@ s {
}
hr {
width: 100%;
border: 1px solid var(--md-sys-color-outline-variant);
opacity: 0.3;

6
posts.md Normal file
View File

@@ -0,0 +1,6 @@
---
layout: posts
title: 所有文章
---
<AllPosts />

6
search.md Normal file
View File

@@ -0,0 +1,6 @@
---
layout: search
title: 搜索文章
---
<SearchPosts />