This commit is contained in:
Han 2025-02-17 18:34:21 +08:00
parent 88271e27e6
commit 2c9740dcf7
38 changed files with 389 additions and 87 deletions

20
.gitignore vendored
View File

@ -26,23 +26,3 @@ test/
/public/hanplayer
/public/MineWeb
/public/other
/src/content/blog/*
!/src/content/blog
/src/content/blog/2024/*
!/src/content/blog/2024
/src/content/blog/2024/07/*
!/src/content/blog/2024/07
/src/content/blog/2024/08/*
!/src/content/blog/2024/08
/src/content/blog/2024/09/*
!/src/content/blog/2024/09
/src/content/blog/2024/11/*
!/src/content/blog/2024/11
/src/content/blog/2024/12/*
!/src/content/blog/2024/12
!/src/content/blog/2024/07/【开源】骤雨重山无限存储图床托管于Cloudflare Pages.md
!/src/content/blog/2024/08/Cloudflare优选IPDnsPod的DDNS自动切换.md
!/src/content/blog/2024/09/【开源】HanAnalytics访问分析Web统计托管于Cloudflare Pages.md
!/src/content/blog/2024/09/基于AI的微博动态心情分析【开源】.md
!/src/content/blog/2024/11/推荐一个开源项目WebWatermark图片添加水印在线小助手.md
!/src/content/blog/2024/12/【开源】Tarot-塔罗牌占卜.md

View File

@ -1,2 +1,71 @@
# vhAstro-Theme
一款简约的 Astro 主题
# Astro Starter Kit: Blog
```sh
npm create astro@latest -- --template blog
```
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/blog)
[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/blog)
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/blog/devcontainer.json)
> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun!
![blog](https://github.com/withastro/astro/assets/2244813/ff10799f-a816-4703-b967-c78997e8323d)
Features:
- ✅ Minimal styling (make it your own!)
- ✅ 100/100 Lighthouse performance
- ✅ SEO-friendly with canonical URLs and OpenGraph data
- ✅ Sitemap support
- ✅ RSS Feed support
- ✅ Markdown & MDX support
## 🚀 Project Structure
Inside of your Astro project, you'll see the following folders and files:
```text
├── public/
├── src/
│   ├── components/
│   ├── content/
│   ├── layouts/
│   └── pages/
├── astro.config.mjs
├── README.md
├── package.json
└── tsconfig.json
```
Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.
There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.
The `src/content/` directory contains "collections" of related Markdown and MDX documents. Use `getCollection()` to retrieve posts from `src/content/blog/`, and type-check your frontmatter using an optional schema. See [Astro's Content Collections docs](https://docs.astro.build/en/guides/content-collections/) to learn more.
Any static assets, like images, can be placed in the `public/` directory.
## 🧞 Commands
All commands are run from the root of the project, from a terminal:
| Command | Action |
| :------------------------ | :----------------------------------------------- |
| `npm install` | Installs dependencies |
| `npm run dev` | Starts local dev server at `localhost:4321` |
| `npm run build` | Build your production site to `./dist/` |
| `npm run preview` | Preview your build locally, before deploying |
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
| `npm run astro -- --help` | Get help using the Astro CLI |
## 👀 Want to learn more?
Check out [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).
## Credit
This theme is based off of the lovely [Bear Blog](https://github.com/HermanMartinus/bearblog/).

View File

@ -12,12 +12,12 @@
"@astrojs/mdx": "^4.0.8",
"@astrojs/rss": "^4.0.11",
"@astrojs/sitemap": "^3.2.1",
"astro": "^5.2.5",
"astro": "^5.3.0",
"dayjs": "^1.11.13",
"dplayer": "^1.27.1",
"hls.js": "^1.5.20",
"nprogress": "^0.2.0",
"overlayscrollbars": "^2.10.1",
"overlayscrollbars": "^2.11.0",
"remark-directive": "^3.0.1",
"twikoo": "1.6.41",
"unist-util-visit": "^5.0.0",

View File

@ -1,4 +1,27 @@
/*
@import url('./HarmonyOS_Sans_Regular/result.css');
@import url('./NotoSans/result.css'); */
@import url('./SFMono-Regular/result.css');
/* @import url('./HarmonyOS_Sans/100/global/result.css');
@import url('./HarmonyOS_Sans/100/sc/result.css');
@import url('./HarmonyOS_Sans/200/global/result.css');
@import url('./HarmonyOS_Sans/200/sc/result.css');
@import url('./HarmonyOS_Sans/300/global/result.css');
@import url('./HarmonyOS_Sans/300/sc/result.css');
@import url('./HarmonyOS_Sans/400/global/result.css');
@import url('./HarmonyOS_Sans/400/sc/result.css');
@import url('./HarmonyOS_Sans/500/global/result.css');
@import url('./HarmonyOS_Sans/500/sc/result.css');
@import url('./HarmonyOS_Sans/600/global/result.css');
@import url('./HarmonyOS_Sans/600/sc/result.css');
@import url('./HarmonyOS_Sans/700/global/result.css');
@import url('./HarmonyOS_Sans/700/sc/result.css');
@import url('./HarmonyOS_Sans/800/global/result.css');
@import url('./HarmonyOS_Sans/800/sc/result.css');
@import url('./HarmonyOS_Sans/900/global/result.css');
@import url('./HarmonyOS_Sans/900/sc/result.css'); */
@import url('./MiSans/100/result.css');
@import url('./MiSans/200/result.css');
@import url('./MiSans/300/result.css');

View File

