style: biome

优化访客统计动画逻辑
This commit is contained in:
二叉树树
2026-01-01 21:39:51 +08:00
parent 82bbc7c598
commit bb4aacb07b
164 changed files with 3945 additions and 3078 deletions

View File

@@ -1,18 +1,26 @@
import sitemap from "@astrojs/sitemap"; import sitemap from "@astrojs/sitemap";
import svelte from "@astrojs/svelte"; import svelte from "@astrojs/svelte";
import tailwind from "@astrojs/tailwind"; import tailwind from "@astrojs/tailwind";
import { pluginCollapsibleSections } from "@expressive-code/plugin-collapsible-sections";
import { pluginLineNumbers } from "@expressive-code/plugin-line-numbers";
import swup from "@swup/astro"; import swup from "@swup/astro";
import expressiveCode from "astro-expressive-code";
import icon from "astro-icon"; import icon from "astro-icon";
import { defineConfig } from "astro/config"; import { defineConfig } from "astro/config";
import { defineConfig, passthroughImageService } from "astro/config";
import rehypeAutolinkHeadings from "rehype-autolink-headings"; import rehypeAutolinkHeadings from "rehype-autolink-headings";
import rehypeComponents from "rehype-components";/* Render the custom directive content */ import rehypeComponents from "rehype-components"; /* Render the custom directive content */
import rehypeExternalLinks from "rehype-external-links";
import rehypeKatex from "rehype-katex"; import rehypeKatex from "rehype-katex";
import rehypeSlug from "rehype-slug"; import rehypeSlug from "rehype-slug";
import remarkDirective from "remark-directive";/* Handle directives */ import remarkDirective from "remark-directive"; /* Handle directives */
import remarkGithubAdmonitionsToDirectives from "remark-github-admonitions-to-directives"; import remarkGithubAdmonitionsToDirectives from "remark-github-admonitions-to-directives";
import remarkMath from "remark-math"; import remarkMath from "remark-math";
import remarkSectionize from "remark-sectionize"; import remarkSectionize from "remark-sectionize";
import { imageFallbackConfig, siteConfig } from "./src/config.ts"; import { imageFallbackConfig, siteConfig } from "./src/config.ts";
import { expressiveCodeConfig } from "./src/config.ts";
// import { pluginLanguageBadge } from "./src/plugins/expressive-code/language-badge.ts";
import { pluginCustomCopyButton } from "./src/plugins/expressive-code/custom-copy-button.js";
import { AdmonitionComponent } from "./src/plugins/rehype-component-admonition.mjs"; import { AdmonitionComponent } from "./src/plugins/rehype-component-admonition.mjs";
import { GithubCardComponent } from "./src/plugins/rehype-component-github-card.mjs"; import { GithubCardComponent } from "./src/plugins/rehype-component-github-card.mjs";
import { UrlCardComponent } from "./src/plugins/rehype-component-url-card.mjs"; import { UrlCardComponent } from "./src/plugins/rehype-component-url-card.mjs";
@@ -20,19 +28,11 @@ import rehypeImageFallback from "./src/plugins/rehype-image-fallback.mjs";
import { parseDirectiveNode } from "./src/plugins/remark-directive-rehype.js"; import { parseDirectiveNode } from "./src/plugins/remark-directive-rehype.js";
import { remarkExcerpt } from "./src/plugins/remark-excerpt.js"; import { remarkExcerpt } from "./src/plugins/remark-excerpt.js";
import { remarkReadingTime } from "./src/plugins/remark-reading-time.mjs"; import { remarkReadingTime } from "./src/plugins/remark-reading-time.mjs";
import rehypeExternalLinks from 'rehype-external-links';
import expressiveCode from "astro-expressive-code";
import { pluginCollapsibleSections } from "@expressive-code/plugin-collapsible-sections";
import { pluginLineNumbers } from "@expressive-code/plugin-line-numbers";
import { expressiveCodeConfig } from "./src/config.ts";
// import { pluginLanguageBadge } from "./src/plugins/expressive-code/language-badge.ts";
import { pluginCustomCopyButton } from "./src/plugins/expressive-code/custom-copy-button.js";
import { defineConfig, passthroughImageService } from 'astro/config';
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
image: { image: {
service: passthroughImageService() service: passthroughImageService(),
}, },
site: "https://blog.acofork.com", site: "https://blog.acofork.com",
base: "/", base: "/",
@@ -40,9 +40,11 @@ export default defineConfig({
output: "static", output: "static",
redirects: { redirects: {
"/donate": "/sponsors", "/donate": "/sponsors",
"/ak": "https://akile.io/register?aff_code=503fe5ea-e7c5-4d68-ae05-6de99513680e", "/ak":
"https://akile.io/register?aff_code=503fe5ea-e7c5-4d68-ae05-6de99513680e",
"/kook": "https://kook.vip/K29zpT", "/kook": "https://kook.vip/K29zpT",
"/long": "https://iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii.iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii.in/", "/long":
"https://iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii.iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii.in/",
"/mly": "https://muleyun.com/aff/GOTRJLPN", "/mly": "https://muleyun.com/aff/GOTRJLPN",
"/tg": "https://t.me/+_07DERp7k1ljYTc1", "/tg": "https://t.me/+_07DERp7k1ljYTc1",
"/tit": "/posts/pin/", "/tit": "/posts/pin/",
@@ -50,11 +52,14 @@ export default defineConfig({
"/wly": "https://wl.awcmam.com/#/register?code=FNQwOQBM", "/wly": "https://wl.awcmam.com/#/register?code=FNQwOQBM",
"/yyb": "https://www.rainyun.com/acofork_?s=bilibili", "/yyb": "https://www.rainyun.com/acofork_?s=bilibili",
"/iku": "https://ikuuu.de/auth/register?code=Bjou", "/iku": "https://ikuuu.de/auth/register?code=Bjou",
"/esa": "https://tianchi.aliyun.com/specials/promotion/freetier/esa?taskCode=25254&recordId=c856e61228828a0423417a767828d166" "/esa":
"https://tianchi.aliyun.com/specials/promotion/freetier/esa?taskCode=25254&recordId=c856e61228828a0423417a767828d166",
}, },
integrations: [tailwind({ integrations: [
tailwind({
nesting: true, nesting: true,
}), swup({ }),
swup({
theme: false, theme: false,
animationClass: "transition-swup-", // see https://swup.js.org/options/#animationselector animationClass: "transition-swup-", // see https://swup.js.org/options/#animationselector
// the default value `transition-` cause transition delay // the default value `transition-` cause transition delay
@@ -67,7 +72,8 @@ export default defineConfig({
updateHead: true, updateHead: true,
updateBodyClass: false, updateBodyClass: false,
globalInstance: true, globalInstance: true,
}), icon({ }),
icon({
include: { include: {
"preprocess: vitePreprocess(),": ["*"], "preprocess: vitePreprocess(),": ["*"],
"fa6-brands": ["*"], "fa6-brands": ["*"],
@@ -77,19 +83,21 @@ export default defineConfig({
"material-symbols-light": ["*"], "material-symbols-light": ["*"],
"material-symbols": ["*"], "material-symbols": ["*"],
}, },
}), svelte(), sitemap(), }),
svelte(),
sitemap(),
expressiveCode({ expressiveCode({
themes: [expressiveCodeConfig.theme, expressiveCodeConfig.theme], themes: [expressiveCodeConfig.theme, expressiveCodeConfig.theme],
plugins: [ plugins: [
pluginCollapsibleSections(), pluginCollapsibleSections(),
pluginLineNumbers(), pluginLineNumbers(),
// pluginLanguageBadge(), // pluginLanguageBadge(),
pluginCustomCopyButton() pluginCustomCopyButton(),
], ],
defaultProps: { defaultProps: {
wrap: true, wrap: true,
overridesByLang: { overridesByLang: {
'shellsession': { shellsession: {
showLineNumbers: false, showLineNumbers: false,
}, },
}, },
@@ -99,7 +107,8 @@ export default defineConfig({
borderRadius: "0.25rem", borderRadius: "0.25rem",
borderColor: "none", borderColor: "none",
codeFontSize: "0.875rem", codeFontSize: "0.875rem",
codeFontFamily: "'JetBrains Mono Variable', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace", codeFontFamily:
"'JetBrains Mono Variable', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace",
codeLineHeight: "1.5rem", codeLineHeight: "1.5rem",
frames: { frames: {
editorBackground: "var(--codeblock-bg)", editorBackground: "var(--codeblock-bg)",
@@ -110,17 +119,17 @@ export default defineConfig({
editorActiveTabIndicatorBottomColor: "var(--primary)", editorActiveTabIndicatorBottomColor: "var(--primary)",
editorActiveTabIndicatorTopColor: "none", editorActiveTabIndicatorTopColor: "none",
editorTabBarBorderBottomColor: "var(--codeblock-topbar-bg)", editorTabBarBorderBottomColor: "var(--codeblock-topbar-bg)",
terminalTitlebarBorderBottomColor: "none" terminalTitlebarBorderBottomColor: "none",
}, },
textMarkers: { textMarkers: {
delHue: 0, delHue: 0,
insHue: 180, insHue: 180,
markHue: 250 markHue: 250,
} },
}, },
frames: { frames: {
showCopyToClipboardButton: false, showCopyToClipboardButton: false,
} },
}), }),
], ],
markdown: { markdown: {
@@ -154,7 +163,7 @@ export default defineConfig({
[ [
rehypeExternalLinks, rehypeExternalLinks,
{ {
target: '_blank', target: "_blank",
}, },
], ],
[ [

View File

@@ -7,7 +7,14 @@
}, },
"files": { "files": {
"ignoreUnknown": false, "ignoreUnknown": false,
"ignore": ["src/**/*.css","src/public/**/*", "dist/**/*", "node_modules/**/*"] "ignore": [
"src/**/*.css",
"public/**/*",
".astro/**/*",
"src/content/.obsidian/**/*",
"dist/**/*",
"node_modules/**/*"
]
}, },
"formatter": { "formatter": {
"enabled": true, "enabled": true,

View File

@@ -16,6 +16,7 @@
}, },
"dependencies": { "dependencies": {
"@astrojs/check": "^0.9.4", "@astrojs/check": "^0.9.4",
"@astrojs/react": "^4.4.2",
"@astrojs/rss": "^4.0.11", "@astrojs/rss": "^4.0.11",
"@astrojs/sitemap": "^3.3.1", "@astrojs/sitemap": "^3.3.1",
"@astrojs/svelte": "7.0.12", "@astrojs/svelte": "7.0.12",
@@ -27,6 +28,7 @@
"@fancyapps/ui": "^6.0.5", "@fancyapps/ui": "^6.0.5",
"@fontsource-variable/jetbrains-mono": "^5.2.5", "@fontsource-variable/jetbrains-mono": "^5.2.5",
"@fontsource/roboto": "^5.2.5", "@fontsource/roboto": "^5.2.5",
"@gsap/react": "^2.1.2",
"@iconify-json/fa6-brands": "^1.2.5", "@iconify-json/fa6-brands": "^1.2.5",
"@iconify-json/fa6-regular": "^1.2.3", "@iconify-json/fa6-regular": "^1.2.3",
"@iconify-json/fa6-solid": "^1.2.3", "@iconify-json/fa6-solid": "^1.2.3",
@@ -35,11 +37,14 @@
"@iconify/svelte": "^4.2.0", "@iconify/svelte": "^4.2.0",
"@swup/astro": "^1.6.0", "@swup/astro": "^1.6.0",
"@tailwindcss/typography": "^0.5.16", "@tailwindcss/typography": "^0.5.16",
"@types/react": "^19.2.7",
"@types/react-dom": "^19.2.3",
"@vercel/analytics": "^1.5.0", "@vercel/analytics": "^1.5.0",
"astro": "5.7.9", "astro": "5.7.9",
"astro-expressive-code": "^0.41.3", "astro-expressive-code": "^0.41.3",
"astro-icon": "^1.1.5", "astro-icon": "^1.1.5",
"glob": "^11.0.3", "glob": "^11.0.3",
"gsap": "^3.14.2",
"hastscript": "^9.0.1", "hastscript": "^9.0.1",
"katex": "^0.16.22", "katex": "^0.16.22",
"markdown-it": "^14.1.0", "markdown-it": "^14.1.0",
@@ -47,6 +52,8 @@
"node-html-parser": "^7.0.1", "node-html-parser": "^7.0.1",
"overlayscrollbars": "^2.11.1", "overlayscrollbars": "^2.11.1",
"photoswipe": "^5.4.4", "photoswipe": "^5.4.4",
"react": "^19.2.3",
"react-dom": "^19.2.3",
"reading-time": "^1.5.0", "reading-time": "^1.5.0",
"rehype-autolink-headings": "^7.1.0", "rehype-autolink-headings": "^7.1.0",
"rehype-components": "^0.3.0", "rehype-components": "^0.3.0",

434
pnpm-lock.yaml generated
View File

@@ -16,6 +16,9 @@ importers:
'@astrojs/check': '@astrojs/check':
specifier: ^0.9.4 specifier: ^0.9.4
version: 0.9.4(typescript@5.8.3) version: 0.9.4(typescript@5.8.3)
'@astrojs/react':
specifier: ^4.4.2
version: 4.4.2(@types/node@22.14.1)(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(jiti@1.21.7)(lightningcss@1.29.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.80.4)(stylus@0.64.0)(terser@5.39.0)(yaml@2.7.0)
'@astrojs/rss': '@astrojs/rss':
specifier: ^4.0.11 specifier: ^4.0.11
version: 4.0.11 version: 4.0.11
@@ -30,7 +33,7 @@ importers:
version: 6.0.2(astro@5.7.9(patch_hash=ysrllw3gj6hylybllnynya5oma)(@types/node@22.14.1)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@2.79.2)(sass@1.80.4)(stylus@0.64.0)(terser@5.39.0)(typescript@5.8.3)(yaml@2.7.0))(tailwindcss@3.4.17) version: 6.0.2(astro@5.7.9(patch_hash=ysrllw3gj6hylybllnynya5oma)(@types/node@22.14.1)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@2.79.2)(sass@1.80.4)(stylus@0.64.0)(terser@5.39.0)(typescript@5.8.3)(yaml@2.7.0))(tailwindcss@3.4.17)
'@astrojs/vercel': '@astrojs/vercel':
specifier: ^8.2.7 specifier: ^8.2.7
version: 8.2.7(astro@5.7.9(patch_hash=ysrllw3gj6hylybllnynya5oma)(@types/node@22.14.1)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@2.79.2)(sass@1.80.4)(stylus@0.64.0)(terser@5.39.0)(typescript@5.8.3)(yaml@2.7.0))(rollup@2.79.2)(svelte@5.28.2) version: 8.2.7(astro@5.7.9(patch_hash=ysrllw3gj6hylybllnynya5oma)(@types/node@22.14.1)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@2.79.2)(sass@1.80.4)(stylus@0.64.0)(terser@5.39.0)(typescript@5.8.3)(yaml@2.7.0))(react@19.2.3)(rollup@2.79.2)(svelte@5.28.2)
'@expressive-code/core': '@expressive-code/core':
specifier: ^0.41.3 specifier: ^0.41.3
version: 0.41.3 version: 0.41.3
@@ -49,6 +52,9 @@ importers:
'@fontsource/roboto': '@fontsource/roboto':
specifier: ^5.2.5 specifier: ^5.2.5
version: 5.2.5 version: 5.2.5
'@gsap/react':
specifier: ^2.1.2
version: 2.1.2(gsap@3.14.2)(react@19.2.3)
'@iconify-json/fa6-brands': '@iconify-json/fa6-brands':
specifier: ^1.2.5 specifier: ^1.2.5
version: 1.2.5 version: 1.2.5
@@ -73,9 +79,15 @@ importers:
'@tailwindcss/typography': '@tailwindcss/typography':
specifier: ^0.5.16 specifier: ^0.5.16
version: 0.5.16(tailwindcss@3.4.17) version: 0.5.16(tailwindcss@3.4.17)
'@types/react':
specifier: ^19.2.7
version: 19.2.7
'@types/react-dom':
specifier: ^19.2.3
version: 19.2.3(@types/react@19.2.7)
'@vercel/analytics': '@vercel/analytics':
specifier: ^1.5.0 specifier: ^1.5.0
version: 1.5.0(svelte@5.28.2) version: 1.5.0(react@19.2.3)(svelte@5.28.2)
astro: astro:
specifier: 5.7.9 specifier: 5.7.9
version: 5.7.9(patch_hash=ysrllw3gj6hylybllnynya5oma)(@types/node@22.14.1)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@2.79.2)(sass@1.80.4)(stylus@0.64.0)(terser@5.39.0)(typescript@5.8.3)(yaml@2.7.0) version: 5.7.9(patch_hash=ysrllw3gj6hylybllnynya5oma)(@types/node@22.14.1)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@2.79.2)(sass@1.80.4)(stylus@0.64.0)(terser@5.39.0)(typescript@5.8.3)(yaml@2.7.0)
@@ -88,6 +100,9 @@ importers:
glob: glob:
specifier: ^11.0.3 specifier: ^11.0.3
version: 11.0.3 version: 11.0.3
gsap:
specifier: ^3.14.2
version: 3.14.2
hastscript: hastscript:
specifier: ^9.0.1 specifier: ^9.0.1
version: 9.0.1 version: 9.0.1
@@ -109,6 +124,12 @@ importers:
photoswipe: photoswipe:
specifier: ^5.4.4 specifier: ^5.4.4
version: 5.4.4 version: 5.4.4
react:
specifier: ^19.2.3
version: 19.2.3
react-dom:
specifier: ^19.2.3
version: 19.2.3(react@19.2.3)
reading-time: reading-time:
specifier: ^1.5.0 specifier: ^1.5.0
version: 1.5.0 version: 1.5.0
@@ -248,6 +269,15 @@ packages:
resolution: {integrity: sha512-GilTHKGCW6HMq7y3BUv9Ac7GMe/MO9gi9GW62GzKtth0SwukCu/qp2wLiGpEujhY+VVhaG9v7kv/5vFzvf4NYw==} resolution: {integrity: sha512-GilTHKGCW6HMq7y3BUv9Ac7GMe/MO9gi9GW62GzKtth0SwukCu/qp2wLiGpEujhY+VVhaG9v7kv/5vFzvf4NYw==}
engines: {node: ^18.17.1 || ^20.3.0 || >=22.0.0} engines: {node: ^18.17.1 || ^20.3.0 || >=22.0.0}
'@astrojs/react@4.4.2':
resolution: {integrity: sha512-1tl95bpGfuaDMDn8O3x/5Dxii1HPvzjvpL2YTuqOOrQehs60I2DKiDgh1jrKc7G8lv+LQT5H15V6QONQ+9waeQ==}
engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0}
peerDependencies:
'@types/react': ^17.0.50 || ^18.0.21 || ^19.0.0
'@types/react-dom': ^17.0.17 || ^18.0.6 || ^19.0.0
react: ^17.0.2 || ^18.0.0 || ^19.0.0
react-dom: ^17.0.2 || ^18.0.0 || ^19.0.0
'@astrojs/rss@4.0.11': '@astrojs/rss@4.0.11':
resolution: {integrity: sha512-3e3H8i6kc97KGnn9iaZBJpIkdoQi8MmR5zH5R+dWsfCM44lLTszOqy1OBfGGxDt56mpQkYVtZJWoxMyWuUZBfw==} resolution: {integrity: sha512-3e3H8i6kc97KGnn9iaZBJpIkdoQi8MmR5zH5R+dWsfCM44lLTszOqy1OBfGGxDt56mpQkYVtZJWoxMyWuUZBfw==}
@@ -287,18 +317,34 @@ packages:
resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
'@babel/code-frame@7.27.1':
resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
engines: {node: '>=6.9.0'}
'@babel/compat-data@7.26.8': '@babel/compat-data@7.26.8':
resolution: {integrity: sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==} resolution: {integrity: sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
'@babel/compat-data@7.28.5':
resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==}
engines: {node: '>=6.9.0'}
'@babel/core@7.26.10': '@babel/core@7.26.10':
resolution: {integrity: sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==} resolution: {integrity: sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
'@babel/core@7.28.5':
resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==}
engines: {node: '>=6.9.0'}
'@babel/generator@7.27.0': '@babel/generator@7.27.0':
resolution: {integrity: sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==} resolution: {integrity: sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
'@babel/generator@7.28.5':
resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==}
engines: {node: '>=6.9.0'}
'@babel/helper-annotate-as-pure@7.25.9': '@babel/helper-annotate-as-pure@7.25.9':
resolution: {integrity: sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==} resolution: {integrity: sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
@@ -307,6 +353,10 @@ packages:
resolution: {integrity: sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA==} resolution: {integrity: sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
'@babel/helper-compilation-targets@7.27.2':
resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==}
engines: {node: '>=6.9.0'}
'@babel/helper-create-class-features-plugin@7.27.0': '@babel/helper-create-class-features-plugin@7.27.0':
resolution: {integrity: sha512-vSGCvMecvFCd/BdpGlhpXYNhhC4ccxyvQWpbGL4CWbvfEoLFWUZuSuf7s9Aw70flgQF+6vptvgK2IfOnKlRmBg==} resolution: {integrity: sha512-vSGCvMecvFCd/BdpGlhpXYNhhC4ccxyvQWpbGL4CWbvfEoLFWUZuSuf7s9Aw70flgQF+6vptvgK2IfOnKlRmBg==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
@@ -324,6 +374,10 @@ packages:
peerDependencies: peerDependencies:
'@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0
'@babel/helper-globals@7.28.0':
resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==}
engines: {node: '>=6.9.0'}
'@babel/helper-member-expression-to-functions@7.25.9': '@babel/helper-member-expression-to-functions@7.25.9':
resolution: {integrity: sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==} resolution: {integrity: sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
@@ -332,12 +386,22 @@ packages:
resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
'@babel/helper-module-imports@7.27.1':
resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==}
engines: {node: '>=6.9.0'}
'@babel/helper-module-transforms@7.26.0': '@babel/helper-module-transforms@7.26.0':
resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
peerDependencies: peerDependencies:
'@babel/core': ^7.0.0 '@babel/core': ^7.0.0
'@babel/helper-module-transforms@7.28.3':
resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0
'@babel/helper-optimise-call-expression@7.25.9': '@babel/helper-optimise-call-expression@7.25.9':
resolution: {integrity: sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==} resolution: {integrity: sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
@@ -346,6 +410,10 @@ packages:
resolution: {integrity: sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==} resolution: {integrity: sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
'@babel/helper-plugin-utils@7.27.1':
resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==}
engines: {node: '>=6.9.0'}
'@babel/helper-remap-async-to-generator@7.25.9': '@babel/helper-remap-async-to-generator@7.25.9':
resolution: {integrity: sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==} resolution: {integrity: sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
@@ -378,10 +446,18 @@ packages:
resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
'@babel/helper-validator-identifier@7.28.5':
resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
engines: {node: '>=6.9.0'}
'@babel/helper-validator-option@7.25.9': '@babel/helper-validator-option@7.25.9':
resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
'@babel/helper-validator-option@7.27.1':
resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
engines: {node: '>=6.9.0'}
'@babel/helper-wrap-function@7.25.9': '@babel/helper-wrap-function@7.25.9':
resolution: {integrity: sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==} resolution: {integrity: sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
@@ -390,6 +466,10 @@ packages:
resolution: {integrity: sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==} resolution: {integrity: sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
'@babel/helpers@7.28.4':
resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==}
engines: {node: '>=6.9.0'}
'@babel/parser@7.27.0': '@babel/parser@7.27.0':
resolution: {integrity: sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==} resolution: {integrity: sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==}
engines: {node: '>=6.0.0'} engines: {node: '>=6.0.0'}
@@ -400,6 +480,11 @@ packages:
engines: {node: '>=6.0.0'} engines: {node: '>=6.0.0'}
hasBin: true hasBin: true
'@babel/parser@7.28.5':
resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==}
engines: {node: '>=6.0.0'}
hasBin: true
'@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.9': '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.9':
resolution: {integrity: sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==} resolution: {integrity: sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
@@ -723,6 +808,18 @@ packages:
peerDependencies: peerDependencies:
'@babel/core': ^7.0.0-0 '@babel/core': ^7.0.0-0
'@babel/plugin-transform-react-jsx-self@7.27.1':
resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
'@babel/plugin-transform-react-jsx-source@7.27.1':
resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
'@babel/plugin-transform-react-jsx@7.25.9': '@babel/plugin-transform-react-jsx@7.25.9':
resolution: {integrity: sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw==} resolution: {integrity: sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
@@ -838,10 +935,18 @@ packages:
resolution: {integrity: sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==} resolution: {integrity: sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
'@babel/template@7.27.2':
resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==}
engines: {node: '>=6.9.0'}
'@babel/traverse@7.27.0': '@babel/traverse@7.27.0':
resolution: {integrity: sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==} resolution: {integrity: sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
'@babel/traverse@7.28.5':
resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==}
engines: {node: '>=6.9.0'}
'@babel/types@7.27.0': '@babel/types@7.27.0':
resolution: {integrity: sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==} resolution: {integrity: sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
@@ -850,6 +955,10 @@ packages:
resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==} resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
'@babel/types@7.28.5':
resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==}
engines: {node: '>=6.9.0'}
'@biomejs/biome@1.9.4': '@biomejs/biome@1.9.4':
resolution: {integrity: sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==} resolution: {integrity: sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==}
engines: {node: '>=14.21.3'} engines: {node: '>=14.21.3'}
@@ -1130,6 +1239,12 @@ packages:
'@fontsource/roboto@5.2.5': '@fontsource/roboto@5.2.5':
resolution: {integrity: sha512-70r2UZ0raqLn5W+sPeKhqlf8wGvUXFWlofaDlcbt/S3d06+17gXKr3VNqDODB0I1ASme3dGT5OJj9NABt7OTZQ==} resolution: {integrity: sha512-70r2UZ0raqLn5W+sPeKhqlf8wGvUXFWlofaDlcbt/S3d06+17gXKr3VNqDODB0I1ASme3dGT5OJj9NABt7OTZQ==}
'@gsap/react@2.1.2':
resolution: {integrity: sha512-JqliybO1837UcgH2hVOM4VO+38APk3ECNrsuSM4MuXp+rbf+/2IG2K1YJiqfTcXQHH7XlA0m3ykniFYstfq0Iw==}
peerDependencies:
gsap: ^3.12.5
react: '>=17'
'@iconify-json/fa6-brands@1.2.5': '@iconify-json/fa6-brands@1.2.5':
resolution: {integrity: sha512-U/iFfziz6jSN9zArOJZYTtoj2tQyh6MxPdI8M84DQ2kEulPaj8j+h9bqvjmzszNHmD7v+kmmKd/MLkMKk+3Zuw==} resolution: {integrity: sha512-U/iFfziz6jSN9zArOJZYTtoj2tQyh6MxPdI8M84DQ2kEulPaj8j+h9bqvjmzszNHmD7v+kmmKd/MLkMKk+3Zuw==}
@@ -1418,10 +1533,16 @@ packages:
resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==}
engines: {node: '>=18.0.0'} engines: {node: '>=18.0.0'}
'@jridgewell/gen-mapping@0.3.13':
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
'@jridgewell/gen-mapping@0.3.8': '@jridgewell/gen-mapping@0.3.8':
resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==}
engines: {node: '>=6.0.0'} engines: {node: '>=6.0.0'}
'@jridgewell/remapping@2.3.5':
resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
'@jridgewell/resolve-uri@3.1.2': '@jridgewell/resolve-uri@3.1.2':
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
engines: {node: '>=6.0.0'} engines: {node: '>=6.0.0'}
@@ -1439,6 +1560,9 @@ packages:
'@jridgewell/trace-mapping@0.3.25': '@jridgewell/trace-mapping@0.3.25':
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
'@jridgewell/trace-mapping@0.3.31':
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
'@mapbox/node-pre-gyp@2.0.0': '@mapbox/node-pre-gyp@2.0.0':
resolution: {integrity: sha512-llMXd39jtP0HpQLVI37Bf1m2ADlEb35GYSh1SDSLsBhR+5iCxiNGlT31yqbNtVHygHAtMy6dWFERpU2JgufhPg==} resolution: {integrity: sha512-llMXd39jtP0HpQLVI37Bf1m2ADlEb35GYSh1SDSLsBhR+5iCxiNGlT31yqbNtVHygHAtMy6dWFERpU2JgufhPg==}
engines: {node: '>=18'} engines: {node: '>=18'}
@@ -1551,6 +1675,9 @@ packages:
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'} engines: {node: '>=14'}
'@rolldown/pluginutils@1.0.0-beta.27':
resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==}
'@rollup/plugin-alias@3.1.9': '@rollup/plugin-alias@3.1.9':
resolution: {integrity: sha512-QI5fsEvm9bDzt32k39wpOwZhVzRcL5ydcffUHMyLVaVaLeC70I8TJZ17F1z1eMoLu4E/UOcH9BWVkKpIKdrfiw==} resolution: {integrity: sha512-QI5fsEvm9bDzt32k39wpOwZhVzRcL5ydcffUHMyLVaVaLeC70I8TJZ17F1z1eMoLu4E/UOcH9BWVkKpIKdrfiw==}
engines: {node: '>=8.0.0'} engines: {node: '>=8.0.0'}
@@ -1928,6 +2055,14 @@ packages:
'@types/parse-json@4.0.2': '@types/parse-json@4.0.2':
resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
'@types/react-dom@19.2.3':
resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==}
peerDependencies:
'@types/react': ^19.2.0
'@types/react@19.2.7':
resolution: {integrity: sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==}
'@types/resolve@1.17.1': '@types/resolve@1.17.1':
resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==}
@@ -1999,6 +2134,12 @@ packages:
'@vercel/routing-utils@5.1.1': '@vercel/routing-utils@5.1.1':
resolution: {integrity: sha512-EyOik06V2fPXAbKY087BM7DMOQOJK+9mubwwox1TkDi21tMeJcMYwsXwepm6ZmyZ5u0j1TpJW172fP4MbzaCcg==} resolution: {integrity: sha512-EyOik06V2fPXAbKY087BM7DMOQOJK+9mubwwox1TkDi21tMeJcMYwsXwepm6ZmyZ5u0j1TpJW172fP4MbzaCcg==}
'@vitejs/plugin-react@4.7.0':
resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==}
engines: {node: ^14.18.0 || >=16.0.0}
peerDependencies:
vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
'@volar/kit@2.4.12': '@volar/kit@2.4.12':
resolution: {integrity: sha512-f9JE8oy9C2rBcCWxUYKUF23hOXz4mwgVXFjk7nHhxzplaoVjEOsKpBm8NI2nBH7Cwu8DRxDwBsbIxMl/8wlLxw==} resolution: {integrity: sha512-f9JE8oy9C2rBcCWxUYKUF23hOXz4mwgVXFjk7nHhxzplaoVjEOsKpBm8NI2nBH7Cwu8DRxDwBsbIxMl/8wlLxw==}
peerDependencies: peerDependencies:
@@ -2500,6 +2641,9 @@ packages:
resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==}
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'}
csstype@3.2.3:
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
data-view-buffer@1.0.2: data-view-buffer@1.0.2:
resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
@@ -2967,6 +3111,9 @@ packages:
graceful-fs@4.2.11: graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
gsap@3.14.2:
resolution: {integrity: sha512-P8/mMxVLU7o4+55+1TCnQrPmgjPKnwkzkXOK1asnR9Jg2lna4tEY5qBJjMmAaOBDDZWtlRjBXjLa0w53G/uBLA==}
gzip-size@3.0.0: gzip-size@3.0.0:
resolution: {integrity: sha512-6s8trQiK+OMzSaCSVXX+iqIcLV9tC+E73jrJrJTyS4h/AJhlxHvzFKqM1YLDJWRGgHX8uLkBeXkA0njNj39L4w==} resolution: {integrity: sha512-6s8trQiK+OMzSaCSVXX+iqIcLV9tC+E73jrJrJTyS4h/AJhlxHvzFKqM1YLDJWRGgHX8uLkBeXkA0njNj39L4w==}
engines: {node: '>=0.12.0'} engines: {node: '>=0.12.0'}
@@ -4404,6 +4551,19 @@ packages:
randombytes@2.1.0: randombytes@2.1.0:
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
react-dom@19.2.3:
resolution: {integrity: sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==}
peerDependencies:
react: ^19.2.3
react-refresh@0.17.0:
resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==}
engines: {node: '>=0.10.0'}
react@19.2.3:
resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==}
engines: {node: '>=0.10.0'}
read-cache@1.0.0: read-cache@1.0.0:
resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==}
@@ -4657,6 +4817,9 @@ packages:
sax@1.4.1: sax@1.4.1:
resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==}
scheduler@0.27.0:
resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==}
scrl@2.0.0: scrl@2.0.0:
resolution: {integrity: sha512-BbbVXxrOn58Ge4wjOORIRVZamssQu08ISLL/AC2z9aATIsKqZLESwZVW5YR0Yz0C7qqDRHb4yNXJlQ8yW0SGHw==} resolution: {integrity: sha512-BbbVXxrOn58Ge4wjOORIRVZamssQu08ISLL/AC2z9aATIsKqZLESwZVW5YR0Yz0C7qqDRHb4yNXJlQ8yW0SGHw==}
@@ -5216,6 +5379,46 @@ packages:
yaml: yaml:
optional: true optional: true
vite@6.4.1:
resolution: {integrity: sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==}
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
hasBin: true
peerDependencies:
'@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
jiti: '>=1.21.0'
less: '*'
lightningcss: ^1.21.0
sass: '*'
sass-embedded: '*'
stylus: '*'
sugarss: '*'
terser: ^5.16.0
tsx: ^4.8.1
yaml: ^2.4.2
peerDependenciesMeta:
'@types/node':
optional: true
jiti:
optional: true
less:
optional: true
lightningcss:
optional: true
sass:
optional: true
sass-embedded:
optional: true
stylus:
optional: true
sugarss:
optional: true
terser:
optional: true
tsx:
optional: true
yaml:
optional: true
vitefu@1.0.6: vitefu@1.0.6:
resolution: {integrity: sha512-+Rex1GlappUyNN6UfwbVZne/9cYC4+R2XDk9xkNXBKMw6HQagdX9PgZ8V2v1WUSK1wfBLp7qbI1+XSNIlB1xmA==} resolution: {integrity: sha512-+Rex1GlappUyNN6UfwbVZne/9cYC4+R2XDk9xkNXBKMw6HQagdX9PgZ8V2v1WUSK1wfBLp7qbI1+XSNIlB1xmA==}
peerDependencies: peerDependencies:
@@ -5556,6 +5759,29 @@ snapshots:
dependencies: dependencies:
prismjs: 1.30.0 prismjs: 1.30.0
'@astrojs/react@4.4.2(@types/node@22.14.1)(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(jiti@1.21.7)(lightningcss@1.29.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.80.4)(stylus@0.64.0)(terser@5.39.0)(yaml@2.7.0)':
dependencies:
'@types/react': 19.2.7
'@types/react-dom': 19.2.3(@types/react@19.2.7)
'@vitejs/plugin-react': 4.7.0(vite@6.4.1(@types/node@22.14.1)(jiti@1.21.7)(lightningcss@1.29.3)(sass@1.80.4)(stylus@0.64.0)(terser@5.39.0)(yaml@2.7.0))
react: 19.2.3
react-dom: 19.2.3(react@19.2.3)
ultrahtml: 1.6.0
vite: 6.4.1(@types/node@22.14.1)(jiti@1.21.7)(lightningcss@1.29.3)(sass@1.80.4)(stylus@0.64.0)(terser@5.39.0)(yaml@2.7.0)
transitivePeerDependencies:
- '@types/node'
- jiti
- less
- lightningcss
- sass
- sass-embedded
- stylus
- sugarss
- supports-color
- terser
- tsx
- yaml
'@astrojs/rss@4.0.11': '@astrojs/rss@4.0.11':
dependencies: dependencies:
fast-xml-parser: 4.5.3 fast-xml-parser: 4.5.3
@@ -5621,10 +5847,10 @@ snapshots:
semver: 7.7.1 semver: 7.7.1
vscode-languageserver-textdocument: 1.0.12 vscode-languageserver-textdocument: 1.0.12
'@astrojs/vercel@8.2.7(astro@5.7.9(patch_hash=ysrllw3gj6hylybllnynya5oma)(@types/node@22.14.1)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@2.79.2)(sass@1.80.4)(stylus@0.64.0)(terser@5.39.0)(typescript@5.8.3)(yaml@2.7.0))(rollup@2.79.2)(svelte@5.28.2)': '@astrojs/vercel@8.2.7(astro@5.7.9(patch_hash=ysrllw3gj6hylybllnynya5oma)(@types/node@22.14.1)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@2.79.2)(sass@1.80.4)(stylus@0.64.0)(terser@5.39.0)(typescript@5.8.3)(yaml@2.7.0))(react@19.2.3)(rollup@2.79.2)(svelte@5.28.2)':
dependencies: dependencies:
'@astrojs/internal-helpers': 0.7.2 '@astrojs/internal-helpers': 0.7.2
'@vercel/analytics': 1.5.0(svelte@5.28.2) '@vercel/analytics': 1.5.0(react@19.2.3)(svelte@5.28.2)
'@vercel/functions': 2.2.13 '@vercel/functions': 2.2.13
'@vercel/nft': 0.29.4(rollup@2.79.2) '@vercel/nft': 0.29.4(rollup@2.79.2)
'@vercel/routing-utils': 5.1.1 '@vercel/routing-utils': 5.1.1
@@ -5654,8 +5880,16 @@ snapshots:
js-tokens: 4.0.0 js-tokens: 4.0.0
picocolors: 1.1.1 picocolors: 1.1.1
'@babel/code-frame@7.27.1':
dependencies:
'@babel/helper-validator-identifier': 7.27.1
js-tokens: 4.0.0
picocolors: 1.1.1
'@babel/compat-data@7.26.8': {} '@babel/compat-data@7.26.8': {}
'@babel/compat-data@7.28.5': {}
'@babel/core@7.26.10': '@babel/core@7.26.10':
dependencies: dependencies:
'@ampproject/remapping': 2.3.0 '@ampproject/remapping': 2.3.0
@@ -5676,6 +5910,26 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@babel/core@7.28.5':
dependencies:
'@babel/code-frame': 7.27.1
'@babel/generator': 7.28.5
'@babel/helper-compilation-targets': 7.27.2
'@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5)
'@babel/helpers': 7.28.4
'@babel/parser': 7.28.5
'@babel/template': 7.27.2
'@babel/traverse': 7.28.5
'@babel/types': 7.28.5
'@jridgewell/remapping': 2.3.5
convert-source-map: 2.0.0
debug: 4.4.0
gensync: 1.0.0-beta.2
json5: 2.2.3
semver: 6.3.1
transitivePeerDependencies:
- supports-color
'@babel/generator@7.27.0': '@babel/generator@7.27.0':
dependencies: dependencies:
'@babel/parser': 7.27.0 '@babel/parser': 7.27.0
@@ -5684,6 +5938,14 @@ snapshots:
'@jridgewell/trace-mapping': 0.3.25 '@jridgewell/trace-mapping': 0.3.25
jsesc: 3.1.0 jsesc: 3.1.0
'@babel/generator@7.28.5':
dependencies:
'@babel/parser': 7.28.5
'@babel/types': 7.28.5
'@jridgewell/gen-mapping': 0.3.13
'@jridgewell/trace-mapping': 0.3.31
jsesc: 3.1.0
'@babel/helper-annotate-as-pure@7.25.9': '@babel/helper-annotate-as-pure@7.25.9':
dependencies: dependencies:
'@babel/types': 7.27.0 '@babel/types': 7.27.0
@@ -5696,6 +5958,14 @@ snapshots:
lru-cache: 5.1.1 lru-cache: 5.1.1
semver: 6.3.1 semver: 6.3.1
'@babel/helper-compilation-targets@7.27.2':
dependencies:
'@babel/compat-data': 7.28.5
'@babel/helper-validator-option': 7.27.1
browserslist: 4.24.4
lru-cache: 5.1.1
semver: 6.3.1
'@babel/helper-create-class-features-plugin@7.27.0(@babel/core@7.26.10)': '@babel/helper-create-class-features-plugin@7.27.0(@babel/core@7.26.10)':
dependencies: dependencies:
'@babel/core': 7.26.10 '@babel/core': 7.26.10
@@ -5727,6 +5997,8 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@babel/helper-globals@7.28.0': {}
'@babel/helper-member-expression-to-functions@7.25.9': '@babel/helper-member-expression-to-functions@7.25.9':
dependencies: dependencies:
'@babel/traverse': 7.27.0 '@babel/traverse': 7.27.0
@@ -5741,6 +6013,13 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@babel/helper-module-imports@7.27.1':
dependencies:
'@babel/traverse': 7.28.5
'@babel/types': 7.28.5
transitivePeerDependencies:
- supports-color
'@babel/helper-module-transforms@7.26.0(@babel/core@7.26.10)': '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.10)':
dependencies: dependencies:
'@babel/core': 7.26.10 '@babel/core': 7.26.10
@@ -5750,12 +6029,23 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)':
dependencies:
'@babel/core': 7.28.5
'@babel/helper-module-imports': 7.27.1
'@babel/helper-validator-identifier': 7.27.1
'@babel/traverse': 7.28.5
transitivePeerDependencies:
- supports-color
'@babel/helper-optimise-call-expression@7.25.9': '@babel/helper-optimise-call-expression@7.25.9':
dependencies: dependencies:
'@babel/types': 7.27.0 '@babel/types': 7.27.0
'@babel/helper-plugin-utils@7.26.5': {} '@babel/helper-plugin-utils@7.26.5': {}
'@babel/helper-plugin-utils@7.27.1': {}
'@babel/helper-remap-async-to-generator@7.25.9(@babel/core@7.26.10)': '@babel/helper-remap-async-to-generator@7.25.9(@babel/core@7.26.10)':
dependencies: dependencies:
'@babel/core': 7.26.10 '@babel/core': 7.26.10
@@ -5783,16 +6073,18 @@ snapshots:
'@babel/helper-string-parser@7.25.9': {} '@babel/helper-string-parser@7.25.9': {}
'@babel/helper-string-parser@7.27.1': '@babel/helper-string-parser@7.27.1': {}
optional: true
'@babel/helper-validator-identifier@7.25.9': {} '@babel/helper-validator-identifier@7.25.9': {}
'@babel/helper-validator-identifier@7.27.1': '@babel/helper-validator-identifier@7.27.1': {}
optional: true
'@babel/helper-validator-identifier@7.28.5': {}
'@babel/helper-validator-option@7.25.9': {} '@babel/helper-validator-option@7.25.9': {}
'@babel/helper-validator-option@7.27.1': {}
'@babel/helper-wrap-function@7.25.9': '@babel/helper-wrap-function@7.25.9':
dependencies: dependencies:
'@babel/template': 7.27.0 '@babel/template': 7.27.0
@@ -5806,6 +6098,11 @@ snapshots:
'@babel/template': 7.27.0 '@babel/template': 7.27.0
'@babel/types': 7.27.0 '@babel/types': 7.27.0
'@babel/helpers@7.28.4':
dependencies:
'@babel/template': 7.27.2
'@babel/types': 7.28.5
'@babel/parser@7.27.0': '@babel/parser@7.27.0':
dependencies: dependencies:
'@babel/types': 7.27.0 '@babel/types': 7.27.0
@@ -5813,7 +6110,10 @@ snapshots:
'@babel/parser@7.28.0': '@babel/parser@7.28.0':
dependencies: dependencies:
'@babel/types': 7.28.2 '@babel/types': 7.28.2
optional: true
'@babel/parser@7.28.5':
dependencies:
'@babel/types': 7.28.5
'@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.9(@babel/core@7.26.10)': '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.9(@babel/core@7.26.10)':
dependencies: dependencies:
@@ -6162,6 +6462,16 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.5)':
dependencies:
'@babel/core': 7.28.5
'@babel/helper-plugin-utils': 7.27.1
'@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.5)':
dependencies:
'@babel/core': 7.28.5
'@babel/helper-plugin-utils': 7.27.1
'@babel/plugin-transform-react-jsx@7.25.9(@babel/core@7.26.10)': '@babel/plugin-transform-react-jsx@7.25.9(@babel/core@7.26.10)':
dependencies: dependencies:
'@babel/core': 7.26.10 '@babel/core': 7.26.10
@@ -6358,6 +6668,12 @@ snapshots:
'@babel/parser': 7.27.0 '@babel/parser': 7.27.0
'@babel/types': 7.27.0 '@babel/types': 7.27.0
'@babel/template@7.27.2':
dependencies:
'@babel/code-frame': 7.27.1
'@babel/parser': 7.28.5
'@babel/types': 7.28.5
'@babel/traverse@7.27.0': '@babel/traverse@7.27.0':
dependencies: dependencies:
'@babel/code-frame': 7.26.2 '@babel/code-frame': 7.26.2
@@ -6370,6 +6686,18 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@babel/traverse@7.28.5':
dependencies:
'@babel/code-frame': 7.27.1
'@babel/generator': 7.28.5
'@babel/helper-globals': 7.28.0
'@babel/parser': 7.28.5
'@babel/template': 7.27.2
'@babel/types': 7.28.5
debug: 4.4.0
transitivePeerDependencies:
- supports-color
'@babel/types@7.27.0': '@babel/types@7.27.0':
dependencies: dependencies:
'@babel/helper-string-parser': 7.25.9 '@babel/helper-string-parser': 7.25.9
@@ -6379,7 +6707,11 @@ snapshots:
dependencies: dependencies:
'@babel/helper-string-parser': 7.27.1 '@babel/helper-string-parser': 7.27.1
'@babel/helper-validator-identifier': 7.27.1 '@babel/helper-validator-identifier': 7.27.1
optional: true
'@babel/types@7.28.5':
dependencies:
'@babel/helper-string-parser': 7.27.1
'@babel/helper-validator-identifier': 7.28.5
'@biomejs/biome@1.9.4': '@biomejs/biome@1.9.4':
optionalDependencies: optionalDependencies:
@@ -6581,6 +6913,11 @@ snapshots:
'@fontsource/roboto@5.2.5': {} '@fontsource/roboto@5.2.5': {}
'@gsap/react@2.1.2(gsap@3.14.2)(react@19.2.3)':
dependencies:
gsap: 3.14.2
react: 19.2.3
'@iconify-json/fa6-brands@1.2.5': '@iconify-json/fa6-brands@1.2.5':
dependencies: dependencies:
'@iconify/types': 2.0.0 '@iconify/types': 2.0.0
@@ -6814,12 +7151,22 @@ snapshots:
dependencies: dependencies:
minipass: 7.1.2 minipass: 7.1.2
'@jridgewell/gen-mapping@0.3.13':
dependencies:
'@jridgewell/sourcemap-codec': 1.5.0
'@jridgewell/trace-mapping': 0.3.31
'@jridgewell/gen-mapping@0.3.8': '@jridgewell/gen-mapping@0.3.8':
dependencies: dependencies:
'@jridgewell/set-array': 1.2.1 '@jridgewell/set-array': 1.2.1
'@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/sourcemap-codec': 1.5.0
'@jridgewell/trace-mapping': 0.3.25 '@jridgewell/trace-mapping': 0.3.25
'@jridgewell/remapping@2.3.5':
dependencies:
'@jridgewell/gen-mapping': 0.3.8
'@jridgewell/trace-mapping': 0.3.25
'@jridgewell/resolve-uri@3.1.2': {} '@jridgewell/resolve-uri@3.1.2': {}
'@jridgewell/set-array@1.2.1': {} '@jridgewell/set-array@1.2.1': {}
@@ -6836,6 +7183,11 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2 '@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/sourcemap-codec': 1.5.0
'@jridgewell/trace-mapping@0.3.31':
dependencies:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.0
'@mapbox/node-pre-gyp@2.0.0': '@mapbox/node-pre-gyp@2.0.0':
dependencies: dependencies:
consola: 3.4.2 consola: 3.4.2
@@ -6927,6 +7279,8 @@ snapshots:
'@pkgjs/parseargs@0.11.0': '@pkgjs/parseargs@0.11.0':
optional: true optional: true
'@rolldown/pluginutils@1.0.0-beta.27': {}
'@rollup/plugin-alias@3.1.9(rollup@2.79.2)': '@rollup/plugin-alias@3.1.9(rollup@2.79.2)':
dependencies: dependencies:
rollup: 2.79.2 rollup: 2.79.2
@@ -7279,23 +7633,19 @@ snapshots:
'@types/babel__generator': 7.27.0 '@types/babel__generator': 7.27.0
'@types/babel__template': 7.4.4 '@types/babel__template': 7.4.4
'@types/babel__traverse': 7.28.0 '@types/babel__traverse': 7.28.0
optional: true
'@types/babel__generator@7.27.0': '@types/babel__generator@7.27.0':
dependencies: dependencies:
'@babel/types': 7.28.2 '@babel/types': 7.28.2
optional: true
'@types/babel__template@7.4.4': '@types/babel__template@7.4.4':
dependencies: dependencies:
'@babel/parser': 7.28.0 '@babel/parser': 7.28.0
'@babel/types': 7.28.2 '@babel/types': 7.28.2
optional: true
'@types/babel__traverse@7.28.0': '@types/babel__traverse@7.28.0':
dependencies: dependencies:
'@babel/types': 7.28.2 '@babel/types': 7.28.2
optional: true
'@types/debug@4.1.12': '@types/debug@4.1.12':
dependencies: dependencies:
@@ -7342,6 +7692,14 @@ snapshots:
'@types/parse-json@4.0.2': {} '@types/parse-json@4.0.2': {}
'@types/react-dom@19.2.3(@types/react@19.2.7)':
dependencies:
'@types/react': 19.2.7
'@types/react@19.2.7':
dependencies:
csstype: 3.2.3
'@types/resolve@1.17.1': '@types/resolve@1.17.1':
dependencies: dependencies:
'@types/node': 22.14.1 '@types/node': 22.14.1
@@ -7370,8 +7728,9 @@ snapshots:
'@ungap/structured-clone@1.3.0': {} '@ungap/structured-clone@1.3.0': {}
'@vercel/analytics@1.5.0(svelte@5.28.2)': '@vercel/analytics@1.5.0(react@19.2.3)(svelte@5.28.2)':
optionalDependencies: optionalDependencies:
react: 19.2.3
svelte: 5.28.2 svelte: 5.28.2
'@vercel/functions@2.2.13': '@vercel/functions@2.2.13':
@@ -7409,6 +7768,18 @@ snapshots:
optionalDependencies: optionalDependencies:
ajv: 6.12.6 ajv: 6.12.6
'@vitejs/plugin-react@4.7.0(vite@6.4.1(@types/node@22.14.1)(jiti@1.21.7)(lightningcss@1.29.3)(sass@1.80.4)(stylus@0.64.0)(terser@5.39.0)(yaml@2.7.0))':
dependencies:
'@babel/core': 7.28.5
'@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5)
'@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.5)
'@rolldown/pluginutils': 1.0.0-beta.27
'@types/babel__core': 7.20.5
react-refresh: 0.17.0
vite: 6.4.1(@types/node@22.14.1)(jiti@1.21.7)(lightningcss@1.29.3)(sass@1.80.4)(stylus@0.64.0)(terser@5.39.0)(yaml@2.7.0)
transitivePeerDependencies:
- supports-color
'@volar/kit@2.4.12(typescript@5.8.3)': '@volar/kit@2.4.12(typescript@5.8.3)':
dependencies: dependencies:
'@volar/language-service': 2.4.12 '@volar/language-service': 2.4.12
@@ -8076,6 +8447,8 @@ snapshots:
dependencies: dependencies:
css-tree: 2.2.1 css-tree: 2.2.1
csstype@3.2.3: {}
data-view-buffer@1.0.2: data-view-buffer@1.0.2:
dependencies: dependencies:
call-bound: 1.0.4 call-bound: 1.0.4
@@ -8614,6 +8987,8 @@ snapshots:
graceful-fs@4.2.11: {} graceful-fs@4.2.11: {}
gsap@3.14.2: {}
gzip-size@3.0.0: gzip-size@3.0.0:
dependencies: dependencies:
duplexer: 0.1.2 duplexer: 0.1.2
@@ -10296,6 +10671,15 @@ snapshots:
dependencies: dependencies:
safe-buffer: 5.2.1 safe-buffer: 5.2.1
react-dom@19.2.3(react@19.2.3):
dependencies:
react: 19.2.3
scheduler: 0.27.0
react-refresh@0.17.0: {}
react@19.2.3: {}
read-cache@1.0.0: read-cache@1.0.0:
dependencies: dependencies:
pify: 2.3.0 pify: 2.3.0
@@ -10701,6 +11085,8 @@ snapshots:
sax@1.4.1: {} sax@1.4.1: {}
scheduler@0.27.0: {}
scrl@2.0.0: {} scrl@2.0.0: {}
semver@6.3.1: {} semver@6.3.1: {}
@@ -11372,6 +11758,24 @@ snapshots:
terser: 5.39.0 terser: 5.39.0
yaml: 2.7.0 yaml: 2.7.0
vite@6.4.1(@types/node@22.14.1)(jiti@1.21.7)(lightningcss@1.29.3)(sass@1.80.4)(stylus@0.64.0)(terser@5.39.0)(yaml@2.7.0):
dependencies:
esbuild: 0.25.3
fdir: 6.4.4(picomatch@4.0.2)
picomatch: 4.0.2
postcss: 8.5.3
rollup: 4.40.1
tinyglobby: 0.2.13
optionalDependencies:
'@types/node': 22.14.1
fsevents: 2.3.3
jiti: 1.21.7
lightningcss: 1.29.3
sass: 1.80.4
stylus: 0.64.0
terser: 5.39.0
yaml: 2.7.0
vitefu@1.0.6(vite@6.3.3(@types/node@22.14.1)(jiti@1.21.7)(lightningcss@1.29.3)(sass@1.80.4)(stylus@0.64.0)(terser@5.39.0)(yaml@2.7.0)): vitefu@1.0.6(vite@6.3.3(@types/node@22.14.1)(jiti@1.21.7)(lightningcss@1.29.3)(sass@1.80.4)(stylus@0.64.0)(terser@5.39.0)(yaml@2.7.0)):
optionalDependencies: optionalDependencies:
vite: 6.3.3(@types/node@22.14.1)(jiti@1.21.7)(lightningcss@1.29.3)(sass@1.80.4)(stylus@0.64.0)(terser@5.39.0)(yaml@2.7.0) vite: 6.3.3(@types/node@22.14.1)(jiti@1.21.7)(lightningcss@1.29.3)(sass@1.80.4)(stylus@0.64.0)(terser@5.39.0)(yaml@2.7.0)

View File

@@ -1,11 +1,11 @@
import postcssImport from 'postcss-import'; import postcssImport from "postcss-import";
import postcssNesting from 'tailwindcss/nesting/index.js'; import tailwindcss from "tailwindcss";
import tailwindcss from 'tailwindcss'; import postcssNesting from "tailwindcss/nesting/index.js";
export default { export default {
plugins: { plugins: {
'postcss-import': postcssImport, // to combine multiple css files "postcss-import": postcssImport, // to combine multiple css files
'tailwindcss/nesting': postcssNesting, "tailwindcss/nesting": postcssNesting,
tailwindcss: tailwindcss, tailwindcss: tailwindcss,
} },
}; };

View File

@@ -2,9 +2,9 @@
* Static Random Pic API * Static Random Pic API
* Generated by build script * Generated by build script
*/ */
(function() { (() => {
var counts = {"h":979,"v":3596}; var counts = { h: 979, v: 3596 };
var domain = 'https://pic.acofork.com'; var domain = "https://pic.acofork.com";
// State management for session consistency // State management for session consistency
var sessionRandomH = null; var sessionRandomH = null;
@@ -12,49 +12,55 @@
// Helper: Get random URL for a type (h or v), persistent per session // Helper: Get random URL for a type (h or v), persistent per session
function getRandomUrl(type) { function getRandomUrl(type) {
if (!counts[type] || counts[type] === 0) return ''; if (!counts[type] || counts[type] === 0) return "";
// Return existing session URL if available // Return existing session URL if available
if (type === 'h' && sessionRandomH) return sessionRandomH; if (type === "h" && sessionRandomH) return sessionRandomH;
if (type === 'v' && sessionRandomV) return sessionRandomV; if (type === "v" && sessionRandomV) return sessionRandomV;
// Generate new if not exists // Generate new if not exists
var num = Math.floor(Math.random() * counts[type]) + 1; var num = Math.floor(Math.random() * counts[type]) + 1;
var url = domain + '/ri/' + type + '/' + num + '.webp'; var url = domain + "/ri/" + type + "/" + num + ".webp";
// Save to session state // Save to session state
if (type === 'h') sessionRandomH = url; if (type === "h") sessionRandomH = url;
if (type === 'v') sessionRandomV = url; if (type === "v") sessionRandomV = url;
return url; return url;
} }
// Expose global functions // Expose global functions
window.getRandomPicH = function() { return getRandomUrl('h'); }; window.getRandomPicH = () => getRandomUrl("h");
window.getRandomPicV = function() { return getRandomUrl('v'); }; window.getRandomPicV = () => getRandomUrl("v");
// 1. Logic for Background (Customized based on user request) // 1. Logic for Background (Customized based on user request)
function setRandomBackground() { function setRandomBackground() {
// Get random URL using the helper (Dynamic count & domain) // Get random URL using the helper (Dynamic count & domain)
const bgUrl = getRandomUrl('h'); const bgUrl = getRandomUrl("h");
// Find the background box element // Find the background box element
const bgBox = document.getElementById('bg-box'); const bgBox = document.getElementById("bg-box");
if (bgBox) { if (bgBox) {
// Preload image // Preload image
const img = new Image(); const img = new Image();
img.onload = function() { img.onload = () => {
bgBox.style.backgroundImage = `url('${bgUrl}')`; bgBox.style.backgroundImage = `url('${bgUrl}')`;
bgBox.classList.add('loaded'); bgBox.classList.add("loaded");
console.log('Random background loaded:', bgUrl); console.log("Random background loaded:", bgUrl);
// Set CSS variables for transparency effects // Set CSS variables for transparency effects
document.documentElement.style.setProperty('--card-bg', 'var(--card-bg-transparent)'); document.documentElement.style.setProperty(
document.documentElement.style.setProperty('--float-panel-bg', 'var(--float-panel-bg-transparent)'); "--card-bg",
"var(--card-bg-transparent)",
);
document.documentElement.style.setProperty(
"--float-panel-bg",
"var(--float-panel-bg-transparent)",
);
}; };
img.onerror = function() { img.onerror = () => {
console.error('Failed to load background image:', bgUrl); console.error("Failed to load background image:", bgUrl);
}; };
img.src = bgUrl; img.src = bgUrl;
} else { } else {
@@ -66,35 +72,38 @@
// 2. Logic for Image Tags (Generic) // 2. Logic for Image Tags (Generic)
function initImgTags() { function initImgTags() {
var imgTags = document.getElementsByTagName('img'); var imgTags = document.getElementsByTagName("img");
for (var i = 0; i < imgTags.length; i++) { for (var i = 0; i < imgTags.length; i++) {
var img = imgTags[i]; var img = imgTags[i];
var alt = img.getAttribute('alt'); var alt = img.getAttribute("alt");
var src = img.getAttribute('src'); var src = img.getAttribute("src");
if (alt === 'random:h' || (src && src.indexOf('/random/h') !== -1)) { if (alt === "random:h" || (src && src.indexOf("/random/h") !== -1)) {
img.src = getRandomUrl('h'); img.src = getRandomUrl("h");
} else if (alt === 'random:v' || (src && src.indexOf('/random/v') !== -1)) { } else if (
img.src = getRandomUrl('v'); alt === "random:v" ||
(src && src.indexOf("/random/v") !== -1)
) {
img.src = getRandomUrl("v");
} }
} }
} }
// Helper for generic data-random-bg (as a backup or secondary feature) // Helper for generic data-random-bg (as a backup or secondary feature)
function initGenericBackgrounds() { function initGenericBackgrounds() {
var bgElements = document.querySelectorAll('[data-random-bg]'); var bgElements = document.querySelectorAll("[data-random-bg]");
bgElements.forEach(function(el) { bgElements.forEach((el) => {
// Skip if it is the bg-box we already handled (though setRandomBackground handles #bg-box specifically) // Skip if it is the bg-box we already handled (though setRandomBackground handles #bg-box specifically)
if (el.id === 'bg-box') return; if (el.id === "bg-box") return;
var type = el.getAttribute('data-random-bg'); var type = el.getAttribute("data-random-bg");
if (type === 'h' || type === 'v') { if (type === "h" || type === "v") {
var url = getRandomUrl(type); var url = getRandomUrl(type);
if (url) { if (url) {
var img = new Image(); var img = new Image();
img.onload = function() { img.onload = () => {
el.style.backgroundImage = 'url("' + url + '")'; el.style.backgroundImage = 'url("' + url + '")';
el.classList.add('loaded'); el.classList.add("loaded");
}; };
img.src = url; img.src = url;
} }
@@ -108,8 +117,8 @@
} }
// Run on initial load // Run on initial load
if (document.readyState === 'loading') { if (document.readyState === "loading") {
document.addEventListener('DOMContentLoaded', init); document.addEventListener("DOMContentLoaded", init);
} else { } else {
init(); init();
} }
@@ -118,17 +127,17 @@
function setupSwup() { function setupSwup() {
if (window.swup && window.swup.hooks) { if (window.swup && window.swup.hooks) {
// Register hook for content replacement // Register hook for content replacement
window.swup.hooks.on('content:replace', init); window.swup.hooks.on("content:replace", init);
console.log('Random Pic API: Registered with Swup hooks.'); console.log("Random Pic API: Registered with Swup hooks.");
} }
} }
if (window.swup) { if (window.swup) {
setupSwup(); setupSwup();
} else { } else {
document.addEventListener('swup:enable', setupSwup); document.addEventListener("swup:enable", setupSwup);
} }
// Legacy Swup support // Legacy Swup support
document.addEventListener('swup:contentReplaced', init); document.addEventListener("swup:contentReplaced", init);
})(); })();

View File

@@ -1,5 +1,5 @@
(function (global) { ((global) => {
const cacheKey = 'umami-share-cache'; const cacheKey = "umami-share-cache";
const cacheTTL = 3600_000; // 1h const cacheTTL = 3600_000; // 1h
async function fetchShareData(baseUrl, shareId) { async function fetchShareData(baseUrl, shareId) {
@@ -16,10 +16,13 @@
} }
const res = await fetch(`${baseUrl}/api/share/${shareId}`); const res = await fetch(`${baseUrl}/api/share/${shareId}`);
if (!res.ok) { if (!res.ok) {
throw new Error('获取 Umami 分享信息失败'); throw new Error("获取 Umami 分享信息失败");
} }
const data = await res.json(); const data = await res.json();
localStorage.setItem(cacheKey, JSON.stringify({ timestamp: Date.now(), value: data })); localStorage.setItem(
cacheKey,
JSON.stringify({ timestamp: Date.now(), value: data }),
);
return data; return data;
} }
@@ -30,21 +33,28 @@
* @param {string} shareId * @param {string} shareId
* @returns {Promise<{websiteId: string, token: string}>} * @returns {Promise<{websiteId: string, token: string}>}
*/ */
global.getUmamiShareData = function (baseUrl, shareId) { global.getUmamiShareData = (baseUrl, shareId) => {
if (!global.__umamiSharePromise) { if (!global.__umamiSharePromise) {
global.__umamiSharePromise = fetchShareData(baseUrl, shareId).catch((err) => { global.__umamiSharePromise = fetchShareData(baseUrl, shareId).catch(
(err) => {
delete global.__umamiSharePromise; delete global.__umamiSharePromise;
throw err; throw err;
}); },
);
} }
return global.__umamiSharePromise; return global.__umamiSharePromise;
}; };
global.clearUmamiShareCache = function () { global.clearUmamiShareCache = () => {
localStorage.removeItem(cacheKey); localStorage.removeItem(cacheKey);
delete global.__umamiSharePromise; delete global.__umamiSharePromise;
}; };
// 初始化全局缓存 Map
if (!global.__umamiDataCache) {
global.__umamiDataCache = new Map();
}
/** /**
* 获取 Umami 统计数据 * 获取 Umami 统计数据
* 自动处理 token 获取和过期重试 * 自动处理 token 获取和过期重试
@@ -53,25 +63,38 @@
* @param {object} queryParams * @param {object} queryParams
* @returns {Promise<any>} * @returns {Promise<any>}
*/ */
global.fetchUmamiStats = async function (baseUrl, shareId, queryParams) { global.fetchUmamiStats = async (baseUrl, shareId, queryParams) => {
// 生成缓存键baseUrl + shareId + queryParams的字符串表示
const cacheKey = `${baseUrl}|${shareId}|${JSON.stringify(queryParams)}`;
// 检查全局内存缓存
if (global.__umamiDataCache.has(cacheKey)) {
const data = global.__umamiDataCache.get(cacheKey);
// 标记数据来自缓存
return { ...data, _fromCache: true };
}
async function doFetch(isRetry = false) { async function doFetch(isRetry = false) {
const { websiteId, token } = await global.getUmamiShareData(baseUrl, shareId); const { websiteId, token } = await global.getUmamiShareData(
baseUrl,
shareId,
);
const currentTimestamp = Date.now(); const currentTimestamp = Date.now();
const params = new URLSearchParams({ const params = new URLSearchParams({
startAt: 0, startAt: 0,
endAt: currentTimestamp, endAt: currentTimestamp,
unit: 'hour', unit: "hour",
timezone: queryParams.timezone || 'Asia/Shanghai', timezone: queryParams.timezone || "Asia/Shanghai",
compare: false, compare: false,
...queryParams ...queryParams,
}); });
const statsUrl = `${baseUrl}/api/websites/${websiteId}/stats?${params.toString()}`; const statsUrl = `${baseUrl}/api/websites/${websiteId}/stats?${params.toString()}`;
const res = await fetch(statsUrl, { const res = await fetch(statsUrl, {
headers: { headers: {
'x-umami-share-token': token "x-umami-share-token": token,
} },
}); });
if (!res.ok) { if (!res.ok) {
@@ -79,13 +102,15 @@
global.clearUmamiShareCache(); global.clearUmamiShareCache();
return doFetch(true); return doFetch(true);
} }
throw new Error('获取统计数据失败'); throw new Error("获取统计数据失败");
} }
return await res.json(); const data = await res.json();
// 写入全局缓存
global.__umamiDataCache.set(cacheKey, data);
return data;
} }
return doFetch(); return doFetch();
}; };
})(window); })(window);

View File

@@ -1,9 +1,9 @@
#!/usr/bin/env node #!/usr/bin/env node
import fs from 'fs'; import fs from "fs";
import path from 'path'; import path from "path";
import { glob } from 'glob'; import { fileURLToPath } from "url";
import { fileURLToPath } from 'url'; import { glob } from "glob";
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename); const __dirname = path.dirname(__filename);
@@ -14,22 +14,30 @@ const __dirname = path.dirname(__filename);
* 查找 src/content/assets 中未被引用的图片并删除 * 查找 src/content/assets 中未被引用的图片并删除
*/ */
const CONTENT_DIR = path.join(process.cwd(), 'src/content'); const CONTENT_DIR = path.join(process.cwd(), "src/content");
const POSTS_DIR = path.join(CONTENT_DIR, 'posts'); const POSTS_DIR = path.join(CONTENT_DIR, "posts");
const ASSETS_DIR = path.join(CONTENT_DIR, 'assets'); const ASSETS_DIR = path.join(CONTENT_DIR, "assets");
// 支持的图片格式 // 支持的图片格式
const IMAGE_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.svg', '.avif']; const IMAGE_EXTENSIONS = [
".jpg",
".jpeg",
".png",
".gif",
".webp",
".svg",
".avif",
];
/** /**
* 获取所有 markdown 文件 * 获取所有 markdown 文件
*/ */
async function getAllMarkdownFiles() { async function getAllMarkdownFiles() {
try { try {
const pattern = path.join(POSTS_DIR, '**/*.md').replace(/\\/g, '/'); const pattern = path.join(POSTS_DIR, "**/*.md").replace(/\\/g, "/");
return await glob(pattern); return await glob(pattern);
} catch (error) { } catch (error) {
console.error('获取 markdown 文件失败:', error.message); console.error("获取 markdown 文件失败:", error.message);
return []; return [];
} }
} }
@@ -39,11 +47,13 @@ async function getAllMarkdownFiles() {
*/ */
async function getAllImageFiles() { async function getAllImageFiles() {
try { try {
const extensions = IMAGE_EXTENSIONS.join(','); const extensions = IMAGE_EXTENSIONS.join(",");
const pattern = path.join(ASSETS_DIR, `**/*{${extensions}}`).replace(/\\/g, '/'); const pattern = path
.join(ASSETS_DIR, `**/*{${extensions}}`)
.replace(/\\/g, "/");
return await glob(pattern); return await glob(pattern);
} catch (error) { } catch (error) {
console.error('获取图片文件失败:', error.message); console.error("获取图片文件失败:", error.message);
return []; return [];
} }
} }
@@ -55,7 +65,8 @@ function extractImageReferences(content) {
const references = new Set(); const references = new Set();
// 匹配 YAML frontmatter 中的 image 字段(支持带引号和不带引号的值) // 匹配 YAML frontmatter 中的 image 字段(支持带引号和不带引号的值)
const yamlImageRegex = /^---[\s\S]*?image:\s*(?:['"]([^'"]+)['"]|([^\s\n]+))[\s\S]*?^---/m; const yamlImageRegex =
/^---[\s\S]*?image:\s*(?:['"]([^'"]+)['"]|([^\s\n]+))[\s\S]*?^---/m;
let match = yamlImageRegex.exec(content); let match = yamlImageRegex.exec(content);
if (match) { if (match) {
// match[1] 是带引号的值match[2] 是不带引号的值 // match[1] 是带引号的值match[2] 是不带引号的值
@@ -75,7 +86,8 @@ function extractImageReferences(content) {
} }
// 匹配 Astro Image 组件引用 // 匹配 Astro Image 组件引用
const astroImageRegex = /import\s+.*?\s+from\s+["']([^"']+\.(jpg|jpeg|png|gif|webp|svg|avif))["']/gi; const astroImageRegex =
/import\s+.*?\s+from\s+["']([^"']+\.(jpg|jpeg|png|gif|webp|svg|avif))["']/gi;
while ((match = astroImageRegex.exec(content)) !== null) { while ((match = astroImageRegex.exec(content)) !== null) {
references.add(match[1]); references.add(match[1]);
} }
@@ -88,17 +100,17 @@ function extractImageReferences(content) {
*/ */
function normalizePath(imagePath, markdownFilePath) { function normalizePath(imagePath, markdownFilePath) {
// 跳过外部 URL // 跳过外部 URL
if (imagePath.startsWith('http://') || imagePath.startsWith('https://')) { if (imagePath.startsWith("http://") || imagePath.startsWith("https://")) {
return null; return null;
} }
// 跳过以 / 开头的绝对路径(通常指向 public 目录) // 跳过以 / 开头的绝对路径(通常指向 public 目录)
if (imagePath.startsWith('/')) { if (imagePath.startsWith("/")) {
return null; return null;
} }
// 处理相对路径 // 处理相对路径
if (imagePath.startsWith('./') || imagePath.startsWith('../')) { if (imagePath.startsWith("./") || imagePath.startsWith("../")) {
const markdownDir = path.dirname(markdownFilePath); const markdownDir = path.dirname(markdownFilePath);
return path.resolve(markdownDir, imagePath); return path.resolve(markdownDir, imagePath);
} }
@@ -112,7 +124,7 @@ function normalizePath(imagePath, markdownFilePath) {
* 主函数 * 主函数
*/ */
async function cleanUnusedImages() { async function cleanUnusedImages() {
console.log('🔍 开始扫描未使用的图片资源...'); console.log("🔍 开始扫描未使用的图片资源...");
// 检查目录是否存在 // 检查目录是否存在
if (!fs.existsSync(POSTS_DIR)) { if (!fs.existsSync(POSTS_DIR)) {
@@ -133,7 +145,7 @@ async function cleanUnusedImages() {
console.log(`🖼️ 找到 ${imageFiles.length} 个图片文件`); console.log(`🖼️ 找到 ${imageFiles.length} 个图片文件`);
if (imageFiles.length === 0) { if (imageFiles.length === 0) {
console.log('✅ 没有找到图片文件,无需清理'); console.log("✅ 没有找到图片文件,无需清理");
return; return;
} }
@@ -142,7 +154,7 @@ async function cleanUnusedImages() {
for (const mdFile of markdownFiles) { for (const mdFile of markdownFiles) {
try { try {
const content = fs.readFileSync(mdFile, 'utf-8'); const content = fs.readFileSync(mdFile, "utf-8");
const references = extractImageReferences(content); const references = extractImageReferences(content);
for (const ref of references) { for (const ref of references) {
@@ -174,7 +186,7 @@ async function cleanUnusedImages() {
console.log(`🗑️ 找到 ${unusedImages.length} 个未使用的图片`); console.log(`🗑️ 找到 ${unusedImages.length} 个未使用的图片`);
if (unusedImages.length === 0) { if (unusedImages.length === 0) {
console.log('✅ 所有图片都在使用中,无需清理'); console.log("✅ 所有图片都在使用中,无需清理");
return; return;
} }
@@ -233,11 +245,12 @@ function cleanEmptyDirectories(dir) {
// 运行脚本 // 运行脚本
// 检查是否直接运行此脚本 // 检查是否直接运行此脚本
const scriptPath = fileURLToPath(import.meta.url); const scriptPath = fileURLToPath(import.meta.url);
const isMainModule = process.argv[1] && path.resolve(process.argv[1]) === path.resolve(scriptPath); const isMainModule =
process.argv[1] && path.resolve(process.argv[1]) === path.resolve(scriptPath);
if (isMainModule) { if (isMainModule) {
cleanUnusedImages().catch(error => { cleanUnusedImages().catch((error) => {
console.error('❌ 脚本执行失败:', error.message); console.error("❌ 脚本执行失败:", error.message);
console.error(error.stack); console.error(error.stack);
process.exit(1); process.exit(1);
}); });

View File

@@ -1,48 +1,48 @@
/* This is a script to create a new post markdown file with front-matter */ /* This is a script to create a new post markdown file with front-matter */
import fs from "fs" import fs from "fs";
import path from "path" import path from "path";
function getDate() { function getDate() {
const today = new Date() const today = new Date();
const year = today.getFullYear() const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, "0") const month = String(today.getMonth() + 1).padStart(2, "0");
const day = String(today.getDate()).padStart(2, "0") const day = String(today.getDate()).padStart(2, "0");
const hours = String(today.getHours()).padStart(2, "0") const hours = String(today.getHours()).padStart(2, "0");
const minutes = String(today.getMinutes()).padStart(2, "0") const minutes = String(today.getMinutes()).padStart(2, "0");
const seconds = String(today.getSeconds()).padStart(2, "0") const seconds = String(today.getSeconds()).padStart(2, "0");
return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}` return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}`;
} }
const args = process.argv.slice(2) const args = process.argv.slice(2);
if (args.length === 0) { if (args.length === 0) {
console.error(`Error: No filename argument provided console.error(`Error: No filename argument provided
Usage: npm run new-post -- <filename>`) Usage: npm run new-post -- <filename>`);
process.exit(1) // Terminate the script and return error code 1 process.exit(1); // Terminate the script and return error code 1
} }
let fileName = args[0] let fileName = args[0];
// Add .md extension if not present // Add .md extension if not present
const fileExtensionRegex = /\.(md|mdx)$/i const fileExtensionRegex = /\.(md|mdx)$/i;
if (!fileExtensionRegex.test(fileName)) { if (!fileExtensionRegex.test(fileName)) {
fileName += ".md" fileName += ".md";
} }
const targetDir = "./src/content/posts/" const targetDir = "./src/content/posts/";
const fullPath = path.join(targetDir, fileName) const fullPath = path.join(targetDir, fileName);
if (fs.existsSync(fullPath)) { if (fs.existsSync(fullPath)) {
console.error(`Error: File ${fullPath} already exists `) console.error(`Error: File ${fullPath} already exists `);
process.exit(1) process.exit(1);
} }
// recursive mode creates multi-level directories // recursive mode creates multi-level directories
const dirPath = path.dirname(fullPath) const dirPath = path.dirname(fullPath);
if (!fs.existsSync(dirPath)) { if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true }) fs.mkdirSync(dirPath, { recursive: true });
} }
const content = `--- const content = `---
@@ -54,8 +54,8 @@ image: ''
draft: false draft: false
lang: '' lang: ''
--- ---
` `;
fs.writeFileSync(path.join(targetDir, fileName), content) fs.writeFileSync(path.join(targetDir, fileName), content);
console.log(`Post ${fullPath} created`) console.log(`Post ${fullPath} created`);

View File

@@ -1,8 +1,8 @@
--- ---
import { execSync } from "node:child_process";
import { profileConfig } from "../config"; import { profileConfig } from "../config";
import { url } from "../utils/url-utils"; import { url } from "../utils/url-utils";
import { execSync } from "child_process";
const currentYear = new Date().getFullYear(); const currentYear = new Date().getFullYear();
@@ -10,15 +10,15 @@ let commitHash = "unknown";
let buildDate = "unknown"; let buildDate = "unknown";
try { try {
commitHash = execSync('git rev-parse --short=7 HEAD').toString().trim(); commitHash = execSync("git rev-parse --short=7 HEAD").toString().trim();
const date = new Date(); const date = new Date();
const year = date.getFullYear(); const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, '0'); const month = (date.getMonth() + 1).toString().padStart(2, "0");
const day = date.getDate().toString().padStart(2, '0'); const day = date.getDate().toString().padStart(2, "0");
const hours = date.getHours().toString().padStart(2, '0'); const hours = date.getHours().toString().padStart(2, "0");
const minutes = date.getMinutes().toString().padStart(2, '0'); const minutes = date.getMinutes().toString().padStart(2, "0");
const seconds = date.getSeconds().toString().padStart(2, '0'); const seconds = date.getSeconds().toString().padStart(2, "0");
buildDate = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; buildDate = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
} catch (e) { } catch (e) {
console.warn("Failed to get git info", e); console.warn("Failed to get git info", e);

View File

@@ -3,11 +3,11 @@ import path from "node:path";
import type { CollectionEntry } from "astro:content"; import type { CollectionEntry } from "astro:content";
import { Icon } from "astro-icon/components"; import { Icon } from "astro-icon/components";
import { getDir } from "../utils/url-utils"; import { umamiConfig } from "../config";
import { formatDateToYYYYMMDD } from "../utils/date-utils"; import { formatDateToYYYYMMDD } from "../utils/date-utils";
import { getDir } from "../utils/url-utils";
import PostMetadata from "./PostMeta.astro"; import PostMetadata from "./PostMeta.astro";
import ImageWrapper from "./misc/ImageWrapper.astro"; import ImageWrapper from "./misc/ImageWrapper.astro";
import { umamiConfig } from "../config";
interface Props { interface Props {
class?: string; class?: string;
@@ -21,16 +21,8 @@ interface Props {
draft: boolean; draft: boolean;
style: string; style: string;
} }
const { const { entry, title, url, published, updated, image, description, style } =
entry, Astro.props;
title,
url,
published,
updated,
image,
description,
style,
} = Astro.props;
const isPinned = entry.data.pinned === true; const isPinned = entry.data.pinned === true;
const className = Astro.props.class; const className = Astro.props.class;
@@ -108,3 +100,72 @@ const { remarkPluginFrontmatter } = await entry.render();
<style define:vars={{coverWidth}}> <style define:vars={{coverWidth}}>
</style> </style>
<script>
// 数字动画函数
function animateValue(obj, start, end, duration) {
let startTimestamp = null;
const step = (timestamp) => {
if (!startTimestamp) startTimestamp = timestamp;
const progress = Math.min((timestamp - startTimestamp) / duration, 1);
obj.innerHTML = Math.floor(progress * (end - start) + start);
if (progress < 1) {
window.requestAnimationFrame(step);
} else {
obj.innerHTML = end;
}
};
window.requestAnimationFrame(step);
}
async function loadCardStats() {
const elements = document.querySelectorAll('.post-pageviews');
elements.forEach(async (el) => {
// 如果元素已经处理过且已有内容非0则不再处理
if (el.classList.contains('processed') && el.textContent !== '0') return;
el.classList.add('processed');
const url = el.dataset.url;
const baseUrl = el.dataset.umamiBaseUrl;
const shareId = el.dataset.umamiShareId;
const timezone = el.dataset.umamiTimezone;
if (!baseUrl || !shareId) return;
try {
// Check if fetchUmamiStats exists
if (typeof window.fetchUmamiStats !== 'function') return;
const statsData = await window.fetchUmamiStats(baseUrl, shareId, {
url: url,
timezone: timezone
});
const pageviews = (statsData.pageviews && statsData.pageviews.value) || statsData.pageviews || 0;
// 如果数据来自缓存,直接显示结果,跳过动画
if (statsData._fromCache) {
el.innerHTML = pageviews;
return;
}
const startVal = parseInt(el.textContent) || 0;
if (startVal !== pageviews) {
// 只有当开始值是0的时候才播放动画首次加载
if (startVal === 0) {
animateValue(el, startVal, pageviews, 1000);
} else {
el.innerHTML = pageviews;
}
}
} catch (e) {
console.error('Failed to load stats for', url, e);
}
});
}
document.addEventListener('DOMContentLoaded', loadCardStats);
document.addEventListener('swup:contentReplaced', loadCardStats);
</script>

View File

@@ -1,9 +1,9 @@
--- ---
import { Icon } from "astro-icon/components"; import { Icon } from "astro-icon/components";
import { getDir, url } from "../utils/url-utils";
import { formatDateToYYYYMMDD } from "../utils/date-utils";
import { umamiConfig } from "../config"; import { umamiConfig } from "../config";
import { formatDateToYYYYMMDD } from "../utils/date-utils";
import { url, getDir } from "../utils/url-utils";
interface Props { interface Props {
class: string; class: string;
@@ -52,13 +52,13 @@ const className = Astro.props.class;
<div class="meta-icon"> <div class="meta-icon">
<Icon name="material-symbols:visibility-outline-rounded" class="text-xl"></Icon> <Icon name="material-symbols:visibility-outline-rounded" class="text-xl"></Icon>
</div> </div>
<span class="text-50 text-sm font-medium" id={`page-views-${slug}`}>-</span> <span class="text-50 text-sm font-medium" id={`page-views-${slug}`}>0 次</span>
</div> </div>
<div class="flex items-center"> <div class="flex items-center">
<div class="meta-icon"> <div class="meta-icon">
<Icon name="material-symbols:person" class="text-xl"></Icon> <Icon name="material-symbols:person" class="text-xl"></Icon>
</div> </div>
<span class="text-50 text-sm font-medium" id={`page-visitors-${slug}`}>-</span> <span class="text-50 text-sm font-medium" id={`page-visitors-${slug}`}>0 人</span>
</div> </div>
</> </>
)} )}
@@ -66,6 +66,21 @@ const className = Astro.props.class;
{slug && ( {slug && (
<script define:vars={{ slug, umamiConfig }}> <script define:vars={{ slug, umamiConfig }}>
// 数字动画函数
function animateValue(obj, start, end, duration, suffix = '') {
let startTimestamp = null;
const step = (timestamp) => {
if (!startTimestamp) startTimestamp = timestamp;
const progress = Math.min((timestamp - startTimestamp) / duration, 1);
obj.innerHTML = `${Math.floor(progress * (end - start) + start)} ${suffix}`;
if (progress < 1) {
window.requestAnimationFrame(step);
} else {
obj.innerHTML = `${end} ${suffix}`;
}
};
window.requestAnimationFrame(step);
}
// 获取访问量统计 // 获取访问量统计
async function fetchPageViews() { async function fetchPageViews() {
@@ -76,19 +91,42 @@ const className = Astro.props.class;
path: `eq./posts/${slug}/` path: `eq./posts/${slug}/`
}); });
const pageViews = statsData.pageviews || 0; const pageViews = (statsData.pageviews && statsData.pageviews.value) || statsData.pageviews || 0;
const visits = statsData.visitors || 0; const visits = (statsData.visitors && statsData.visitors.value) || statsData.visitors || 0;
const viewsElement = document.getElementById(`page-views-${slug}`); const viewsElement = document.getElementById(`page-views-${slug}`);
const visitorsElement = document.getElementById(`page-visitors-${slug}`); const visitorsElement = document.getElementById(`page-visitors-${slug}`);
if (viewsElement) viewsElement.textContent = `${pageViews} 次`;
if (visitorsElement) visitorsElement.textContent = `${visits} 人`; // 如果数据来自缓存,直接显示结果,跳过动画
if (statsData._fromCache) {
if (viewsElement) viewsElement.innerHTML = `${pageViews} 次`;
if (visitorsElement) visitorsElement.innerHTML = `${visits} 人`;
return;
}
if (viewsElement) {
const currentViews = parseInt(viewsElement.textContent) || 0;
if (currentViews !== pageViews) {
if (currentViews === 0) {
animateValue(viewsElement, currentViews, pageViews, 1000, '次');
} else {
viewsElement.innerHTML = `${pageViews} 次`;
}
}
}
if (visitorsElement) {
const currentVisits = parseInt(visitorsElement.textContent) || 0;
if (currentVisits !== visits) {
if (currentVisits === 0) {
animateValue(visitorsElement, currentVisits, visits, 1000, '人');
} else {
visitorsElement.innerHTML = `${visits} 人`;
}
}
}
} catch (error) { } catch (error) {
console.error('Error fetching page views:', error); console.error('Error fetching page views:', error);
const viewsElement = document.getElementById(`page-views-${slug}`);
const visitorsElement = document.getElementById(`page-visitors-${slug}`);
if (viewsElement) viewsElement.textContent = '-';
if (visitorsElement) visitorsElement.textContent = '-';
} }
} }
@@ -98,5 +136,5 @@ const className = Astro.props.class;
} else { } else {
fetchPageViews(); fetchPageViews();
} }
</script> </script>
)} )}

View File

@@ -1,5 +1,4 @@
<script lang="ts"> <script lang="ts">
import Icon from "@iconify/svelte"; import Icon from "@iconify/svelte";
import { url } from "@utils/url-utils.ts"; import { url } from "@utils/url-utils.ts";
import { onMount } from "svelte"; import { onMount } from "svelte";
@@ -17,6 +16,7 @@ let keywordDesktop = "";
let keywordMobile = ""; let keywordMobile = "";
let result: SearchResult[] = []; let result: SearchResult[] = [];
let isSearching = false; let isSearching = false;
// biome-ignore lint/suspicious/noExplicitAny: Temporary usage of any for posts array
let posts: any[] = []; let posts: any[] = [];
const togglePanel = () => { const togglePanel = () => {
@@ -59,33 +59,35 @@ const search = async (keyword: string, isDesktop: boolean): Promise<void> => {
const urlPath = `/posts/${post.link}`; const urlPath = `/posts/${post.link}`;
// 支持内容搜索和URL后缀搜索 // 支持内容搜索和URL后缀搜索
return searchText.includes(keywordLower) || return (
searchText.includes(keywordLower) ||
urlPath.toLowerCase().includes(keywordLower) || urlPath.toLowerCase().includes(keywordLower) ||
post.link.toLowerCase().includes(keywordLower); post.link.toLowerCase().includes(keywordLower)
);
}) })
.map((post) => { .map((post) => {
const contentLower = post.content.toLowerCase(); const contentLower = post.content.toLowerCase();
const keywordLower = keyword.toLowerCase(); const keywordLower = keyword.toLowerCase();
const contentIndex = contentLower.indexOf(keywordLower); const contentIndex = contentLower.indexOf(keywordLower);
let excerpt = ''; let excerpt = "";
if (contentIndex !== -1) { if (contentIndex !== -1) {
const start = Math.max(0, contentIndex - 50); const start = Math.max(0, contentIndex - 50);
const end = Math.min(post.content.length, contentIndex + 100); const end = Math.min(post.content.length, contentIndex + 100);
excerpt = post.content.substring(start, end); excerpt = post.content.substring(start, end);
if (start > 0) excerpt = '...' + excerpt; if (start > 0) excerpt = `...${excerpt}`;
if (end < post.content.length) excerpt = excerpt + '...'; if (end < post.content.length) excerpt = `${excerpt}...`;
} else { } else {
excerpt = post.description || post.content.substring(0, 150) + '...'; excerpt = post.description || `${post.content.substring(0, 150)}...`;
} }
return { return {
url: url(`/posts/${post.link}/`), url: url(`/posts/${post.link}/`),
meta: { meta: {
title: post.title title: post.title,
}, },
excerpt: highlightText(excerpt, keyword), excerpt: highlightText(excerpt, keyword),
urlPath: `/posts/${post.link}` urlPath: `/posts/${post.link}`,
}; };
}); });
@@ -124,7 +126,10 @@ onMount(async () => {
title: item.querySelector("title")?.textContent || "", title: item.querySelector("title")?.textContent || "",
description: item.querySelector("description")?.textContent || "", description: item.querySelector("description")?.textContent || "",
content: content, content: content,
link: item.querySelector("link")?.textContent?.replace(/.*\/posts\/(.*?)\//, "$1") || "", link:
item
.querySelector("link")
?.textContent?.replace(/.*\/posts\/(.*?)\//, "$1") || "",
}; };
}); });
} catch (error) { } catch (error) {

View File

@@ -9,8 +9,8 @@ interface Props {
basePath?: string; basePath?: string;
} }
import { Image } from "astro:assets"; import { Image } from "astro:assets";
import { url } from "../../utils/url-utils";
import { imageFallbackConfig, siteConfig } from "../../config"; import { imageFallbackConfig, siteConfig } from "../../config";
import { url } from "../../utils/url-utils";
const { id, src, alt, position = "center", basePath = "/" } = Astro.props; const { id, src, alt, position = "center", basePath = "/" } = Astro.props;
const className = Astro.props.class; const className = Astro.props.class;

View File

@@ -1,27 +1,27 @@
<script lang="ts"> <script lang="ts">
import { onMount } from "svelte"; import { AUTO_MODE, DARK_MODE, LIGHT_MODE } from "@constants/constants";
import Icon from "@iconify/svelte"; import Icon from "@iconify/svelte";
import { import {
getDefaultHue,
getHue,
setHue,
getStoredTheme,
setTheme,
getRainbowMode,
setRainbowMode,
getRainbowSpeed,
setRainbowSpeed,
getBgBlur, getBgBlur,
getDefaultHue,
getDevMode,
getDevServer,
getHideBg,
getHue,
getRainbowMode,
getRainbowSpeed,
getStoredTheme,
setBgBlur, setBgBlur,
setBgHueRotate, setBgHueRotate,
getHideBg,
setHideBg,
getDevMode,
setDevMode, setDevMode,
getDevServer,
setDevServer, setDevServer,
setHideBg,
setHue,
setRainbowMode,
setRainbowSpeed,
setTheme,
} from "@utils/setting-utils"; } from "@utils/setting-utils";
import { AUTO_MODE, DARK_MODE, LIGHT_MODE } from "@constants/constants"; import { onMount } from "svelte";
let hue = getHue(); let hue = getHue();
let theme = getStoredTheme(); let theme = getStoredTheme();
@@ -102,7 +102,7 @@ onMount(() => {
} }
return () => { return () => {
if (animationId) cancelAnimationFrame(animationId); if (animationId) cancelAnimationFrame(animationId);
} };
}); });
</script> </script>

View File

@@ -1,6 +1,6 @@
--- ---
import { Icon } from "astro-icon/components"; import { Icon } from "astro-icon/components";
import { profileConfig, umamiConfig, siteConfig } from "../../config"; import { profileConfig, siteConfig, umamiConfig } from "../../config";
const config = profileConfig; const config = profileConfig;
--- ---
@@ -35,14 +35,14 @@ const config = profileConfig;
<Icon name="material-symbols:visibility-outline" class="text-base"></Icon> <Icon name="material-symbols:visibility-outline" class="text-base"></Icon>
<span class="text-xs">访问量</span> <span class="text-xs">访问量</span>
</div> </div>
<div id="site-views" class="font-bold text-lg text-neutral-700 dark:text-neutral-300">-</div> <div id="site-views" class="font-bold text-lg text-neutral-700 dark:text-neutral-300">0</div>
</div> </div>
<div class="text-center border-l border-neutral-300 dark:border-neutral-700"> <div class="text-center border-l border-neutral-300 dark:border-neutral-700">
<div class="text-xs text-neutral-500 mb-1 flex items-center justify-center gap-1"> <div class="text-xs text-neutral-500 mb-1 flex items-center justify-center gap-1">
<Icon name="material-symbols:person" class="text-base"></Icon> <Icon name="material-symbols:person" class="text-base"></Icon>
<span class="text-xs">访客数</span> <span class="text-xs">访客数</span>
</div> </div>
<div id="site-visitors" class="font-bold text-lg text-neutral-700 dark:text-neutral-300">-</div> <div id="site-visitors" class="font-bold text-lg text-neutral-700 dark:text-neutral-300">0</div>
</div> </div>
</div> </div>
</div> </div>
@@ -68,6 +68,22 @@ const config = profileConfig;
</style> </style>
<script define:vars={{ umamiConfig}}> <script define:vars={{ umamiConfig}}>
// 数字动画函数
function animateValue(obj, start, end, duration) {
let startTimestamp = null;
const step = (timestamp) => {
if (!startTimestamp) startTimestamp = timestamp;
const progress = Math.min((timestamp - startTimestamp) / duration, 1);
obj.innerHTML = Math.floor(progress * (end - start) + start);
if (progress < 1) {
window.requestAnimationFrame(step);
} else {
obj.innerHTML = end;
}
};
window.requestAnimationFrame(step);
}
// 获取全站访问量统计 // 获取全站访问量统计
async function loadSiteStats() { async function loadSiteStats() {
if (!umamiConfig.enable) return; if (!umamiConfig.enable) return;
@@ -81,8 +97,22 @@ const config = profileConfig;
const viewsElement = document.getElementById('site-views'); const viewsElement = document.getElementById('site-views');
const visitorsElement = document.getElementById('site-visitors'); const visitorsElement = document.getElementById('site-visitors');
if (viewsElement) viewsElement.textContent = pageviews;
if (visitorsElement) visitorsElement.textContent = visitors; if (viewsElement) {
const startVal = parseInt(viewsElement.textContent) || 0;
// 如果当前值已经是目标值,就不执行动画
if (startVal !== pageviews) {
animateValue(viewsElement, startVal, pageviews, 1000);
}
}
if (visitorsElement) {
const startVal = parseInt(visitorsElement.textContent) || 0;
// 如果当前值已经是目标值,就不执行动画
if (startVal !== visitors) {
animateValue(visitorsElement, startVal, visitors, 1000);
}
}
} catch (error) { } catch (error) {
console.error('获取全站统计失败:', error); console.error('获取全站统计失败:', error);
} }
@@ -90,4 +120,6 @@ const config = profileConfig;
// 页面加载完成后获取统计数据 // 页面加载完成后获取统计数据
document.addEventListener('DOMContentLoaded', loadSiteStats); document.addEventListener('DOMContentLoaded', loadSiteStats);
// 监听 Swup 内容替换事件,确保页面切换后重新获取数据
document.addEventListener('content:replace', loadSiteStats);
</script> </script>

View File

@@ -79,13 +79,13 @@ export const navBarConfig: NavBarConfig = {
{ {
name: "他站", name: "他站",
url: "/posts/other-sites/", // Internal links should not include the base path, as it is automatically added url: "/posts/other-sites/", // Internal links should not include the base path, as it is automatically added
external: true, // Show an external link icon and will open in a new tab external: false, // Show an external link icon and will open in a new tab
}, },
{ {
name: "统计", name: "统计",
url: "https://umami.acofork.com/share/CdkXbGgZr6ECKOyK", // Internal links should not include the base path, as it is automatically added url: "https://umami.acofork.com/share/CdkXbGgZr6ECKOyK", // Internal links should not include the base path, as it is automatically added
external: true, // Show an external link icon and will open in a new tab external: true, // Show an external link icon and will open in a new tab
} },
], ],
}; };

View File

@@ -1,6 +1,5 @@
import { LinkPreset, type NavBarLink } from "@/types/config"; import { LinkPreset, type NavBarLink } from "@/types/config";
export const LinkPresets: { [key in LinkPreset]: NavBarLink } = { export const LinkPresets: { [key in LinkPreset]: NavBarLink } = {
[LinkPreset.Home]: { [LinkPreset.Home]: {
name: "首页", name: "首页",

View File

@@ -1,3 +1 @@
[ ["obsidian-paste-image-rename"]
"obsidian-paste-image-rename"
]

File diff suppressed because it is too large Load Diff

View File

@@ -21,7 +21,7 @@ const postsCollection = defineCollection({
}); });
const assetsCollection = defineCollection({ const assetsCollection = defineCollection({
type: 'data', type: "data",
schema: z.object({ schema: z.object({
title: z.string().optional(), title: z.string().optional(),
description: z.string().optional(), description: z.string().optional(),

View File

@@ -3,4 +3,4 @@
"avatar": "https://sisubeny.space/img/ff_hu_5652443c9e3495e9.png", "avatar": "https://sisubeny.space/img/ff_hu_5652443c9e3495e9.png",
"description": "SISUBENY's Blog", "description": "SISUBENY's Blog",
"url": "https://sisubeny.space/" "url": "https://sisubeny.space/"
} }

View File

@@ -1,5 +1,5 @@
--- ---
import Analytics from '@vercel/analytics/astro' import Analytics from "@vercel/analytics/astro";
import "@fontsource/roboto/400.css"; import "@fontsource/roboto/400.css";
import "@fontsource/roboto/500.css"; import "@fontsource/roboto/500.css";
import "@fontsource/roboto/700.css"; import "@fontsource/roboto/700.css";
@@ -730,3 +730,12 @@ if (window.swup) {
document.addEventListener("swup:enable", setup) document.addEventListener("swup:enable", setup)
} }
</script> </script>
<svg style="position: absolute; width: 0; height: 0; overflow: hidden;" aria-hidden="true">
<defs>
<filter id="liquid-glass">
<feTurbulence type="fractalNoise" baseFrequency="0.05" numOctaves="2" result="noise" />
<feDisplacementMap in="SourceGraphic" in2="noise" scale="20" xChannelSelector="R" yChannelSelector="G" />
</filter>
</defs>
</svg>

View File

@@ -1,8 +1,8 @@
--- ---
import { siteConfig } from "@/config";
import Layout from "@/layouts/Layout.astro"; import Layout from "@/layouts/Layout.astro";
import MainGridLayout from "@/layouts/MainGridLayout.astro"; import MainGridLayout from "@/layouts/MainGridLayout.astro";
import { Icon } from "astro-icon/components"; import { Icon } from "astro-icon/components";
import { siteConfig } from "@/config";
--- ---
<Layout title="页面未找到"> <Layout title="页面未找到">

View File

@@ -1,10 +1,15 @@
--- ---
import { siteConfig } from "@/config";
import type { Friend } from "@/types/data";
import MainGridLayout from "@layouts/MainGridLayout.astro"; import MainGridLayout from "@layouts/MainGridLayout.astro";
import { Icon } from "astro-icon/components"; import { Icon } from "astro-icon/components";
import type { Friend } from "@/types/data";
import { siteConfig } from "@/config";
const friends = Object.values(import.meta.glob<Friend>("@/data/friends/*.json", { eager: true, import: "default" })); const friends = Object.values(
import.meta.glob<Friend>("@/data/friends/*.json", {
eager: true,
import: "default",
}),
);
--- ---
<MainGridLayout title="友链"> <MainGridLayout title="友链">

View File

@@ -10,7 +10,7 @@ import { Icon } from "astro-icon/components";
import { gitHubEditConfig, licenseConfig } from "src/config"; import { gitHubEditConfig, licenseConfig } from "src/config";
import PostMetadata from "../../components/PostMeta.astro"; import PostMetadata from "../../components/PostMeta.astro";
import ImageWrapper from "../../components/misc/ImageWrapper.astro"; import ImageWrapper from "../../components/misc/ImageWrapper.astro";
import { profileConfig, siteConfig } from "../../config"; import { profileConfig, siteConfig, umamiConfig } from "../../config";
import { formatDateToYYYYMMDD } from "../../utils/date-utils"; import { formatDateToYYYYMMDD } from "../../utils/date-utils";
export async function getStaticPaths() { export async function getStaticPaths() {
@@ -278,6 +278,60 @@ const jsonLd = {
document.addEventListener('swup:contentReplaced', setupImageLoading); document.addEventListener('swup:contentReplaced', setupImageLoading);
</script> </script>
<script define:vars={{ umamiConfig, postUrl: getPostUrlBySlug(entry.slug) }}>
// 数字动画函数
function animateValue(obj, start, end, duration) {
let startTimestamp = null;
const step = (timestamp) => {
if (!startTimestamp) startTimestamp = timestamp;
const progress = Math.min((timestamp - startTimestamp) / duration, 1);
obj.innerHTML = Math.floor(progress * (end - start) + start);
if (progress < 1) {
window.requestAnimationFrame(step);
} else {
obj.innerHTML = end;
}
};
window.requestAnimationFrame(step);
}
async function loadPageViews() {
if (!umamiConfig.enable) return;
try {
const statsData = await fetchUmamiStats(umamiConfig.baseUrl, umamiConfig.shareId, {
url: postUrl,
timezone: umamiConfig.timezone
});
const pageviews = (statsData.pageviews && statsData.pageviews.value) || statsData.pageviews || 0;
const element = document.getElementById('post-pageviews');
if (element) {
// 如果数据来自缓存,直接显示结果,跳过动画
if (statsData._fromCache) {
element.innerHTML = pageviews;
return;
}
const startVal = parseInt(element.textContent) || 0;
if (startVal !== pageviews) {
if (startVal === 0) {
animateValue(element, startVal, pageviews, 1000);
} else {
element.innerHTML = pageviews;
}
}
}
} catch (error) {
console.error('获取页面访问量失败:', error);
}
}
document.addEventListener('DOMContentLoaded', loadPageViews);
document.addEventListener('swup:contentReplaced', loadPageViews);
</script>
<style is:global> <style is:global>
@keyframes loading-progress { @keyframes loading-progress {
0% { 0% {

View File

@@ -1,24 +1,24 @@
import rss from '@astrojs/rss'; import { getImage } from "astro:assets";
import sanitizeHtml from 'sanitize-html'; import { getCollection } from "astro:content";
import MarkdownIt from 'markdown-it'; import { siteConfig } from "@/config";
import { getCollection } from 'astro:content'; import { getSortedPosts } from "@/utils/content-utils";
import { siteConfig } from '@/config'; import rss from "@astrojs/rss";
import { parse as htmlParser } from 'node-html-parser'; import type { RSSFeedItem } from "@astrojs/rss";
import { getImage } from 'astro:assets'; import type { APIContext, ImageMetadata } from "astro";
import type { APIContext, ImageMetadata } from 'astro'; import MarkdownIt from "markdown-it";
import type { RSSFeedItem } from '@astrojs/rss'; import { parse as htmlParser } from "node-html-parser";
import { getSortedPosts } from '@/utils/content-utils'; import sanitizeHtml from "sanitize-html";
const markdownParser = new MarkdownIt(); const markdownParser = new MarkdownIt();
// get dynamic import of images as a map collection // get dynamic import of images as a map collection
const imagesGlob = import.meta.glob<{ default: ImageMetadata }>( const imagesGlob = import.meta.glob<{ default: ImageMetadata }>(
'/src/content/**/*.{jpeg,jpg,png,gif,webp}', // include posts and assets "/src/content/**/*.{jpeg,jpg,png,gif,webp}", // include posts and assets
); );
export async function GET(context: APIContext) { export async function GET(context: APIContext) {
if (!context.site) { if (!context.site) {
throw Error('site not set'); throw Error("site not set");
} }
// Use the same ordering as site listing (pinned first, then by published desc) // Use the same ordering as site listing (pinned first, then by published desc)
@@ -27,38 +27,40 @@ export async function GET(context: APIContext) {
for (const post of posts) { for (const post of posts) {
// convert markdown to html string // convert markdown to html string
const body = markdownParser.render(post.body || ''); const body = markdownParser.render(post.body || "");
// convert html string to DOM-like structure // convert html string to DOM-like structure
const html = htmlParser.parse(body); const html = htmlParser.parse(body);
// hold all img tags in variable images // hold all img tags in variable images
const images = html.querySelectorAll('img'); const images = html.querySelectorAll("img");
for (const img of images) { for (const img of images) {
const src = img.getAttribute('src'); const src = img.getAttribute("src");
if (!src) continue; if (!src) continue;
// Handle content-relative images and convert them to built _astro paths // Handle content-relative images and convert them to built _astro paths
if (src.startsWith('./') || src.startsWith('../')) { if (src.startsWith("./") || src.startsWith("../")) {
let importPath: string | null = null; let importPath: string | null = null;
if (src.startsWith('./')) { if (src.startsWith("./")) {
// Path relative to the post file directory // Path relative to the post file directory
const prefixRemoved = src.slice(2); const prefixRemoved = src.slice(2);
importPath = `/src/content/posts/${prefixRemoved}`; importPath = `/src/content/posts/${prefixRemoved}`;
} else { } else {
// Path like ../assets/images/xxx -> relative to /src/content/ // Path like ../assets/images/xxx -> relative to /src/content/
const cleaned = src.replace(/^\.\.\//, ''); const cleaned = src.replace(/^\.\.\//, "");
importPath = `/src/content/${cleaned}`; importPath = `/src/content/${cleaned}`;
} }
const imageMod = await imagesGlob[importPath]?.()?.then((res) => res.default); const imageMod = await imagesGlob[importPath]?.()?.then(
(res) => res.default,
);
if (imageMod) { if (imageMod) {
const optimizedImg = await getImage({ src: imageMod }); const optimizedImg = await getImage({ src: imageMod });
img.setAttribute('src', new URL(optimizedImg.src, context.site).href); img.setAttribute("src", new URL(optimizedImg.src, context.site).href);
} }
} else if (src.startsWith('/')) { } else if (src.startsWith("/")) {
// images starting with `/` are in public dir // images starting with `/` are in public dir
img.setAttribute('src', new URL(src, context.site).href); img.setAttribute("src", new URL(src, context.site).href);
} }
} }
@@ -69,14 +71,14 @@ export async function GET(context: APIContext) {
link: `/posts/${post.slug}/`, link: `/posts/${post.slug}/`,
// sanitize the new html string with corrected image paths // sanitize the new html string with corrected image paths
content: sanitizeHtml(html.toString(), { content: sanitizeHtml(html.toString(), {
allowedTags: sanitizeHtml.defaults.allowedTags.concat(['img']), allowedTags: sanitizeHtml.defaults.allowedTags.concat(["img"]),
}), }),
}); });
} }
return rss({ return rss({
title: siteConfig.title, title: siteConfig.title,
description: siteConfig.subtitle || 'No description', description: siteConfig.subtitle || "No description",
site: context.site, site: context.site,
items: feed, items: feed,
customData: `<language>${siteConfig.lang}</language>`, customData: `<language>${siteConfig.lang}</language>`,

View File

@@ -1,10 +1,15 @@
--- ---
import { siteConfig } from "@/config";
import type { Sponsor } from "@/types/data";
import MainGridLayout from "@layouts/MainGridLayout.astro"; import MainGridLayout from "@layouts/MainGridLayout.astro";
import { Icon } from "astro-icon/components"; import { Icon } from "astro-icon/components";
import type { Sponsor } from "@/types/data";
import { siteConfig } from "@/config";
const sponsors = Object.values(import.meta.glob<Sponsor>("@/data/sponsors/*.json", { eager: true, import: "default" })); const sponsors = Object.values(
import.meta.glob<Sponsor>("@/data/sponsors/*.json", {
eager: true,
import: "default",
}),
);
--- ---
<MainGridLayout title="赞助支持"> <MainGridLayout title="赞助支持">

View File

@@ -43,7 +43,7 @@ export function UrlCardComponent(properties, children) {
const nTitleText = h( const nTitleText = h(
`div#${cardUuid}-title`, `div#${cardUuid}-title`,
{ class: "uc-title-text" }, { class: "uc-title-text" },
"Loading..." "Loading...",
); );
const nScript = h( const nScript = h(
@@ -97,11 +97,7 @@ export function UrlCardComponent(properties, children) {
}, },
[ [
h(`div#${cardUuid}-container`, { class: "uc-container" }, [ h(`div#${cardUuid}-container`, { class: "uc-container" }, [
h("div", { class: "uc-content" }, [ h("div", { class: "uc-content" }, [nTitle, nTitleText, nDescription]),
nTitle,
nTitleText,
nDescription,
]),
nImage, nImage,
]), ]),
nScript, nScript,

View File

@@ -141,3 +141,20 @@
.collapsed { .collapsed {
height: var(--collapsedHeight); height: var(--collapsedHeight);
} }
.shiny-text {
animation: shine 5s linear infinite;
}
@keyframes shine {
0% {
background-position: 100%;
}
100% {
background-position: -100%;
}
}
.shiny-text.disabled {
animation: none;
}

View File

@@ -92,8 +92,6 @@ export type UmamiConfig = {
timezone: string; timezone: string;
}; };
export type LIGHT_DARK_MODE = export type LIGHT_DARK_MODE =
| typeof LIGHT_MODE | typeof LIGHT_MODE
| typeof DARK_MODE | typeof DARK_MODE

View File

@@ -1,6 +1,5 @@
import { getCollection } from "astro:content"; import { getCollection } from "astro:content";
export async function getSortedPosts() { export async function getSortedPosts() {
const allBlogPosts = await getCollection("posts", ({ data }) => { const allBlogPosts = await getCollection("posts", ({ data }) => {
return import.meta.env.PROD ? data.draft !== true : true; return import.meta.env.PROD ? data.draft !== true : true;
@@ -27,4 +26,3 @@ export async function getSortedPosts() {
return sorted; return sorted;
} }

View File

@@ -18,7 +18,7 @@ export function getHue(): number {
return stored ? Number.parseInt(stored) : getDefaultHue(); return stored ? Number.parseInt(stored) : getDefaultHue();
} }
export function setHue(hue: number, save: boolean = true): void { export function setHue(hue: number, save = true): void {
if (save) { if (save) {
localStorage.setItem("hue", String(hue)); localStorage.setItem("hue", String(hue));
} }
@@ -56,7 +56,10 @@ export function setBgBlur(blur: number): void {
const currentFilter = bgBox.style.filter || ""; const currentFilter = bgBox.style.filter || "";
const hueRotateMatch = currentFilter.match(/hue-rotate\((.*?)deg\)/); const hueRotateMatch = currentFilter.match(/hue-rotate\((.*?)deg\)/);
const hueRotate = hueRotateMatch ? hueRotateMatch[1] : "0"; const hueRotate = hueRotateMatch ? hueRotateMatch[1] : "0";
bgBox.style.setProperty("filter", `blur(${blur}px) hue-rotate(${hueRotate}deg)`); bgBox.style.setProperty(
"filter",
`blur(${blur}px) hue-rotate(${hueRotate}deg)`,
);
} }
} }

View File

@@ -13,8 +13,6 @@ export function getPostUrlBySlug(slug: string): string {
return url(`/posts/${slug}/`); return url(`/posts/${slug}/`);
} }
export function getDir(path: string): string { export function getDir(path: string): string {
const lastSlashIndex = path.lastIndexOf("/"); const lastSlashIndex = path.lastIndexOf("/");
if (lastSlashIndex < 0) { if (lastSlashIndex < 0) {

View File

@@ -1,5 +1,5 @@
/** @type {import('tailwindcss').Config} */ /** @type {import('tailwindcss').Config} */
const defaultTheme = require("tailwindcss/defaultTheme") const defaultTheme = require("tailwindcss/defaultTheme");
module.exports = { module.exports = {
content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue,mjs}"], content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue,mjs}"],
darkMode: "class", // allows toggling dark mode manually darkMode: "class", // allows toggling dark mode manually
@@ -11,4 +11,4 @@ module.exports = {
}, },
}, },
plugins: [require("@tailwindcss/typography")], plugins: [require("@tailwindcss/typography")],
} };

View File

@@ -5,5 +5,4 @@
"directory": "./dist", "directory": "./dist",
"not_found_handling": "404-page" "not_found_handling": "404-page"
} }
} }