diff --git a/package.json b/package.json index ddf4302..77abcec 100644 --- a/package.json +++ b/package.json @@ -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" diff --git a/src/components/ArticleCard.astro b/src/components/ArticleCard.astro index 2cb3dcc..937e1ae 100644 --- a/src/components/ArticleCard.astro +++ b/src/components/ArticleCard.astro @@ -12,7 +12,7 @@ import "../styles/components/ArticleCard.less"; ---
- +
{post.data.title}
diff --git a/src/content.config.ts b/src/content.config.ts index a2eb10f..9f2d71e 100644 --- a/src/content.config.ts +++ b/src/content.config.ts @@ -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() }), }); diff --git a/src/pages/[...page].astro b/src/pages/[...page].astro index d6e766d..663eafd 100644 --- a/src/pages/[...page].astro +++ b/src/pages/[...page].astro @@ -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), diff --git a/src/styles/Article.less b/src/styles/Article.less index 4dd24f5..a8532bb 100644 --- a/src/styles/Article.less +++ b/src/styles/Article.less @@ -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; diff --git a/src/styles/components/ArticleCard.less b/src/styles/components/ArticleCard.less index 824d8fa..dec9a9a 100644 --- a/src/styles/components/ArticleCard.less +++ b/src/styles/components/ArticleCard.less @@ -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%; diff --git a/src/styles/components/Search.less b/src/styles/components/Search.less index fd623e3..9654d06 100644 --- a/src/styles/components/Search.less +++ b/src/styles/components/Search.less @@ -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); diff --git a/src/utils/getCover.ts b/src/utils/getCover.ts index f18b856..a40e035 100644 --- a/src/utils/getCover.ts +++ b/src/utils/getCover.ts @@ -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; \ No newline at end of file +} \ No newline at end of file diff --git a/src/utils/getFileTime.ts b/src/utils/getFileTime.ts deleted file mode 100644 index fd67b50..0000000 --- a/src/utils/getFileTime.ts +++ /dev/null @@ -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(); - } -} \ No newline at end of file diff --git a/src/utils/getPostInfo.ts b/src/utils/getPostInfo.ts index a0a6e46..758a219 100644 --- a/src/utils/getPostInfo.ts +++ b/src/utils/getPostInfo.ts @@ -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 }; \ No newline at end of file diff --git a/src/utils/moveTopToFirst.ts b/src/utils/moveTopToFirst.ts new file mode 100644 index 0000000..c5f583f --- /dev/null +++ b/src/utils/moveTopToFirst.ts @@ -0,0 +1,8 @@ +export default (arr: Array) => { + const index = arr.findIndex((item: any) => item.data.top === true); + if (index !== -1) { + const [item] = arr.splice(index, 1); + arr.unshift(item); + } + return arr; +} \ No newline at end of file diff --git a/src/utils/vhSearch.ts b/src/utils/vhSearch.ts index 4cdb390..93ddc75 100644 --- a/src/utils/vhSearch.ts +++ b/src/utils/vhSearch.ts @@ -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(`${i.rendered.html}`); return { @@ -25,6 +25,4 @@ const setSearchJson = async (posts: any[]) => { } catch (error) { console.error('Error writing search index file:', error); } -}; - -export default setSearchJson; \ No newline at end of file +}; \ No newline at end of file