@ -0,0 +1,2 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="101" height="20" role="img" aria-label="Frame: Astro"><title>Frame: Astro</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="101" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="62" height="20" fill="#555"/><rect x="62" width="39" height="20" fill="#bc52ee"/><rect width="101" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><image x="5" y="3" width="14" height="14" xlink:href="data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjYmM1MmVlIiByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48dGl0bGU+QXN0cm88L3RpdGxlPjxwYXRoIGQ9Ik04LjM1OCAyMC4xNjJjLTEuMTg2LTEuMDctMS41MzItMy4zMTYtMS4wMzgtNC45NDQuODU2IDEuMDI2IDIuMDQzIDEuMzUyIDMuMjcyIDEuNTM1IDEuODk3LjI4MyAzLjc2LjE3NyA1LjUyMi0uNjc4LjIwMi0uMDk4LjM4OC0uMjI5LjYwOC0uMzYuMTY2LjQ3My4yMDkuOTUuMTUxIDEuNDM3LS4xNCAxLjE4NS0uNzM4IDIuMS0xLjY4OCAyLjc5NC0uMzguMjc3LS43ODIuNTI1LTEuMTc1Ljc4Ny0xLjIwNS44MDQtMS41MzEgMS43NDctMS4wNzggMy4xMTlsLjA0NC4xNDhhMy4xNTggMy4xNTggMCAwIDEtMS40MDctMS4xODggMy4zMSAzLjMxIDAgMCAxLS41NDQtMS44MTVjLS4wMDQtLjMyLS4wMDQtLjY0Mi0uMDQ4LS45NTgtLjEwNi0uNzY5LS40NzItMS4xMTMtMS4xNjEtMS4xMzMtLjcwNy0uMDItMS4yNjcuNDExLTEuNDE1IDEuMDktLjAxMi4wNTMtLjAyOC4xMDQtLjA0NS4xNjVoLjAwMnptLTUuOTYxLTQuNDQ1czMuMjQtMS41NzUgNi40OS0xLjU3NWwyLjQ1MS03LjU2NWMuMDkyLS4zNjYuMzYtLjYxNC42NjItLjYxNC4zMDIgMCAuNTcuMjQ4LjY2Mi42MTRsMi40NSA3LjU2NWMzLjg1IDAgNi40OTEgMS41NzUgNi40OTEgMS41NzVMMTYuMDg4LjcyN0MxNS45My4yODUgMTUuNjYzIDAgMTUuMzAzIDBIOC42OTdjLS4zNiAwLS42MTUuMjg1LS43ODQuNzI3bC01LjUxNiAxNC45OXoiLz48L3N2Zz4="/><text aria-hidden="true" x="405" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="350">Frame</text><text x="405" y="140" transform="scale(.1)" fill="#fff" textLength="350">Frame</text><text aria-hidden="true" x="805" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="290">Astro</text><text x="805" y="140" transform="scale(.1)" fill="#fff" textLength="290">Astro</text></g></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="167" height="20" aria-label="Copyright: BY-NC-SA 4.0"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="167" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h80v20H0z"/><path fill="#d42328" d="M80 0h87v20H80z"/><path fill="url(#b)" d="M0 0h167v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><image x="5" y="3" width="14" height="14" xlink:href="data:image/svg+xml;base64,PHN2ZyBmaWxsPSJ3aGl0ZXNtb2tlIiByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48dGl0bGU+Q2xhcmlzPC90aXRsZT48cGF0aCBkPSJNMTEuNTYgMGEzLjM0IDMuMzQgMCAwMC0uNTcuMDQzTDIyLjk0NyAxMiAxMC45OSAyMy45NTdjLjEzMi4wMjIuMzA3LjA0My41Ny4wNDMgNi42MjYgMCAxMi01LjM3NSAxMi0xMnMtNS4zNzQtMTItMTItMTJ6bS0xLjUzNSAyLjQxNEM0LjczOCAyLjQxNC40NCA2LjcxMy40NCAxMnM0LjMgOS41ODggOS41ODYgOS41ODhjLjI2NCAwIC40NC0uMDIzLjU3LS4wNDVMMS4wNTQgMTJsOS41NDMtOS41NDNhMy4zMzcgMy4zMzcgMCAwMC0uNTctLjA0M3ptLjc0NiAyLjQ1N2MtLjI2MyAwLS40MzguMDIxLS41Ny4wNDNMMTcuMjg3IDEybC03LjA4NiA3LjA4NmMuMTMyLjAyMi4zMDcuMDQ1LjU3LjA0NSAzLjkyNyAwIDcuMTMtMy4yMDQgNy4xMy03LjEzMXMtMy4yMDMtNy4xMjktNy4xMy03LjEyOXptLS40MTYgMi40MzRBNC43MDEgNC43MDEgMCAwMDUuNjYgMTJhNC43MDEgNC43MDEgMCAwMDQuNjk1IDQuNjk1Yy4yNjQgMCAuNDQtLjAyMy41Ny0uMDQ1TDYuMjc0IDEybDQuNjUzLTQuNjVhMy4yOTYgMy4yOTYgMCAwMC0uNTctLjA0NVoiLz48L3N2Zz4="/><text aria-hidden="true" x="495" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="530">Copyright</text><text x="495" y="140" transform="scale(.1)" textLength="530">Copyright</text><text aria-hidden="true" x="1225" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="770">BY-NC-SA 4.0</text><text x="1225" y="140" transform="scale(.1)" textLength="770">BY-NC-SA 4.0</text></g></svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="145" height="20" role="img" aria-label="Access: HanAnalytics"><title>Access: HanAnalytics</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="145" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="64" height="20" fill="#f5f5f5"/><rect x="64" width="81" height="20" fill="#454957"/><rect width="145" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><image x="5" y="3" width="14" height="14" xlink:href="data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjM2IzZjRmIiByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48dGl0bGU+QXBhY2hlIFNwYXJrPC90aXRsZT48cGF0aCBkPSJNMTAuODEyIDBjLS40MjUuMDEzLS44NDUuMjE1LTEuMTk2LjYwNWEzLjU5MyAzLjU5MyAwIDAwLS40OTMuNzIyYy0uMzU1LjY2Ny0uNDI1IDEuNDE1LS41NTYgMi4xNDNhNTUxLjkgNTUxLjkgMCAwMC0uNzI2IDQuMDg3Yy0uMDI3LjE2LS4wOTYuMjI3LS4yNDQuMjczQzUuODMgOC4zODYgNC4wNiA4Ljk0IDIuMyA5LjUxNGMtLjM4Ny4xMjUtLjc3My4yODktMS4xMTQuNTA2LTEuMDQyLjY2NS0xLjE5NiAxLjc1My0uNDE1IDIuNzEuMzQ2LjQyMi43OS43MTUgMS4yODQuOTM2IDEuMS40OSAyLjIwMi45NzYgMy4zIDEuNDcuMDE5LjAxLjAzNi4wMTMuMDUzLjAxOWgtLjAwNGwxLjMwNi41MzVjMCAuMDIzLjAwMi4wNDUgMCAuMDczLS4yIDIuMDMtLjM5IDQuMDYzLS41OCA2LjA5NS0uMDQuNDE5LS4wMTIuODMxLjEzNCAxLjIzLjMxNy44NyAxLjA2NSAxLjE0OCAxLjg4MS43MDEuMzcyLS4yMDQuNjY2LS40OTcuOTM3LS44MTggMS4zNzItMS42MjMgMi43NDYtMy4yNDQgNC4xMTMtNC44NzIuMTExLS4xMzMuMjA1LS4xNS4zNjMtLjA5OC4zNDkuMTE3LjY5Ny4yMzEgMS4wNDUuMzQ3aC4wMDFjLjAyLjAxMi4wNDUuMDIuMDczLjAzbC4xNDIuMDQyYzEuMjQ4LjQxNiAyLjY4Ljc3NSAzLjkyOSAxLjE5LjQuMTMyLjYyMi4xNjQgMS4wNDUuMDk4LjMxMS0uMDQ4LjU5Mi0uMDYyLjgyOC0uMjM2LjYwMi0uMzMuOTk1LS45NTcuOTg4LTEuNjgyLS4wMDUtLjQyNy0uMTU0LS44MTMtLjM1LTEuMTg2LS44Mi0xLjU1Ni0xLjYzNy0zLjExMy0yLjQ2MS00LjY2Ni0uMDc4LS4xNDgtLjA3Ni0uMjQzLjAzNy0uMzc1IDEuMzgxLTEuNjE1IDIuNzU2LTMuMjM2IDQuMTMzLTQuODU1LjI3Mi0uMzIuNTEzLS42NTguNjUzLTEuMDU4LjMwOC0uODc4LS4wOS0xLjU3LTEtMS43NDFhMi43ODMgMi43ODMgMCAwMC0xLjIzNS4wNjljLTEuOTc0LjUyMS0zLjk0NyAxLjA0MS01LjkxOCAxLjU3LS4xNzUuMDQ3LS4yNi4wMTUtLjM1NS0uMTQ0YTM1My4wOCAzNTMuMDggMCAwMC0yLjQyMS00LjAxOCA0LjYxIDQuNjEgMCAwMC0uNjUyLS44NDljLS4zNzEtLjM3LS44MDItLjU0OS0xLjIyNy0uNTM2em0uMTcyIDMuNzAzYS41OTIuNTkyIDAgMDEuMTg5LjIxMWMuODcgMS40NDYgMS43NDIgMi44OSAyLjYwOSA0LjMzOC4wNy4xMTguMTM1LjE2LjI3Ny4xMjEgMS41MjUtLjQxIDMuMDUyLS44MTMgNC41NzktMS4yMTcuMzY3LS4wOTguNzM1LS4xOTMgMS4xMDMtLjI4OWEuMzk5LjM5OSAwIDAxLS4xLjJjLTEuMjU5IDEuNDgtMi41MTYgMi45NjItMy43NzkgNC40MzgtLjExLjEzLS4xMi4yMi0uMDQuMzcuOTM3IDEuODAzIDEuNzY4IDMuMzA5IDIuNDk4IDQuNzZsLTMuNjk2LTEuMDE5Yy0uNTM4LS4xOC0xLjA3Ny0uMzU4LTEuNjE1LS41MzktLjE2My0uMDU1LS4yNS0uMDMtLjM2LjEtMS4yNDggMS40ODgtMi41MDQgMi45Ny0zLjc1OSA0LjQ1NGEuMzk4LjM5OCAwIDAxLS4xOC4xMzJjLjAzNS0uMzc4LjA2OC0uNzU3LjEwNC0xLjEzNi4xNDktMS41NzIuMjk3LTMuMTQ0LjQ1MS00LjcxNi0uMDMtLjMxOC4xMTctLjQwNS0uMzIyLS41NDUtMS40OTMtLjU5My0zLjM0Ni0xLjMyMS00LjgxNi0xLjkwNWEuNTk1LjU5NSAwIDAxLjI0LS4xMzRjMS43OTctLjU3IDMuNTk1LTEuMTQgNS4zOTQtMS43MDUuMTI3LS4wNC4xOTktLjA5Mi4yMTEtLjIzMy4wMTMtLjE0OC4wNS0uMjk0LjA3Ni0uNDQxLjI0MS0xLjM2My40ODMtMi43MjYuNzI2LTQuMDg4LjA2OC0uMzg2LjE0LS43NzEuMjEtMS4xNTd6Ii8+PC9zdmc+"/><text aria-hidden="true" x="415" y="150" fill="#ccc" fill-opacity=".3" transform="scale(.1)" textLength="370">Access</text><text x="415" y="140" transform="scale(.1)" fill="#333" textLength="370">Access</text><text aria-hidden="true" x="1035" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="710">HanAnalytics</text><text x="1035" y="140" transform="scale(.1)" fill="#fff" textLength="710">HanAnalytics</text></g></svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="159" height="20" aria-label="浙ICP备2022035705号"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="159" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h68v20H0z"/><path fill="#e1d492" d="M68 0h91v20H68z"/><path fill="url(#b)" d="M0 0h159v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><image x="5" y="3" width="14" height="14" xlink:href="data:image/png;base64,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"/><text aria-hidden="true" x="435" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="410">浙ICP备</text><text x="435" y="140" transform="scale(.1)" textLength="410">浙ICP备</text><text aria-hidden="true" x="1125" y="150" fill="#ccc" fill-opacity=".3" transform="scale(.1)" textLength="810">2022035705号</text><text x="1125" y="140" transform="scale(.1)" fill="#333" textLength="810">2022035705号</text></g></svg>

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="98" height="20" aria-label="小韩: 营业中"><style></style><linearGradient id="a" x2="0" y2="100%"><stop offset="0" stop-color="#fcfcfc" stop-opacity="0"/><stop offset="1" stop-opacity=".1"/></linearGradient><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#ccc" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><g stroke="#d5d5d5"><rect stroke="none" fill="#fcfcfc" x=".5" y=".5" width="50" height="19" rx="2"/><rect x="56.5" y=".5" width="41" height="19" rx="2" fill="#fafafa"/><path stroke="#fafafa" d="M56 7.5h.5v5H56z"/><path d="m56.5 6.5-3 3v1l3 3" stroke="d5d5d5" fill="#fafafa"/></g><image x="5" y="3" width="14" height="14" xlink:href="data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjRDMzQzQzIiByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48dGl0bGU+Q2FrZVBIUDwvdGl0bGU+PHBhdGggZD0iTTAgMTMuODc1djMuNzQ1YzAgMi4wNjcgNS4zNyAzLjc0MyAxMiAzLjc0M1YxNy42MmMtNi42MyAwLTEyLTEuNjgtMTItMy43NDN2LS4wMDJ6bTIxLjM4NCAyLjMzM0wxMiAxMy44NzV2My43NDVsOS4zODQgMi4zMzNDMjMuMDIgMTkuMzEzIDI0IDE4LjUwMyAyNCAxNy42MnYtMy43NDVjMCAuODgyLS45OCAxLjY5Mi0yLjYxNiAyLjMzM3pNMTIgMTAuMTMzdjMuNzQyYy02LjYyNyAwLTEyLTEuNjc3LTEyLTMuNzQ0VjYuMzhjMC0yLjA2NCA1LjM3LTMuNzQzIDEyLTMuNzQzIDYuNjI1IDAgMTIgMS42OCAxMiAzLjc0NHYzLjc1YzAgLjg4My0uOTggMS42OS0yLjYxNiAyLjMzNEwxMiAxMC4xM3YuMDAzeiIvPjwvc3ZnPg=="/><g aria-hidden="true" fill="#333" text-anchor="middle" font-family="Helvetica Neue,Helvetica,Arial,sans-serif" text-rendering="geometricPrecision" font-weight="700" font-size="110"><rect id="llink" stroke="#d5d5d5" fill="url(#a)" x=".5" y=".5" width="50" height="19" rx="2"/><text aria-hidden="true" x="335" y="150" fill="#fff" transform="scale(.1)" textLength="230">小韩</text><text x="335" y="140" transform="scale(.1)" textLength="230">小韩</text><text aria-hidden="true" x="765" y="150" fill="#fff" transform="scale(.1)" textLength="330">营业中</text><text id="rlink" x="765" y="140" transform="scale(.1)" textLength="330">营业中</text></g></svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="105" height="20" aria-label="SEO: Sitemap"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="105" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#c5b9a3" d="M0 0h50v20H0z"/><path fill="#738b71" d="M50 0h55v20H50z"/><path fill="url(#b)" d="M0 0h105v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><image x="5" y="3" width="14" height="14" xlink:href="data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjNTk0ZTM4IiByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48dGl0bGU+UlNTPC90aXRsZT48cGF0aCBkPSJNMTkuMTk5IDI0QzE5LjE5OSAxMy40NjcgMTAuNTMzIDQuOCAwIDQuOFYwYzEzLjE2NSAwIDI0IDEwLjgzNSAyNCAyNGgtNC44MDF6TTMuMjkxIDE3LjQxNWMxLjgxNCAwIDMuMjkzIDEuNDc5IDMuMjkzIDMuMjk1IDAgMS44MTMtMS40ODUgMy4yOS0zLjMwMSAzLjI5QzEuNDcgMjQgMCAyMi41MjYgMCAyMC43MXMxLjQ3NS0zLjI5NCAzLjI5MS0zLjI5NXpNMTUuOTA5IDI0aC00LjY2NWMwLTYuMTY5LTUuMDc1LTExLjI0NS0xMS4yNDQtMTEuMjQ1VjguMDljOC43MjcgMCAxNS45MDkgNy4xODQgMTUuOTA5IDE1LjkxeiIvPjwvc3ZnPg=="/><text aria-hidden="true" x="345" y="150" fill="#ccc" fill-opacity=".3" transform="scale(.1)" textLength="230">SEO</text><text x="345" y="140" transform="scale(.1)" fill="#594E38" textLength="230">SEO</text><text aria-hidden="true" x="765" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="450">Sitemap</text><text x="765" y="140" transform="scale(.1)" textLength="450">Sitemap</text></g></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,2 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="157" height="20" role="img" aria-label="Theme: vhAstro Theme"><title>Theme: vhAstro Theme</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="157" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="64" height="20" fill="#555"/><rect x="64" width="93" height="20" fill="#fff"/><rect width="157" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><image x="5" y="3" width="14" height="14" xlink:href="data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjZmZmIiByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48dGl0bGU+QXN0cm88L3RpdGxlPjxwYXRoIGQ9Ik04LjM1OCAyMC4xNjJjLTEuMTg2LTEuMDctMS41MzItMy4zMTYtMS4wMzgtNC45NDQuODU2IDEuMDI2IDIuMDQzIDEuMzUyIDMuMjcyIDEuNTM1IDEuODk3LjI4MyAzLjc2LjE3NyA1LjUyMi0uNjc4LjIwMi0uMDk4LjM4OC0uMjI5LjYwOC0uMzYuMTY2LjQ3My4yMDkuOTUuMTUxIDEuNDM3LS4xNCAxLjE4NS0uNzM4IDIuMS0xLjY4OCAyLjc5NC0uMzguMjc3LS43ODIuNTI1LTEuMTc1Ljc4Ny0xLjIwNS44MDQtMS41MzEgMS43NDctMS4wNzggMy4xMTlsLjA0NC4xNDhhMy4xNTggMy4xNTggMCAwIDEtMS40MDctMS4xODggMy4zMSAzLjMxIDAgMCAxLS41NDQtMS44MTVjLS4wMDQtLjMyLS4wMDQtLjY0Mi0uMDQ4LS45NTgtLjEwNi0uNzY5LS40NzItMS4xMTMtMS4xNjEtMS4xMzMtLjcwNy0uMDItMS4yNjcuNDExLTEuNDE1IDEuMDktLjAxMi4wNTMtLjAyOC4xMDQtLjA0NS4xNjVoLjAwMnptLTUuOTYxLTQuNDQ1czMuMjQtMS41NzUgNi40OS0xLjU3NWwyLjQ1MS03LjU2NWMuMDkyLS4zNjYuMzYtLjYxNC42NjItLjYxNC4zMDIgMCAuNTcuMjQ4LjY2Mi42MTRsMi40NSA3LjU2NWMzLjg1IDAgNi40OTEgMS41NzUgNi40OTEgMS41NzVMMTYuMDg4LjcyN0MxNS45My4yODUgMTUuNjYzIDAgMTUuMzAzIDBIOC42OTdjLS4zNiAwLS42MTUuMjg1LS43ODQuNzI3bC01LjUxNiAxNC45OXoiLz48L3N2Zz4="/><text aria-hidden="true" x="415" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="370">Theme</text><text x="415" y="140" transform="scale(.1)" fill="#fff" textLength="370">Theme</text><text aria-hidden="true" x="1095" y="150" fill="#ccc" fill-opacity=".3" transform="scale(.1)" textLength="830">vhAstro Theme</text><text x="1095" y="140" transform="scale(.1)" fill="#333" textLength="830">vhAstro Theme</text></g></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -1,7 +1,7 @@
---
// 获取用户配置数据
import SITE_CONFIG from "../config";
import { fmtTime, fmtDate } from "../utils/index";
import { fmtDate } from "../utils/index";
const { Avatar, Author, Motto, WebSites } = SITE_CONFIG;
// 获取文章数据
import { getCategories, getTags, getRecommendArticles } from "../utils/getPostInfo";
@ -78,7 +78,7 @@ import "../styles/components/Aside.less";
</p>
<p class="info">
<span>{(await i).title}</span>
<time>{fmtDate((await i).date)}</time>
<time>{fmtDate((await i).date)}</time>
</p>
</a>
))

