添加置顶文章
This commit is contained in:
parent
a019180b73
commit
ae1bcf555d
@ -15,8 +15,8 @@
|
||||
"@astrojs/sitemap": "^3.2.1",
|
||||
"@swup/astro": "^1.5.0",
|
||||
"aplayer": "^1.10.1",
|
||||
"astro": "^5.4.1",
|
||||
"lenis": "^1.2.1",
|
||||
"astro": "^5.4.2",
|
||||
"lenis": "^1.2.3",
|
||||
"overlayscrollbars": "^2.11.1",
|
||||
"vanilla-lazyload": "^19.1.3",
|
||||
"vh-plugin": "^1.2.2"
|
||||
|
||||
@ -12,7 +12,7 @@ import "../styles/components/ArticleCard.less";
|
||||
---
|
||||
|
||||
<article class="vh-article-item vh-animation vh-animation-init">
|
||||
<a class="vh-article-link" href={`/article/${post.data.id}`}>
|
||||
<a class={`vh-article-link${post.data.top ? " active" : ""}`} href={`/article/${post.data.id}`}>
|
||||
<section class="vh-article-banner"><Image src="/assets/images/lazy-loading.webp" data-vh-lz-src={ARTICLE_COVER} alt={post.data.title} width="10" height="10" /></section>
|
||||
<section class="vh-article-desc">
|
||||
<header>
|
||||
|
||||
@ -14,7 +14,8 @@ const blog = defineCollection({
|
||||
id: z.union([z.string(), z.number()]),
|
||||
cover: z.string().optional(),
|
||||
recommend: z.boolean().optional(),
|
||||
hide: z.boolean().optional()
|
||||
hide: z.boolean().optional(),
|
||||
top: z.boolean().optional()
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@ -2,12 +2,14 @@
|
||||
import { getCollection } from "astro:content";
|
||||
import type { GetStaticPathsOptions } from "astro";
|
||||
import setSearchJson from "../utils/vhSearch";
|
||||
import moveTopToFirst from "../utils/moveTopToFirst";
|
||||
export async function getStaticPaths(options: GetStaticPathsOptions) {
|
||||
const { paginate } = options;
|
||||
const posts = (await getCollection("blog")).sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf());
|
||||
// 生成 Search JSON 文件 ======
|
||||
// 置顶文章功能
|
||||
moveTopToFirst(posts);
|
||||
// 生成 Search JSON 文件
|
||||
await setSearchJson(posts);
|
||||
// 生成 Search JSON 文件 ======
|
||||
// 隐藏的文章不显示
|
||||
return paginate(
|
||||
posts.filter(i => !i.data.hide),
|
||||
|
||||
@ -3,7 +3,6 @@ section.vh-container {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
|
||||
|
||||
&>header {
|
||||
box-sizing: border-box;
|
||||
padding: 2rem 1rem 1rem;
|
||||
@ -70,6 +69,14 @@ section.vh-container {
|
||||
box-shadow: 0 12px 8px 6px rgba(7, 17, 27, 0.05);
|
||||
overflow: hidden;
|
||||
|
||||
.aplayer-list {
|
||||
max-height: max-content !important;
|
||||
|
||||
&>ol {
|
||||
max-height: 566px !important;
|
||||
}
|
||||
}
|
||||
|
||||
&>.tag-list {
|
||||
box-sizing: border-box;
|
||||
padding-top: 2rem;
|
||||
|
||||
@ -20,6 +20,7 @@ section.article-list {
|
||||
overflow: hidden;
|
||||
|
||||
&>a.vh-article-link {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -38,7 +39,48 @@ section.article-list {
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
&::before {
|
||||
content: "置顶";
|
||||
position: absolute;
|
||||
top: 1.6rem;
|
||||
left: 0.66rem;
|
||||
box-sizing: border-box;
|
||||
padding: 0.18rem 1rem;
|
||||
width: max-content;
|
||||
height: max-content;
|
||||
font-size: 1rem;
|
||||
color: #fff;
|
||||
border-radius: 0.66rem;
|
||||
transform: rotate(-45deg);
|
||||
/* 确保元素有半透明背景 */
|
||||
background: #00000033;
|
||||
box-shadow: 0 2rem 1rem rgba(0, 0, 0, 0.1);
|
||||
z-index: 1;
|
||||
/* 高斯模糊效果 */
|
||||
backdrop-filter: blur(6px);
|
||||
-webkit-backdrop-filter: blur(6px);
|
||||
/* 兼容旧版浏览器 */
|
||||
}
|
||||
|
||||
&>.vh-article-banner {
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.06);
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&>.vh-article-banner {
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
|
||||
@ -14,11 +14,12 @@
|
||||
transition: opacity 0.16s ease-in-out;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
z-index: 10;
|
||||
z-index: -1;
|
||||
|
||||
&.active {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
z-index: 1;
|
||||
|
||||
&>main {
|
||||
transform: translateY(0);
|
||||
|
||||
@ -59,10 +59,8 @@ async function* createImageIterator(dir: string) {
|
||||
|
||||
const targetDir = path.resolve(__dirname, '../../public/assets/images/banner/'); // 目标目录
|
||||
const fileIter = createImageIterator(targetDir);
|
||||
const getCover = async (filename: string | null | undefined) => {
|
||||
export default async (filename: string | null | undefined) => {
|
||||
if (filename) return filename;
|
||||
const { value } = await fileIter.next();
|
||||
return SITE_INFO.Site + `/assets/images/banner/${value}`
|
||||
}
|
||||
|
||||
export default getCover;
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
import { execSync } from "child_process";
|
||||
|
||||
const COMMITER_DATE_ISO_FORMAT = "%cI";
|
||||
|
||||
export default function getFileCreateTime(filePath: string, type: string): Date {
|
||||
try {
|
||||
const result = execSync(`git log --pretty=format:"${COMMITER_DATE_ISO_FORMAT}" ${filePath}`).toString();
|
||||
if (!result) {
|
||||
throw new Error('Git command failed to execute');
|
||||
}
|
||||
const commits = result.split(/\r?\n/g);
|
||||
return new Date(commits[type == 'create' ? commits.length - 1 : 0]);
|
||||
} catch (e) {
|
||||
// not committed yet
|
||||
return new Date();
|
||||
}
|
||||
}
|
||||
@ -24,8 +24,8 @@ const getTags = () => {
|
||||
|
||||
// 获取推荐文章 (给文章添加 recommend: true 字段)
|
||||
const getRecommendArticles = () => {
|
||||
const recommendList = posts.filter(i => i.data.recommend).slice(0, 6);
|
||||
return (recommendList.length ? recommendList : posts).slice(0, 6).map(async i => ({ title: i.data.title, date: i.data.date, id: i.data.id, cover: await getCover(i.data.cover) }))
|
||||
const recommendList = posts.filter(i => i.data.recommend);
|
||||
return (recommendList.length ? recommendList : posts.slice(0, 6)).map(async i => ({ title: i.data.title, date: i.data.date, id: i.data.id, cover: await getCover(i.data.cover) }))
|
||||
};
|
||||
|
||||
export { getCategories, getTags, getRecommendArticles };
|
||||
8
src/utils/moveTopToFirst.ts
Normal file
8
src/utils/moveTopToFirst.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export default (arr: Array<any>) => {
|
||||
const index = arr.findIndex((item: any) => item.data.top === true);
|
||||
if (index !== -1) {
|
||||
const [item] = arr.splice(index, 1);
|
||||
arr.unshift(item);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
@ -2,7 +2,7 @@ import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
import * as cheerio from 'cheerio';
|
||||
|
||||
const setSearchJson = async (posts: any[]) => {
|
||||
export default async (posts: any[]) => {
|
||||
const searchIndex = posts.map(i => {
|
||||
const $ = cheerio.load(`<body>${i.rendered.html}</body>`);
|
||||
return {
|
||||
@ -25,6 +25,4 @@ const setSearchJson = async (posts: any[]) => {
|
||||
} catch (error) {
|
||||
console.error('Error writing search index file:', error);
|
||||
}
|
||||
};
|
||||
|
||||
export default setSearchJson;
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user