From 68d5f36a26cd433ae8637144fd94c4c3c82d6e1c Mon Sep 17 00:00:00 2001 From: Han <1655466387@qq.com> Date: Sat, 8 Mar 2025 14:36:33 +0800 Subject: [PATCH] =?UTF-8?q?=20=E8=B6=85=E7=BA=A7=E5=8A=A0=E5=80=8D?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=9B=B4=E6=96=B0=E2=9C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- astro.config.mjs | 30 +++++++++++++++---- package.json | 6 ++++ ...markdown.formate.ts => markdown.custom.ts} | 29 +++++++----------- src/scripts/BackTop.ts | 6 +++- src/scripts/{Article.ts => Code.ts} | 17 ++--------- src/scripts/Comment.ts | 4 +-- src/scripts/Init.ts | 16 +++++++--- src/scripts/Lenis.ts | 15 ++++++++++ src/scripts/Search.ts | 6 ++-- src/scripts/Talking.ts | 2 +- src/scripts/Video.ts | 1 + src/styles/Article.less | 17 +++++++---- src/styles/components/Comment.less | 6 ++-- 13 files changed, 99 insertions(+), 56 deletions(-) rename src/plugins/{markdown.formate.ts => markdown.custom.ts} (79%) rename src/scripts/{Article.ts => Code.ts} (70%) create mode 100644 src/scripts/Lenis.ts diff --git a/astro.config.mjs b/astro.config.mjs index 9a95b5c..da24d81 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -2,8 +2,14 @@ import mdx from '@astrojs/mdx'; import sitemap from '@astrojs/sitemap'; import { defineConfig } from 'astro/config'; -import remarkDirective from "remark-directive"; /* Handle directives */ -import { remarkNote, addClassNames } from './src/plugins/markdown.formate' +import Compress from "@playform/compress"; +// Markdown 配置================ +import remarkMath from "remark-math"; +import rehypeSlug from "rehype-slug"; +import rehypeKatex from "rehype-katex"; +import remarkDirective from "remark-directive"; +import { remarkNote, addClassNames } from './src/plugins/markdown.custom' +// Markdown 配置================ import swup from '@swup/astro'; // https://astro.build/config export default defineConfig({ @@ -22,6 +28,11 @@ export default defineConfig({ updateBodyClass: false, globalInstance: true }), + Compress({ + CSS: false, + Image: false, + Action: { Passed: async () => true }, + }), sitemap({ changefreq: 'weekly', priority: 0.7, @@ -29,10 +40,19 @@ export default defineConfig({ // 处理末尾带 / 的 url serialize: (item) => ({ ...item, url: item.url.endsWith('/') ? item.url.slice(0, -1) : item.url }) }), - mdx()], + mdx({ extendMarkdownConfig: false }) + ], markdown: { - rehypePlugins: [addClassNames], - remarkPlugins: [remarkDirective, remarkNote], + remarkPlugins: [ + remarkMath, + remarkDirective, + remarkNote, + ], + rehypePlugins: [ + rehypeKatex, + rehypeSlug, + addClassNames + ], syntaxHighlight: 'shiki', shikiConfig: { theme: 'github-light' }, }, diff --git a/package.json b/package.json index 6247735..ddf4302 100644 --- a/package.json +++ b/package.json @@ -16,11 +16,13 @@ "@swup/astro": "^1.5.0", "aplayer": "^1.10.1", "astro": "^5.4.1", + "lenis": "^1.2.1", "overlayscrollbars": "^2.11.1", "vanilla-lazyload": "^19.1.3", "vh-plugin": "^1.2.2" }, "devDependencies": { + "@playform/compress": "^0.1.7", "@types/dplayer": "^1.25.5", "@types/nprogress": "^0.2.3", "cheerio": "^1.0.0", @@ -28,7 +30,11 @@ "less": "^4.2.2", "mdast-util-to-string": "^4.0.0", "reading-time": "^1.5.0", + "rehype-katex": "^7.0.1", + "rehype-slug": "^6.0.0", "remark-directive": "^4.0.0", + "remark-math": "^6.0.0", + "remark-sectionize": "^2.1.0", "typescript": "^5.8.2", "unist-util-visit": "^5.0.0" }, diff --git a/src/plugins/markdown.formate.ts b/src/plugins/markdown.custom.ts similarity index 79% rename from src/plugins/markdown.formate.ts rename to src/plugins/markdown.custom.ts index 2beb294..ebcda2a 100644 --- a/src/plugins/markdown.formate.ts +++ b/src/plugins/markdown.custom.ts @@ -3,16 +3,10 @@ import { visit } from 'unist-util-visit'; import getReadingTime from 'reading-time'; import { toString } from 'mdast-util-to-string'; -// 处理函数 -const nodeTreeFmt = (node: any, parent: any) => { - if (node.type === 'text') parent.children = node.value.split('\n').map((i: string) => ({ type: 'paragraph', children: [{ type: 'text', value: i }] })); - if (node.children && node.children.length) node.children.forEach((child: any) => nodeTreeFmt(child, node)); -} - // 处理标签 const remarkNote = () => { return (tree: any, { data: astroData }: any) => { - visit(tree, (node, index, parent) => { + visit(tree, (node) => { const { type, name, attributes } = node; // 处理组件 if (type == 'textDirective' || type == 'leafDirective' || type == 'containerDirective') { @@ -31,10 +25,6 @@ const remarkNote = () => { if (name.startsWith('vh')) { Object.keys(node.attributes).forEach((i: any) => (hProperties[`data-${i}`] = node.attributes[i])); } - // 处理 note 内容换行问题 - if (name == 'note') { - nodeTreeFmt(node, parent); - }; // 设置 class hProperties.class = `vh-node vh-${name}${attributes.type ? ` ${name}-${attributes.type}` : ''}`; // 文章字数统计 @@ -48,7 +38,7 @@ const remarkNote = () => { } -// Pre中的 Copy 按钮 +// 处理 HTML 标签 const addClassNames = () => { return (tree: any) => { visit(tree, (node, index, parent) => { @@ -56,19 +46,22 @@ const addClassNames = () => { if (node.tagName === 'a') { node.properties.target = '_blank', node.properties.rel = 'noopener nofollow' node.children = [{ type: 'element', tagName: 'span', children: node.children || [] }]; - } - // 处理代码快 - if (node.tagName === 'pre') { + // 处理 pre 标签 + } else if (node.tagName === 'pre') { const divNode = { type: 'element', tagName: 'section', properties: { class: 'vh-code-box' }, children: [{ type: 'element', tagName: 'span', properties: { class: 'vh-code-copy' } }, node] }; // 替换父节点的 children 中的 pre 节点为新的 div 节点 if (parent && index !== null) parent.children.splice(index, 1, divNode); - } - // 处理图片 - if (node.tagName === 'img') { + // 处理 img 标签 + } else if (node.tagName === 'img') { // 添加 class 和 loading 属性 node.properties.class = 'vh-article-img'; node.properties['data-vh-lz-src'] = node.properties.src; node.properties.src = '/assets/images/lazy-loading.webp'; + // 处理 section 标签 + } else if (node.tagName === 'section') { + if (node.properties.class && node.properties.class.includes('vh-vhVideo')) { + node.children = [{ type: 'element', tagName: 'section', properties: { class: 'vh-space-loading' }, children: [{ type: 'element', tagName: 'span' }, { type: 'element', tagName: 'span' }, { type: 'element', tagName: 'span' }] }]; + } } }); diff --git a/src/scripts/BackTop.ts b/src/scripts/BackTop.ts index fc624c4..e2f9b81 100644 --- a/src/scripts/BackTop.ts +++ b/src/scripts/BackTop.ts @@ -12,7 +12,11 @@ const scrollChangeFn = () => { circle.style.strokeDashoffset = circumference - (percentage / 100) * circumference; }; // 返回顶部事件 -const backTopFn = () => window.scrollTo({ top: 0, behavior: "smooth" }); +const backTopFn = () => { + (window as any).vhlenis && (window as any).vhlenis.stop(); + window.scrollTo({ top: 0, behavior: "smooth" }); + (window as any).vhlenis.start(); +}; // 页面更新,初始化函数====== // 回顶部DOM let backTop: any = document.querySelector(".vh-back-top"); diff --git a/src/scripts/Article.ts b/src/scripts/Code.ts similarity index 70% rename from src/scripts/Article.ts rename to src/scripts/Code.ts index 7b504c9..639d203 100644 --- a/src/scripts/Article.ts +++ b/src/scripts/Code.ts @@ -1,25 +1,13 @@ -// 灯箱JS初始化====== -import "../../public/assets/js/view-image.min.js"; -declare const ViewImage: any; -// 灯箱JS初始化====== +// Pre Code 代码复制功能====== +let copyText = null; // Pre 滚动条====== import "overlayscrollbars/overlayscrollbars.css"; import { OverlayScrollbars } from "overlayscrollbars"; -// Pre 滚动条====== -// Pre Code 代码复制功能====== -let copyText = null; -// Pre Code 代码复制功能====== - -// 初始化 export default () => { - // 灯箱JS初始化====== - ViewImage && ViewImage.init("main>.vh-container>article.vh-article-main img.vh-article-img"); - // 灯箱JS初始化====== // Pre 滚动条====== document.querySelectorAll("section.vh-code-box>pre.astro-code").forEach((i: any) => { OverlayScrollbars(i, { scrollbars: { autoHide: "leave", autoHideDelay: 500, autoHideSuspend: false } }); }); - // Pre 滚动条====== // Pre Code 代码复制功能====== document.querySelectorAll("section.vh-code-box>span.vh-code-copy").forEach((i: any) => { i.vhTimer = null; @@ -35,5 +23,4 @@ export default () => { }, 1000); }); }); - // Pre Code 代码复制功能====== } \ No newline at end of file diff --git a/src/scripts/Comment.ts b/src/scripts/Comment.ts index 796ad38..3536167 100644 --- a/src/scripts/Comment.ts +++ b/src/scripts/Comment.ts @@ -8,14 +8,14 @@ declare const twikoo: any; // 处理评论区数据 const formateComment = () => { // 图片灯箱 - ViewImage && ViewImage.init(".vh-comment img:not(.tk-avatar-img,.tk-owo-emotion,.OwO-item img), main>.vh-container>article.vh-article-main img.vh-article-img"); + ViewImage && ViewImage.init(".vh-container>article.vh-article-main img.vh-article-img, .vh-talking>main>article>.main img, .vh-comment>.twikoo>.tk-comments img:not(.tk-avatar-img,.tk-owo-emotion,.OwO-item img)"); // 处理 URL document.querySelectorAll('.vh-comment a[href="#"]').forEach(link => link.removeAttribute('href')); } // 初始化评论插件 export default async () => { const commentDOM = '.vh-comment>section' - if (!document.querySelector(commentDOM) || !SITE_INFO.Twikoo.envId) return; + if (!document.querySelector(commentDOM) || !SITE_INFO.Twikoo.envId) return formateComment(); document.querySelector(commentDOM)!.innerHTML = '
' await LoadScript("https://registry.npmmirror.com/twikoo/1.6.41/files/dist/twikoo.all.min.js"); twikoo.init({ envId: SITE_INFO.Twikoo.envId, el: commentDOM, onCommentLoaded: () => setTimeout(formateComment) }) diff --git a/src/scripts/Init.ts b/src/scripts/Init.ts index 659f0b0..8e66b92 100644 --- a/src/scripts/Init.ts +++ b/src/scripts/Init.ts @@ -1,6 +1,8 @@ import { inRouter, outRouter } from "../utils/updateRouter"; -// 初始化文章功能脚本 -import ArticleInit from "../scripts/Article"; +// 鼠标滚动阻尼效果 +import LenisInit from './Lenis'; +// 初始化文章代码块 +import codeInit from "../scripts/Code"; // 初始化视频播放器 import videoInit from "../scripts/Video"; // 初始化音乐播放器 @@ -17,6 +19,8 @@ import initLinkCurrent from "../scripts/Header"; import initWebSiteTime from "../scripts/Footer"; // 友情链接初始化 import initLinks from "../scripts/Links"; +// 朋友圈 RSS 初始化 +import initFriends from "../scripts/Friends"; // 动态说说初始化 import initTalking from "../scripts/Talking"; // 文章评论初始化 @@ -36,6 +40,8 @@ import { LoadScript } from "../utils/index"; const videoList: any[] = []; const MusicList: any[] = []; const indexInit = async (only: boolean = true) => { + // 鼠标滚动阻尼效果 + only && LenisInit(); // 预加载搜索数据 only && searchFn(""); // 初始化搜索功能 @@ -48,14 +54,16 @@ const indexInit = async (only: boolean = true) => { only && initMobileSidebar(); // 顶部导航 Current 状态 initLinkCurrent() + // 初始化文章代码块 + codeInit(); // 文章评论初始化 initComment(); - // 初始化文章功能脚本 - ArticleInit(); // 图片懒加载初始化 vhLzImgInit(); // 友情链接初始化 initLinks(); + // 朋友圈 RSS 初始化 + initFriends(); // 动态说说初始化 initTalking(); // Google 广告 diff --git a/src/scripts/Lenis.ts b/src/scripts/Lenis.ts new file mode 100644 index 0000000..96c0014 --- /dev/null +++ b/src/scripts/Lenis.ts @@ -0,0 +1,15 @@ +import Lenis from "lenis"; + +(window as any).vhlenis = new Lenis(); +const lenisInit = (time: any) => { + (window as any).vhlenis.raf(time) + requestAnimationFrame(lenisInit) +} +(window as any).vhlenis.on('scroll', () => { + if (window.scrollY + window.innerHeight >= document.documentElement.scrollHeight) { + (window as any).vhlenis.stop(); + (window as any).vhlenis.start(); + } +}); + +export default () => requestAnimationFrame(lenisInit) \ No newline at end of file diff --git a/src/scripts/Search.ts b/src/scripts/Search.ts index 021c226..8d4e42d 100644 --- a/src/scripts/Search.ts +++ b/src/scripts/Search.ts @@ -1,4 +1,3 @@ -import vh from 'vh-plugin' import { $GET } from '../utils/index' // 更新数据 @@ -48,7 +47,10 @@ const vhSearchInit = () => { const searchDOM: any = document.querySelector(".vh-header>.main>.nav-btn>span.search-btn"); const searchMainDOM: any = document.querySelector(".vh-header>.main>.vh-search>main"); const searchListDOM: any = document.querySelector(".vh-header>.main>.vh-search"); - const addActive = () => setTimeout(() => searchListDOM.classList.add("active")); + const addActive = () => setTimeout(() => { + searchListDOM.classList.add("active"); + searchListDOM.querySelector(".search-input>input").focus(); + }); const removeActive = () => setTimeout(() => searchListDOM.classList.remove("active")); // 禁止默认事件 searchMainDOM.addEventListener("click", (e: Event) => e.stopPropagation()); diff --git a/src/scripts/Talking.ts b/src/scripts/Talking.ts index 56603de..4c3d883 100644 --- a/src/scripts/Talking.ts +++ b/src/scripts/Talking.ts @@ -21,7 +21,7 @@ const TalkingInit = async (data: any) => { // 图片懒加载 vhLzImgInit(); // 灯箱JS初始化====== - ViewImage && ViewImage.init(".vh-talking>main>article>.main img"); + setTimeout(() => (ViewImage && ViewImage.init(".vh-talking>main>article>.main img, .vh-comment>.twikoo>.tk-comments img:not(.tk-avatar-img,.tk-owo-emotion,.OwO-item img)"))); // 灯箱JS初始化====== } catch { vh.Toast('获取数据失败') diff --git a/src/scripts/Video.ts b/src/scripts/Video.ts index 8d007d5..ae55fd7 100644 --- a/src/scripts/Video.ts +++ b/src/scripts/Video.ts @@ -18,6 +18,7 @@ export default async (videoList: any[]) => { video: { url: i.getAttribute("data-url"), type: "auto", + pic: i.getAttribute("data-poster") || '', customType: { hls: (video: any) => { if (Hls.isSupported()) { diff --git a/src/styles/Article.less b/src/styles/Article.less index c4afd0b..4dd24f5 100644 --- a/src/styles/Article.less +++ b/src/styles/Article.less @@ -195,11 +195,12 @@ section.vh-container { // 其下面的 a 标签样式 a { - box-shadow: inset 0 -.12em #60a5fa; + color: #280F25; + box-shadow: inset 0 -.12rem #60a5fa; transition: box-shadow .2s ease-in-out, color .2s ease-in-out; &:hover { - box-shadow: inset 0 -1.5em #60a5fa7f + box-shadow: inset 0 -1.5rem #60a5fa66; } } @@ -221,14 +222,17 @@ section.vh-container { } blockquote { - padding: 0.188rem 0.58rem; - border-left: 5px solid #eee; - border-left-color: #929292; - background-color: #f3f5f7; + margin: 1rem 0 1.618rem; + padding: 0 0.88rem; + border-left: 0.288rem solid #49b1f5; + background-color: rgba(73, 177, 245, 0.1); + border-radius: 0.618rem; &>p { font-size: 0.875rem; font-weight: 500; + line-height: 1.58rem; + color: #6A737D; } } @@ -492,6 +496,7 @@ section.vh-container { // ::vhVideo &.vh-vhVideo { margin: 1.188rem 0; + box-sizing: border-box; width: 100%; aspect-ratio: 16 / 9; border: solid 1px #E8E8E8; diff --git a/src/styles/components/Comment.less b/src/styles/components/Comment.less index df96a58..7eac65c 100644 --- a/src/styles/components/Comment.less +++ b/src/styles/components/Comment.less @@ -58,12 +58,14 @@ font-size: 0.875rem; line-height: 28px; + a { - box-shadow: inset 0 -.12em #60a5fa; + color: #280F25; + box-shadow: inset 0 -.12rem #60a5fa; transition: box-shadow .2s ease-in-out, color .2s ease-in-out; &:hover { - box-shadow: inset 0 -1.5em #60a5fa7f + box-shadow: inset 0 -1.5rem #60a5fa66; } } }