View File

@ -3,19 +3,18 @@ import "../styles/components/Comment.less";
---
<section class="vh-comment"><section></section></section>
<script>
import updateRouter from "../utils/updateRouter";
import { LoadScript } from "../utils/index";
import SITE_CONFIG from "../config";
const { Twikoo } = SITE_CONFIG;
import SITE_INFO from "../config";
declare const twikoo: any;
// 初始化评论插件
SITE_INFO.Twikoo.envId &&
updateRouter("afterMount", async () => {
if (!document.querySelector(".vh-comment>section")) return;
await LoadScript("https://registry.npmmirror.com/twikoo/1.6.41/files/dist/twikoo.all.min.js");
twikoo.init({
envId: Twikoo.envId,
envId: SITE_INFO.Twikoo.envId,
el: ".vh-comment>section"
});
});

View File

@ -0,0 +1,17 @@
---
import { fmtDate } from "../utils/index";
// 页面内容的元数据
import SITE_CONFIG from "../config";
const { CreateTime } = SITE_CONFIG;
// 基础 样式
import "../styles/Footer.less";
---
<footer class="vh-footer">
<main>
<p>
<img src="/assets/images/footer/ing.svg" /><span><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> <path fill="#fff" d="M269.4 2.9C265.2 1 260.7 0 256 0s-9.2 1-13.4 2.9L54.3 82.8c-22 9.3-38.4 31-38.3 57.2c.5 99.2 41.3 280.7 213.6 363.2c16.7 8 36.1 8 52.8 0C454.7 420.7 495.5 239.2 496 140c.1-26.2-16.3-47.9-38.3-57.2L269.4 2.9zM144 221.3c0-33.8 27.4-61.3 61.3-61.3c16.2 0 31.8 6.5 43.3 17.9l7.4 7.4 7.4-7.4c11.5-11.5 27.1-17.9 43.3-17.9c33.8 0 61.3 27.4 61.3 61.3c0 16.2-6.5 31.8-17.9 43.3l-82.7 82.7c-6.2 6.2-16.4 6.2-22.6 0l-82.7-82.7c-11.5-11.5-17.9-27.1-17.9-43.3z"></path></svg><cite>稳定运行</cite><em>{fmtDate(CreateTime)}</em></span><a href="https://analytics.vvhan.com" target="_blank" rel="noopener noreferrer"><img src="/assets/images/footer/hananalytics.svg" /></a>
</p>
<p><a href="https://astro.build/" target="_blank" rel="noopener noreferrer"><img src="/assets/images/footer/astro.svg" /></a><a href="#" target="_blank" rel="noopener noreferrer"><img src="/assets/images/footer/theme.svg" /></a><a href="/sitemap-index.xml"><img src="/assets/images/footer/sitemap.svg" /></a><a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener noreferrer"><img src="/assets/images/footer/icp.svg" /></a></p>
</main>
</footer>

View File

@ -23,7 +23,7 @@ import "../styles/components/Pagination.less";
}
<!-- 总页的前一页 -->
{
(!data.next || !data.last) && (
(!data.next || !data.last) && data.prev && (
<a class={`vh-pagination-item`} href={data.prev}>
{fmtPage(data.prev)}
</a>
@ -33,7 +33,7 @@ import "../styles/components/Pagination.less";
<a class="vh-pagination-item active">{fmtPage(data.current) || "1"}</a>
<!-- 第一页的后一页 -->
{
(!data.prev || !data.first) && (
(!data.prev || !data.first) && data.next && (
<a class={`vh-pagination-item`} href={data.next}>
{fmtPage(data.next)}
</a>

View File

@ -38,7 +38,7 @@ export default {
// 博客音乐组件解析接口
vhMusicApi: 'https://meting-dd.2333332.xyz/api',
// 评论组件 Twikoo
Twikoo: {
envId: "https://twikoo.vvhan.com/.netlify/functions/twikoo",
}
Twikoo: { envId: 'https://twikoo.vvhan.com/.netlify/functions/twikoo' },
// Han Analytics 统计https://github.com/uxiaohan/HanAnalytics
HanAnalytics: { enable: true, server: 'https://analytics.vvhan.com', siteId: 'Hello-HanHexoBlog' }
}

View File

@ -5,6 +5,8 @@ const { title, keywords, description, activeNav } = Astro.props;
import Head from "../components/Head.astro";
// 顶部 Header
import Header from "../components/Header.astro";
// 底部 Footer
import Footer from "../components/Footer.astro";
// 返回顶部
import BackTop from "../components/BackTop.astro";
// 手机端侧边栏
@ -24,6 +26,7 @@ import "../styles/Layout.less";
<main class="vh-main">
<slot />
</main>
<Footer />
<BackTop />
<script>
import updateRouter from "../utils/updateRouter";
@ -35,6 +38,10 @@ import "../styles/Layout.less";
import NProgress from "nprogress";
import "nprogress/nprogress.css";
NProgress.configure({ easing: "ease", speed: 500, showSpinner: false, trickleSpeed: 200, minimum: 0.3 });
// Han Analytics 统计
import SITE_INFO from "../config";
const { HanAnalytics } = SITE_INFO;
import { LoadScript } from "../utils/index";
// 初始化 图片懒加载初
updateRouter("afterMount", () => {
// 预加载搜索数据
@ -43,6 +50,8 @@ import "../styles/Layout.less";
vhLzImgInit();
// 进入页面,进度条结束
NProgress.done();
// Han Analytics 统计
HanAnalytics.enable && LoadScript(`${HanAnalytics.server}/tracker.min.js`, [{ k: "data-website-id", v: HanAnalytics.siteId }]);
});
// 离开页面,进度条开始
updateRouter("beforeCreate", NProgress.start);

19
src/page_data/Link.ts Normal file
View File

@ -0,0 +1,19 @@
export default {
// API 接口请求优先,数据格式保持和 data 一致
api: '',
// api 为空则使用 data 静态数据
data: [
{
"name": "韩小韩博客",
"link": "https://www.vvhan.com",
"avatar": "https://q1.qlogo.cn/g?b=qq&nk=1655466387&s=640",
"descr": "运气是计划之外的东西."
},
{
"name": "韩小韩API",
"link": "https://api.vvhan.com",
"avatar": "https://api.vvhan.com/static/images/logo.webp",
"descr": "免费Web API数据接口调用服务平台."
}
]
}

31
src/page_data/Talking.ts Normal file
View File

@ -0,0 +1,31 @@
export default {
// API 接口请求优先,数据格式保持和 data 一致
api: '',
// api 为空则使用 data 静态数据
// 注意:图片请用 vh-img-flex 类包裹
data: [
{
"date": "2025-02-12 19:36:16",
"tags": [
"树",
"夕阳"
],
"content": "好美🌲<p class=\"vh-img-flex\"><img src=\"https://i0.wp.com/shp.qpic.cn/collector/1655466387/937ec070-8448-4c7b-9c8b-abd41ce892cb/0\"></p>"
},
{
"date": "2024-10-08 18:18:18",
"tags": [
"日常",
"工作"
],
"content": "下班!"
},
{
"date": "2024-10-05 16:16:06",
"tags": [
"日常"
],
"content": "记录第一条说说"
}
]
}

View File

@ -1,7 +1,7 @@
---
// 页面 Info
import SITE_CONFIG from "../../config";
const { Description } = SITE_CONFIG;
const { Description, Twikoo } = SITE_CONFIG;
// Aside组件
import Aside from "../../components/Aside.astro";
// 公共 Layout
@ -42,7 +42,7 @@ import "../../styles/About.less";
<a href="https://code.visualstudio.com/" target="_blank" rel="noopener nofollow"><img data-vh-lz-src="https://img.shields.io/badge/VS_Code-007ACC?style=for-the-badge&logo=visual-studio-code&logoColor=white" alt="VS Code" /></a>
</div>
</main>
<Comment />
{Twikoo.envId && <Comment envId={Twikoo.envId} />}
</section>
<Aside />
</section>

View File

@ -1,4 +1,5 @@
---
import { fmtDate } from "../../utils/index";
import { getDescription, fmtTime } from "../../utils/index";
import { type CollectionEntry, getCollection } from "astro:content";
import { render } from "astro:content";
@ -11,6 +12,7 @@ type Props = CollectionEntry<"blog">;
const post: any = Astro.props;
// 页面 Info
import SITE_CONFIG from "../../config";
const { Site, Title, Author, Twikoo } = SITE_CONFIG;
// 处理文章内容
const description = getDescription(post);
const { Content } = await render(post);
@ -34,11 +36,11 @@ import "../../styles/Article.less";
<div class="article-meta">
<span class="article-meta-item">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"> <path d="M152 24c0-13.3-10.7-24-24-24s-24 10.7-24 24l0 40L64 64C28.7 64 0 92.7 0 128l0 16 0 48L0 448c0 35.3 28.7 64 64 64l320 0c35.3 0 64-28.7 64-64l0-256 0-48 0-16c0-35.3-28.7-64-64-64l-40 0 0-40c0-13.3-10.7-24-24-24s-24 10.7-24 24l0 40L152 64l0-40zM48 192l80 0 0 56-80 0 0-56zm0 104l80 0 0 64-80 0 0-64zm128 0l96 0 0 64-96 0 0-64zm144 0l80 0 0 64-80 0 0-64zm80-48l-80 0 0-56 80 0 0 56zm0 160l0 40c0 8.8-7.2 16-16 16l-64 0 0-56 80 0zm-128 0l0 56-96 0 0-56 96 0zm-144 0l0 56-64 0c-8.8 0-16-7.2-16-16l0-40 80 0zM272 248l-96 0 0-56 96 0 0 56z"></path></svg>
<time>{fmtTime(post.data.date, "YYYY-MM-DD")}</time>
<time>{fmtDate(post.data.date)}前</time>
</span>
<span class="article-meta-item">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> <path d="M75 75L41 41C25.9 25.9 0 36.6 0 57.9L0 168c0 13.3 10.7 24 24 24l110.1 0c21.4 0 32.1-25.9 17-41l-30.8-30.8C155 85.5 203 64 256 64c106 0 192 86 192 192s-86 192-192 192c-40.8 0-78.6-12.7-109.7-34.4c-14.5-10.1-34.4-6.6-44.6 7.9s-6.6 34.4 7.9 44.6C151.2 495 201.7 512 256 512c141.4 0 256-114.6 256-256S397.4 0 256 0C185.3 0 121.3 28.7 75 75zm181 53c-13.3 0-24 10.7-24 24l0 104c0 6.4 2.5 12.5 7 17l72 72c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-65-65 0-94.1c0-13.3-10.7-24-24-24z"></path></svg>
<time>{fmtTime(post.data.updated, "YYYY-MM-DD")}</time>
<time>{fmtDate(post.data.updated || post.data.date)}前</time>
</span>
<a class="article-meta-item" href={`/categories/${post.data.categories}`}>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> <path d="M40 48C26.7 48 16 58.7 16 72l0 48c0 13.3 10.7 24 24 24l48 0c13.3 0 24-10.7 24-24l0-48c0-13.3-10.7-24-24-24L40 48zM192 64c-17.7 0-32 14.3-32 32s14.3 32 32 32l288 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L192 64zm0 160c-17.7 0-32 14.3-32 32s14.3 32 32 32l288 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-288 0zm0 160c-17.7 0-32 14.3-32 32s14.3 32 32 32l288 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-288 0zM16 232l0 48c0 13.3 10.7 24 24 24l48 0c13.3 0 24-10.7 24-24l0-48c0-13.3-10.7-24-24-24l-48 0c-13.3 0-24 10.7-24 24zM40 368c-13.3 0-24 10.7-24 24l0 48c0 13.3 10.7 24 24 24l48 0c13.3 0 24-10.7 24-24l0-48c0-13.3-10.7-24-24-24l-48 0z"></path></svg>
@ -47,8 +49,8 @@ import "../../styles/Article.less";
</div>
</header>
<Content />
<Copyright site={SITE_CONFIG.Site} id={post.data.id} title={post.data.title} sitename={SITE_CONFIG.Title} time={fmtTime(post.data.date, "YYYY-MM-DD")} auther={SITE_CONFIG.Author} />
<Comment />
<Copyright site={Site} id={post.data.id} title={post.data.title} sitename={Title} time={fmtTime(post.data.date, "YYYY-MM-DD")} auther={Author} />
{Twikoo.envId && <Comment envId={Twikoo.envId} />}
</article>
<Aside />
</section>

View File

@ -1,7 +1,7 @@
---
// 页面 Info
import SITE_CONFIG from "../../config";
const { Description } = SITE_CONFIG;
const { Description, Twikoo } = SITE_CONFIG;
// Aside组件
import Aside from "../../components/Aside.astro";
// 公共 Layout
@ -20,7 +20,7 @@ import "../../styles/Links.less";
<p>天下快意之事莫若友。</p>
</header>
<main></main>
<Comment />
{Twikoo.envId && <Comment envId={Twikoo.envId} />}
</section>
<Aside />
</section>
@ -29,6 +29,9 @@ import "../../styles/Links.less";
import updateRouter from "../../utils/updateRouter";
import LinksInit from "../../scripts/Links";
// 进入页面时初始化
updateRouter("afterMount", LinksInit);
// 数据源
import LINKS_DATA from "../../page_data/Link";
const { api, data } = LINKS_DATA;
updateRouter("afterMount", () => LinksInit(api || data));
</script>
</Layout>

View File

@ -1,7 +1,7 @@
---
// 页面 Info
import SITE_CONFIG from "../../config";
const { Description } = SITE_CONFIG;
const { Description, Twikoo } = SITE_CONFIG;
// Aside组件
import Aside from "../../components/Aside.astro";
// 公共 Layout
@ -17,7 +17,7 @@ import Comment from "../../components/Comment.astro";
<h1>留言板 🌸</h1>
<p>快友之事莫若谈。</p>
</header>
<Comment />
{Twikoo.envId && <Comment envId={Twikoo.envId} />}
</section>
<Aside />
</section>

View File

@ -1,7 +1,7 @@
---
// 页面 Info
import SITE_CONFIG from "../../config";
const { Description } = SITE_CONFIG;
const { Description, Twikoo } = SITE_CONFIG;
// Aside组件
import Aside from "../../components/Aside.astro";
// 公共 Layout
@ -20,7 +20,7 @@ import "../../styles/Talking.less";
<p>记录美好生活.</p>
</header>
<main></main>
<Comment />
{Twikoo.envId && <Comment envId={Twikoo.envId} />}
</section>
<Aside />
</section>
@ -29,6 +29,9 @@ import "../../styles/Talking.less";
import updateRouter from "../../utils/updateRouter";
import TalkingInit from "../../scripts/Talking";
// 进入页面时初始化
updateRouter("afterMount", TalkingInit);
// 数据源
import TALKING_DATA from "../../page_data/Talking";
const { api, data } = TALKING_DATA;
updateRouter("afterMount", () => TalkingInit(api || data));
</script>
</Layout>

View File

@ -4,12 +4,15 @@ import { $GET } from '../utils/index'
// 图片懒加载
import vhLzImgInit from "../scripts/vhLazyImg";
const LinksInit = async () => {
const LinksInit = async (data: any) => {
const linksDOM = document.querySelector('.vh-container>.vh-links>main')
if (!linksDOM) return;
vh.showLoading();
try {
const res = await $GET('https://tools-api.vvhan.com/blog/link');
let res = data;
if (typeof data === 'string') {
res = await $GET(data);
}
linksDOM.innerHTML = res.map((i: any) => `<a href="${i.link}" target="_blank"><img class="avatar" src="${i.avatar}" /><section class="link-info"><span>${i.name}</span><p>${i.descr}</p></section></a>`).join('');
// 图片懒加载
vhLzImgInit();

View File

@ -1,5 +1,6 @@
import vh from 'vh-plugin'
import { fmtDate } from '../utils/index'
import { $GET } from '../utils/index'
// 图片懒加载
import vhLzImgInit from "../scripts/vhLazyImg";
@ -8,13 +9,16 @@ import "../../public/assets/js/view-image.min.js";
declare const ViewImage: any;
// 灯箱JS初始化======
const TalkingInit = async () => {
const TalkingInit = async (data: any) => {
const talkingDOM = document.querySelector('.vh-container>.vh-talking>main')
if (!talkingDOM) return;
vh.showLoading();
try {
const res = await $GET('https://tools-api.vvhan.com/blog/feeling');
talkingDOM.innerHTML = res.map((i: any) => `<article><header><img data-vh-lz-src="https://q1.qlogo.cn/g?b=qq&nk=1655466387&s=640" /><p class="info"><span>.𝙃𝙖𝙣</span><time>${i.date}</time></p></header><section class="main">${i.content}</section><footer>${i.tags.map((tag: any) => `<span>${tag}</span>`).join('')}</footer></article>`).join('');
let res = data;
if (typeof data === 'string') {
res = await $GET(data);
}
talkingDOM.innerHTML = res.map((i: any) => `<article><header><img data-vh-lz-src="https://q1.qlogo.cn/g?b=qq&nk=1655466387&s=640" /><p class="info"><span>.𝙃𝙖𝙣</span><time>${fmtDate(i.date)}</time></p></header><section class="main">${i.content}</section><footer>${i.tags.map((tag: any) => `<span>${tag}</span>`).join('')}</footer></article>`).join('');
// 图片懒加载
vhLzImgInit();
// 灯箱JS初始化======

View File

@ -3,7 +3,8 @@
:root {
--vh-animation-delay: 0ms;
--vh-padding-top: calc(66px + 1rem);
--vh-back-top: calc((calc(100vw - 2rem) - min((100vw - 2rem), 1388px)) / 2 + 1rem);
--vh-main-max-width: 1388px;
--vh-back-top: calc((calc(100vw - 2rem) - min((100vw - 2rem), var(--vh-main-max-width))) / 2 + 1rem);
}
h1,

116
src/styles/Footer.less Normal file
View File

@ -0,0 +1,116 @@
.vh-footer {
margin-top: 1.68rem;
box-sizing: border-box;
padding: 2.6rem 0;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: max-content;
background: rgba(255, 255, 255, 0.1);
backdrop-filter: saturate(100%) blur(2px);
user-select: none;
&>main {
box-sizing: border-box;
display: flex;
flex-direction: column;
gap: 0.618rem;
width: 100%;
max-width: var(--vh-main-max-width);
height: max-content;
&>p {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
gap: 0.618rem;
line-height: 1;
&>a {
line-height: 1;
}
&>span {
box-sizing: border-box;
padding-left: 0.28rem;
display: flex;
align-items: center;
width: max-content;
height: 1.25rem;
background: #25C2A0;
font-size: 0.68rem;
border-radius: 0.18rem;
overflow: hidden;
&>cite,
&>em {
box-sizing: border-box;
padding: 0 0.618rem;
width: max-content;
height: 100%;
line-height: 1.25rem;
color: #fff;
font-style: normal;
}
&>cite {
padding-left: 0.28rem;
}
&>em {
background: #5D5D5D;
}
&>svg {
width: 0.88rem;
height: 0.88rem;
}
}
}
}
&>section {
box-sizing: border-box;
display: flex;
flex-direction: column;
gap: 0.88rem;
width: 100%;
height: max-content;
p {
line-height: 1;
a {
line-height: 1;
}
}
&.text {
&>p {
font-size: 0.88rem;
&>a {
color: #94A3B8;
transition: opacity 0.16s ease-in-out;
&:hover {
opacity: 0.88;
}
}
}
}
&.icon {
&>p {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 1rem;
}
}
}
}

View File

@ -16,13 +16,12 @@ body {
flex-direction: column;
gap: 1rem;
width: 100%;
max-width: 1388px;
max-width: var(--vh-main-max-width);
height: max-content;
&>section.vh-container {
position: relative;
box-sizing: border-box;
padding-bottom: 5.66rem;
display: flex;
flex-direction: row-reverse;
gap: 1.8rem;

View File

@ -6,6 +6,7 @@ section.article-list {
grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
gap: 1.6rem;
width: 100%;
height: max-content;
overflow: hidden;
&>.vh-article-item {

View File

@ -24,7 +24,7 @@ header.vh-header {
justify-content: space-between;
width: 100%;
height: 80%;
max-width: 1388px;
max-width: var(--vh-main-max-width);
a,
span.nav-btn-item {

View File

@ -4,41 +4,55 @@ const getDescription = (post: any, num: number = 150) => (post.rendered ? post.r
//处理时间
const fmtTime = (time: any, fmt: string = 'MMMM D, YYYY') => dayjs(time).format(fmt)
// 处理日期
const fmtDate = (time: any) => {
const past = dayjs(time);
const now = dayjs();
const duration = now.diff(past, 'seconds');
if (duration < 60) {
return `${duration} 秒前`;
} else if (duration < 60 * 60) {
const minutes = Math.floor(duration / 60);
return `${minutes} 分钟前`;
} else if (duration < 60 * 60 * 24) {
const hours = Math.floor(duration / (60 * 60));
return `${hours} 小时前`;
} else if (duration < 60 * 60 * 24 * 30) {
const days = Math.floor(duration / (60 * 60 * 24));
return `${days} 天前`;
} else if (duration < 60 * 60 * 24 * 30 * 12) {
const months = Math.floor(duration / (60 * 60 * 24 * 30));
return `${months} 个月前`;
} else {
const years = Math.floor(duration / (60 * 60 * 24 * 30 * 12));
return `${years} 年前`;
}
const fmtDate = (time: string | Date) => {
const now = dayjs()
const past = dayjs(time)
// 计算时间差组件
const years = now.diff(past, 'year')
const months = now.diff(past.add(years, 'year'), 'month')
const days = now.diff(past.add(years, 'year').add(months, 'month'), 'day')
const hours = now.diff(past, 'hour')
const minutes = now.diff(past, 'minute')
const seconds = now.diff(past, 'second')
// 构建时间差描述
return [
years && `${years}`,
months && `${months}`,
days && `${days}`,
!years && !months && hours && `${hours}小时`,
!years && !months && !days && minutes && `${minutes}分钟`,
!years && !months && !days && !hours && `${seconds}`
].filter(Boolean).join('')
}
// 处理页码展示
const fmtPage = (page: string | undefined) => page ? page.replace(/\//g, '') : null
// 加载外部脚本
const LoadScript = (src: string): Promise<HTMLScriptElement> => {
const LoadScript = (
src: string,
attrs?: Array<{ k: string; v: string | boolean }>
): Promise<HTMLScriptElement> => {
return new Promise((resolve, reject) => {
const script = document.createElement("script");
script.src = src;
// 添加自定义属性
if (attrs?.length) {
attrs.forEach(({ k, v }) => {
// 处理不同值类型
const value = typeof v === "boolean"
? (v ? "" : null) // 布尔值处理为 HTML 标准属性格式
: String(v); // 其他类型转为字符串
if (value !== null) {
script.setAttribute(k, value);
}
});
}
script.onload = () => resolve(script);
script.onerror = () => reject(new Error(`Failed to load script: ${src}`));
document.head.appendChild(script);
});
}
};
// 加载外部CSS
const LoadStyle = (href: string): Promise<HTMLLinkElement> => {
return new Promise((resolve, reject) => {