From ce41c800ba61d6ff2f4fc670b314bd8be0c5cf41 Mon Sep 17 00:00:00 2001 From: wait4xx Date: Sat, 24 Oct 2026 23:00:20 +0800 Subject: [PATCH 01/10] =?UTF-8?q?chore(spec):=20=E5=88=9B=E5=BB=BA=20add-b?= =?UTF-8?q?log-skeleton=20=E4=BB=BB=E5=8A=A1=E5=8C=85=EF=BC=88Phase=201=20?= =?UTF-8?q?=E5=8D=81=E4=BB=BB=E5=8A=A1=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Spec: 2026-10-24_add-blog-skeleton --- .../2026-10-24_add-blog-skeleton/spec.md | 83 +++++++++++++++++++ .../2026-10-24_add-blog-skeleton/tasks.md | 69 +++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 .spec/specs/2026-10-24_add-blog-skeleton/spec.md create mode 100644 .spec/specs/2026-10-24_add-blog-skeleton/tasks.md diff --git a/.spec/specs/2026-10-24_add-blog-skeleton/spec.md b/.spec/specs/2026-10-24_add-blog-skeleton/spec.md new file mode 100644 index 0000000..9f18543 --- /dev/null +++ b/.spec/specs/2026-10-24_add-blog-skeleton/spec.md @@ -0,0 +1,83 @@ +# Phase 1:Astro 骨架+设计系统+五页型+极客层 P0 - 项目范围 + + + +## 1. 问题定义 +- **项目目标**:在 Astro 5 上实现博客前端全骨架——设计 tokens、自托管分片字体、三轨内容集合、五类页面、明暗模式、极客层 P0、搜索/RSS,可在 staging 演练部署 +- **目标用户**:站长(Phase 2 迁入真实内容即可上线) +- **核心价值**:丙路线「灰阶骨架×分轨正文」从样板变成可构建可部署的真实代码 + +## 2. 假设与待确认 + +### 2.1 已确认事实 +- Node v22.22.3 + pnpm 11.3.0 可用;remote origin = https://git.wait4x.online/wait4x/blog.git(Phase 0 已推 main) +- 设计规格全部定稿(docs/博客重设计调研报告.md v1.8 §2 丙路线/§3 排版参数/§4c 极客层/§4e 多端) +- 样板参考 design/mockup.html(v2,1050 行,三属性驱动:route/scheme/page) +- 预字体包:lxgw-wenkai-screen-webfont / @fontsource/noto-sans-sc / @fontsource/jetbrains-mono(npm 预分片自托管,替代 cn-font-split 构建步) + +### 2.2 关键假设 +- 上述 npm 预分片字体包的 unicode-range 切片质量满足按需加载(若不满足,回退 vite-plugin-font 方案) +- 样例内容(等待戈多等)可先行入库 content/,Phase 2 再被真实迁移覆盖 + +### 2.3 待确认问题 +- [x] Lighthouse 移动端 ≥90 需真实域名(Phase 4 预发布验收执行;本包只做结构自查)→ 结论:按此执行 + +### 2.4 可选解释与取舍 +- 预分片 npm 字体包 > cn-font-split 构建:零构建工具、社区维护切片、同样自托管;代价是包体切片策略不可定制 → 接受 +- 样例内容先行 > 空集合:页面开发需要真实排版观感(书评长文/代码块/照片比例)→ 接受 + +### 2.5 已证伪路径 +- 无 + +## 3. 功能范围 + +### 3.1 核心功能(MVP) +- [ ] T1 Astro 5 初始化(pnpm+TS strict) +- [ ] T2 设计 tokens + 全局样式(丙路线参数) +- [ ] T3 自托管分片字体三轨接入 +- [ ] T4 内容集合(posts/moments/photos + EXIF loader) +- [ ] T5 布局/导航/页脚/明暗不闪烁 +- [ ] T6 五页型(首页/文章双模板/图库/瞬间/关于) +- [ ] T7 极客层 P0(键盘+帮助/build-info/View Transitions/项目墙) +- [ ] T8 Artalk 占位 + Pagefind + RSS + sitemap +- [ ] T9 响应式结构自查(§4e 断点全覆盖) +- [ ] T10 staging 部署演练(build.sh 填实) + +### 3.2 扩展功能 +- 书评索引画廊页、/now·/stack·/colophon(Phase 4+ 二期) + +### 3.3 不在范围内 +- 真实内容迁移(Phase 2)、双语管线(Phase 3)、上线切换与 Lighthouse 实测(Phase 4)、Halo 退役(Phase 5) + +## 4. 最小实现路径 +- 单 Astro 项目根目录 src/{layouts,components,pages,styles,content},无多余工作区 +- 暂不引入:React/Vue 框架、tailwind(原生 CSS + tokens 足够且更快)、CMS 适配层 +- 项目墙构建时 fetch 失败用仓内缓存 JSON 兜底(src/data/projects-fallback.json) + +## 5. 技术决策 +- 技术栈:Astro 5 + 原生 TS/CSS;包管理 pnpm +- 证据协议:evidence: runs(verify 由 spec_verify 真实执行) +- 本轮允许改动:仓库 src/、public/、package.json、pnpm-lock.yaml、astro.config.*、tsconfig.json、content/、infra/deploy/build.sh、.spec/ +- 本轮不应触碰:infra/{gitea,artalk}/、~/docker_apps/ 运行实例、nginx、生产 Halo +- Git integration branch:`spec/2026-10-24_add-blog-skeleton` + +### 5.1 验证策略 +- 范围级别:package +- 变更对象:src/ 全部源码、content/ 样例集合、public/ 静态资产、构建配置、build.sh +- 快速检查:`pnpm astro build`(全包 verify 的基座命令) +- 集成检查:dist/ 路由产物断言(五页型 HTML 存在、字体分片计数、pagefind/rss/sitemap 产出) +- 全项目检查:staging 部署演练 + rollback-dryrun 仍绿;仅在 src 构建链/部署脚本/共享基础设施变更时升级范围重跑 +- 升级触发:只有改动构建链(astro/字体/搜索集成)、build.sh 或暴露公网入口时,才升级验证范围并记录理由 + +## 6. 成功标准与验证方式 +- [ ] `pnpm astro build` exit 0 且零框架 JS 依赖(仅原生脚本) -> verify: task_0001 +- [ ] 五页型路由 HTML 全部生成于 dist/ -> verify: task_0006 +- [ ] 字体分片自托管产出(woff2 切片 >50 个文件) -> verify: task_0003 +- [ ] 极客层 P0 标记齐全(键盘脚本/帮助浮层/built-from/ClientRouter/项目墙区块) -> verify: task_0007 +- [ ] Pagefind 索引 + rss.xml + sitemap 产出 -> verify: task_0008 +- [ ] staging 目录更新 + 回滚干跑仍绿 -> verify: task_0010 + +## 7. 风险与约束 +- 预分片字体包若含 latin-only 假冒 CJK 切片 → 构建后抽查切片数与体积 -> 验证步覆盖 +- exifr 对样例占位图无 EXIF → loader 需容错空值 -> schema 可选字段 +- View Transitions 三引擎兼容(caniuse 已核)→ 降级 CSS 直切,无破坏 diff --git a/.spec/specs/2026-10-24_add-blog-skeleton/tasks.md b/.spec/specs/2026-10-24_add-blog-skeleton/tasks.md new file mode 100644 index 0000000..5019867 --- /dev/null +++ b/.spec/specs/2026-10-24_add-blog-skeleton/tasks.md @@ -0,0 +1,69 @@ +# Phase 1:Astro 骨架+设计系统+五页型+极客层 P0 - 任务拆解 + +## 使用规则 +- 每个任务都要写清楚 `boundary` 和 `verify`;机器任务的 verify 以首个反引号 span 为执行的命令 +- verify 命令不得自引用本包 check 门禁 +- 多 agent 协作:任务可加 `claim:` 行(信息约定);子代理车道须先 mesh_reserve 各自路径 + +## 阶段一:实现 + +- [ ] T1 Astro 5 项目初始化(pnpm + TS strict + minimal) + - claim: orchestrator + - boundary: 只新建 package.json/pnpm-lock/astro.config.mjs/tsconfig.json/src/pages/index 占位;不装 UI 框架 + - verify: `pnpm astro build` + +- [ ] T2 设计 tokens 与全局样式(丙路线) + - depends-on: task_0001 + - claim: orchestrator + - boundary: 只写 src/styles/{tokens.css,global.css};变量命名与 docs/博客重设计调研报告.md §3 参数一一对应 + - verify: `pnpm astro build && test -f dist/index.html` + +- [ ] T3 字体三轨自托管分片(文楷/思源黑/JBMono) + - depends-on: task_0002 + - boundary: 只加字体 npm 依赖与 src/styles/fonts.css 引入;不引入 cn-font-split 构建步(预分片包方案,证伪则回退并记 2.5) + - verify: `pnpm astro build && test $(find dist -name "*.woff2" | wc -l) -gt 50` + +- [ ] T4 内容集合与 EXIF loader(posts/moments/photos) + - depends-on: task_0001 + - claim: lane-content(子代理,预留 src/content 与 src/lib) + - boundary: 只写 src/content/config.ts、src/lib/{exif.ts,collections 辅助}、content/ 样例(书评/技术/瞬间各 1+、照片 3 张占位图含两种比例);EXIF 空值容错 + - verify: `pnpm astro build` + +- [ ] T5 布局/导航/页脚/明暗不闪烁 + - depends-on: task_0002 + - claim: orchestrator + - boundary: 只写 src/layouts/BaseLayout.astro 与 src/components/{Header,Footer,ThemeScript}.astro;导航 ≤4 项;页脚 ICP+built-from 槽位;inline 防闪烁脚本 + - verify: `pnpm astro build && grep -q "陕ICP备2026014860号" dist/index.html` + +- [ ] T6 五页型(首页/文章双模板/图库/瞬间/关于) + - depends-on: task_0004, task_0005 + - claim: lane-pages(子代理,预留 src/components 与 src/pages 除 index 外路由) + - boundary: 只写页面与页面级组件(名片开场/分轨列表/书评衬线模板+引文组件/技术模板+TOC+进度条/图库 masonry+lightbox/瞬间时间线/关于含身份陈述空槽位);排版参数按报告 §3 + - verify: `pnpm astro build && test -f dist/archives/deng-dai-ge-duo/index.html -a -f dist/gallery/index.html -a -f dist/moments/index.html -a -f dist/about/index.html` + +- [ ] T7 极客层 P0(键盘+帮助/build-info/View Transitions/项目墙) + - depends-on: task_0005 + - claim: lane-geek(子代理,预留 src/components/geek 与 src/data) + - boundary: 只写 geek 组件(keyboard+? 帮助浮层、built-from 注入 vite define、ClientRouter、项目墙构建时 fetch 双源+缓存兜底 JSON);不改页面结构 + - verify: `pnpm astro build && grep -q "built from" dist/index.html -i && grep -q "ClientRouter\|view-transition" dist/index.html` + +- [ ] T8 Pagefind + RSS + sitemap + Artalk 占位 + - depends-on: task_0006 + - claim: orchestrator + - boundary: 只加 astro-pagefind/@astrojs-rss/@astrojs-sitemap 集成与文章模板 Artalk 容器组件(无凭据占位);astro.config 修改限集成段 + - verify: `pnpm astro build && test -d dist/pagefind -a -f dist/rss.xml -a -f dist/sitemap-index.xml` + +- [ ] T9 响应式结构自查(§4e 断点全覆盖) + - depends-on: task_0006 + - boundary: 只做断点/容器查询与触屏属性的静态断言脚本 scripts/check-responsive.sh(1120/820/760/560 四档 + 44px 触点 + safe-area + 100dvh),不改样式本体(缺陷回写对应组件修复) + - verify: `bash scripts/check-responsive.sh` + +- [ ] T10 staging 部署演练(build.sh 填实) + - depends-on: task_0008, task_0009 + - claim: orchestrator + - boundary: 只改 infra/deploy/build.sh 为真实 astro build+rsync;staging 产物断言;不碰 nginx/生产 + - verify: `bash infra/deploy/build.sh && test -f ~/docker_apps/blog/www-staging/index.html && bash infra/deploy/rollback-dryrun.sh` + +--- + +**当前进度**:由脚本计算,无需手动维护 From eeb9bde1211754f33181090d33415a4de3d82524 Mon Sep 17 00:00:00 2001 From: wait4xx Date: Sat, 24 Oct 2026 23:07:11 +0800 Subject: [PATCH 02/10] =?UTF-8?q?feat(skeleton):=20Astro=207.3.8=20?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E5=88=9D=E5=A7=8B=E5=8C=96=EF=BC=88pnpm+TS?= =?UTF-8?q?=20strict=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - astro 锁 7.3.8:7.4 起 engines 要求 node>=22.23.4,宿主 22.22.3 差一档 - minimal 骨架:单页占位 + site=https://wait4x.online,集成留 T8 按任务接入 验证: pnpm astro build exit 0(1 page built) Spec: 2026-10-24_add-blog-skeleton Co-authored-by: GLM-5.3 --- astro.config.mjs | 7 + package.json | 15 + pnpm-lock.yaml | 2335 +++++++++++++++++++++++++++++++++++++++++ src/pages/index.astro | 8 + tsconfig.json | 5 + 5 files changed, 2370 insertions(+) create mode 100644 astro.config.mjs create mode 100644 package.json create mode 100644 pnpm-lock.yaml create mode 100644 src/pages/index.astro create mode 100644 tsconfig.json diff --git a/astro.config.mjs b/astro.config.mjs new file mode 100644 index 0000000..85f1596 --- /dev/null +++ b/astro.config.mjs @@ -0,0 +1,7 @@ +// @ts-check +import { defineConfig } from 'astro/config'; + +// 极简起点:集成(pagefind/rss/sitemap)在 T8 按任务加入,保持骨架可构建 +export default defineConfig({ + site: 'https://wait4x.online', +}); diff --git a/package.json b/package.json new file mode 100644 index 0000000..48999c3 --- /dev/null +++ b/package.json @@ -0,0 +1,15 @@ +{ + "name": "wait4x-blog", + "type": "module", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "astro dev", + "build": "astro build", + "preview": "astro preview", + "astro": "astro" + }, + "dependencies": { + "astro": "^7.3.8" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..da59a85 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,2335 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + astro: + specifier: ^7.3.8 + version: 7.3.8(yaml@2.9.1) + +packages: + + '@astrojs/compiler-binding-android-arm64@0.5.2': + resolution: {integrity: sha512-kckIxon6Rm/Bxzh9mGPYpRRqUbToUQoHptCmpMmE+Yt0Xumq8CqrKUidyYhrBsrHVO7bxuRzzWUUqvpf+iYceQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@astrojs/compiler-binding-darwin-arm64@0.5.2': + resolution: {integrity: sha512-1ZG5Ar3dD8HtodX9XH1mRmE0qBXZlvjYXSFfpgFwocqfWnvhFuqtGUNseL8wgfImiRMztIjpQqlogQFQQtgiag==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@astrojs/compiler-binding-darwin-x64@0.5.2': + resolution: {integrity: sha512-+kl35S7hiHJ2cb7eujwEsPFYYuSgE11uEE2Z20lAJ+undpgulMcW+weQqFPOSSZccEKHOiLIY+kQHkb4e4092w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@astrojs/compiler-binding-linux-arm64-gnu@0.5.2': + resolution: {integrity: sha512-BqlR0EHNQLPLwgL9+xogjsAc7zGf0cHho2CPdhv0P1yqbVMwGVaGAqrANP6VYAXCqSC43AF4Czcxc2n+oqdesg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@astrojs/compiler-binding-linux-arm64-musl@0.5.2': + resolution: {integrity: sha512-GRGyby3AZWw5d6JQzidyxPyvGgHWsSusrpgKyFVpDTKctABF7L3Pd5V1cRJbV36/rcu+Eh292/wL7pF7MkmGkQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@astrojs/compiler-binding-linux-x64-gnu@0.5.2': + resolution: {integrity: sha512-9XAqGTMQAtIslMsjK3xdyY6OI9d59OZqcLBB6pvD/DcoR0daYswfrKx2azdDERDY4AqAnWPC7odVM1BmxYv3Vw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@astrojs/compiler-binding-linux-x64-musl@0.5.2': + resolution: {integrity: sha512-jOViewGeTh9bSfS8vK72ECxoy2yvmA+Pd/ZcEvBI5c7+7IcfHwZ5qA4L9fRYuOhSrAifvQ2dV4vm1XAtloaWBw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@astrojs/compiler-binding-wasm32-wasi@0.5.2': + resolution: {integrity: sha512-Z7p64doar1uvR5C9Xs6j1CV9lGlPVQX7OQ2aAtZ/xKC5aGS6GB13nyc2UfQXTQLvZrvVwsyaflTQy6ziY5Bekw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] + + '@astrojs/compiler-binding-win32-arm64-msvc@0.5.2': + resolution: {integrity: sha512-Tr13bh+ahTWsjXjzctK7pFpWV+dUU4FtBfETlR7gO+ueex0F+RDch7eRr0YfKysaRhk9tWm14lsCJ5uWyFPNHQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@astrojs/compiler-binding-win32-x64-msvc@0.5.2': + resolution: {integrity: sha512-SfKkI+jOQYLh6wojPvVPV0lFfQnxisweN9B+qCzRvZp7DHAuGif8Y0WcC5PUgN4jb8VKy57LggQDtggR46Du1g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@astrojs/compiler-binding@0.5.2': + resolution: {integrity: sha512-lEn76+0JcMQ5RDXU0wSMWJg2ZppiZvSULpghC29cfv4o9bhvWFDbQjsCtvjjXN9iVLFQ7fL3wTR2L2UU13mP8g==} + engines: {node: ^20.19.0 || >=22.12.0} + + '@astrojs/compiler-rs@0.5.2': + resolution: {integrity: sha512-IvwYLB8t1M86rKO4oPdBi9GP4gzXcgrVlNgocjwos1jeeUuEIV8d9Crn1PvYD/5IKteWOxpIHomf7e8iYlkE+Q==} + engines: {node: '>=22.12.0'} + + '@astrojs/internal-helpers@0.12.0': + resolution: {integrity: sha512-pKPuwCDtO0L7zgmt1JGd9X4Aes1+0SX3IEBSqBNPHsScYdPMlfmed3Y7DTbXyF7E+8ylnb563o/0OzGQPOFehw==} + + '@astrojs/markdown-satteri@0.4.3': + resolution: {integrity: sha512-PFbEHPnwUlLvpXd7RXrrKM+j12akF4bG+DSuNuoN+3eiwjOwp4HaPi+QQdbkBV7QEYXmzyKca50OJsmGxhNIUA==} + + '@astrojs/prism@4.0.2': + resolution: {integrity: sha512-KTivpmnz6lDsC6o9H4+DNm2SrE/GHzw8cNAvEJwAvUT+eoaEnn/4NtbDNfRRaxaJHdp15gf+tfHAWiXR4wB3BA==} + engines: {node: '>=22.12.0'} + + '@astrojs/telemetry@3.3.3': + resolution: {integrity: sha512-C1TLn5sPJr0x4vk56piHWKbnqlEB8BKyte5Y45V02U+D7BGO5eMqZDH5aPjnkXQWJggvmsTXxH03QMZ9NgWLzQ==} + engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0} + + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.9': + resolution: {integrity: sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/types@7.29.8': + resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==} + engines: {node: '>=6.9.0'} + + '@bruits/satteri-darwin-arm64@0.10.5': + resolution: {integrity: sha512-27KTVl4TJkVahMy/ohyA7qd4938G5UNneFUz/PsScYfpIhj0IVAS23mpcJXdPF44sa6nva198lmV/cKIb2YPyA==} + cpu: [arm64] + os: [darwin] + + '@bruits/satteri-darwin-x64@0.10.5': + resolution: {integrity: sha512-IjnLe3nKspq6qaeqGgjT7MT8VrTV74yWRlaag7ZdNsI8TDAYZ0iPxMCo+9KQZHUk5EyVB+reBI/PFWL5KuFw9Q==} + cpu: [x64] + os: [darwin] + + '@bruits/satteri-linux-arm64-gnu@0.10.5': + resolution: {integrity: sha512-glkYXZCJywjP13v67eAyAMSJdF+ncvEbYvgi/wOtffL9tQ27lr/zsyzUfgs+ovjJ9d8JNQKiXeiArJcX8PJL9w==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@bruits/satteri-linux-arm64-musl@0.10.5': + resolution: {integrity: sha512-yWdgG1g17Nh2QyGVlFUxGRa3FEFwiMcpZEyMNWkbM3deC94cmVc+/i9OuyFpdKuWo3GkgoCtYVOoxk1uCnCZIA==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@bruits/satteri-linux-x64-gnu@0.10.5': + resolution: {integrity: sha512-FVaLoPT1fBgGl0J+AYebyyXJYBachGl8Oyyrf1lye4RTqCB4S0Gwkj1uM9RJyThUOvx5VUmAT1CnNh1SFHA+kw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@bruits/satteri-linux-x64-musl@0.10.5': + resolution: {integrity: sha512-EHpVAx2bqW3GINHTKkljtxVfQmVDGWIuwOYOP5YghTj+0PkBa2o8oKPRtQ9Kbsr1Fye8jtUcDjhwj2jMNugZKg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@bruits/satteri-wasm32-wasi@0.10.5': + resolution: {integrity: sha512-ypz8c/Zmipxp4IoeDa228Gstv6TLzVmNs3yC6wKCoNSOjx1iwpgzu87Y3hTkXFdwChVGU85qeUDuOIarGUZQLw==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@bruits/satteri-win32-arm64-msvc@0.10.5': + resolution: {integrity: sha512-siTV88nb0LRqNpkL2gXboqCwVdq95sLtzMHS1/3eONV2gLbB3NAK46wmSMvCO/yquBvI2lvaFIfd8P12ecsxBw==} + cpu: [arm64] + os: [win32] + + '@bruits/satteri-win32-x64-msvc@0.10.5': + resolution: {integrity: sha512-C3IfPvfvMXmlzBxaMPKFS1XiuV9pu2mC7YqkPk7PSvTgPZ8gbdASIpHpztDLvTTQjqZ0z1Ol8tK5X+V6XXC0wQ==} + cpu: [x64] + os: [win32] + + '@capsizecss/unpack@4.0.1': + resolution: {integrity: sha512-CuNiSqg7+e1cO/GjffyMOm5Tt2jUF9CWHHnvQ/UkqvtkGfHdgwEC0wpmq7fkN3gxwpRnrAN0WzO3vREKmNolMQ==} + engines: {node: '>=18'} + + '@clack/core@1.5.1': + resolution: {integrity: sha512-iHTrHA8MtVuLl2TfZySmcKv1qO2PoyC9Z7pfSDozEuV5vtY3/wcOPKJXlqJ5Oq2Cx5DDGQGAMVx6HZfRRoVEbQ==} + engines: {node: '>= 20.12.0'} + + '@clack/prompts@1.8.1': + resolution: {integrity: sha512-dlT1m5e/0yUL0kRNcQn7yGLVThkgbB0Ga/1AmfDDC/8ik6AIiSf2QLQO2zPYvefsHP0aFgxO93cVLCCfDp7kzQ==} + engines: {node: '>= 20.12.0'} + + '@emnapi/core@1.11.1': + resolution: {integrity: sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==} + + '@emnapi/core@1.11.3': + resolution: {integrity: sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg==} + + '@emnapi/runtime@1.11.1': + resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} + + '@emnapi/runtime@1.11.3': + resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} + + '@emnapi/wasi-threads@1.2.2': + resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} + + '@emnapi/wasi-threads@1.2.3': + resolution: {integrity: sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g==} + + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.35.5': + resolution: {integrity: sha512-QRUlFQ0WxvdWyqqG/WtI3iupfD5rBzmCHXSdPsY91sAtVtTo7Q4cb6zOccZ3gqEqkr0f1As1ehLqmEpDsRf+lg==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.35.5': + resolution: {integrity: sha512-+BR255RhDlpygUpOc/Jdt1nT6DQ3XG/ERo5wbcdOf5Q320dKtPCKPLR1LJs9VGXRaMa8l1uUa0tkCNOXiAxZUw==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [darwin] + + '@img/sharp-freebsd-wasm32@0.35.5': + resolution: {integrity: sha512-Y/z91nEZ4uIBX5X3nfTovjU9lHNKFYbL2lpHCLVNmXQK03VIZvXBBt0KxbPGp2SdGSF+2mQU4e+hQaWOt86iAw==} + engines: {node: '>=20.9.0'} + os: [freebsd] + + '@img/sharp-libvips-darwin-arm64@1.3.4': + resolution: {integrity: sha512-5R89nBYiRdUlSWJxPhO+GVtaXzXSxKnRu/xqMn3KTA3L9EB9Oy/P+Nn2f2vlhPuUdy/Zusb2DarbyTpGCfEDuw==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.3.4': + resolution: {integrity: sha512-iR2OKH80yi0U+dUplyh3/xdpFvps6YkCwsXenIJxqxR1v9o+xtKTGbS9H7cps+2Vxjc8B1j96p75NmTGjIhtpQ==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.3.4': + resolution: {integrity: sha512-Y3dgX/6lE2QhQb+Gxy0WZxfg9MEm/JBjamZpS2IklP7xIQoKN4hzAm7KcMVGtaVDt3neE9OKBC7vAfonA/Lr1A==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.3.4': + resolution: {integrity: sha512-LmRtTsOHuvM2+wlO2Db37dx5MiZhB0FvSunciw48YjdOkZz9KAiRbm8ujeMOA1INqmei5NapFxYEK1D1ZSidmw==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-ppc64@1.3.4': + resolution: {integrity: sha512-Le6boB8Tai0Nis+gIxIpKx68UDVVIqdR8Tin5Yf1z2LJJQLDJvCDRqRu+jC2qCoD+eIomonmOwB4smBRxfVpYQ==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-riscv64@1.3.4': + resolution: {integrity: sha512-aHkkIEHPRdQEegJN20MLmGtxYD9R2wQr3Cwpddnu5+YKMt6Uzax7S9h5gpZTo8wyrGuZSlfQ63OevL5mTyOC7Q==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.3.4': + resolution: {integrity: sha512-ra/mB6MikESDUO7Yg+Mi95bFBb9GsObURuhnOv3OqknjGe9sZrG8tCe9q0xSIGrtLgvgw0gKnFWcK4blSgQOuQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.3.4': + resolution: {integrity: sha512-GJ//SSXbnwSDes02umB3nDJLFcQzw8a18V8fyhqr6tV515tOEMdImjjxj1AoafMRz56F3PHgftnj1QEKSU1zkw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linuxmusl-arm64@1.3.4': + resolution: {integrity: sha512-hvulFwtjUcagsis6BBxHwGFwWoNZjgYmULGVrZcyfNbjA8hKILbRxGg15/7w5HDyXHXUos/j6baAWqnCyQ2DWA==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.3.4': + resolution: {integrity: sha512-6zXKeE/p39I1AmA3cJG35eyBGNqNddLnUXjhwBnsGjFPWqf5VKkDBEqaEkPDoTEtkxwi2vv8Tcr2mDyP4So7Fg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-linux-arm64@0.35.5': + resolution: {integrity: sha512-LYVx5JTsOM2CBzmxreh+nl64/3H6Xb09iSLknqH47z2T2DFFxDeFLP5y4dJwe6H7uGQlHPyEEtIqyo3DYsRwdQ==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm@0.35.5': + resolution: {integrity: sha512-LEaXK2WdXVK5ykcw0buWyPMsmLLL2vpHLD6yrNSW+JGEL3BZPA4tpKN6iaMc4AxTTAoaX/sU1rOL51lcIz48ZQ==} + engines: {node: '>=20.9.0'} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-ppc64@0.35.5': + resolution: {integrity: sha512-QVxAAq8evVRI9ia2vqgwrmWucn5Dfv+JdWzj75pD8omHLPSP7f8p20O8jxzjCcuCEQEOtYOZUmX1hkiZ0kdevA==} + engines: {node: '>=20.9.0'} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-riscv64@0.35.5': + resolution: {integrity: sha512-LtdreXguaavKODPIfzJ4kffx7UNt1omwtK0rch4EBbbSTXPnxWmYSayXdLJw0fJzQ97kHt1gL/yh4tvU+nCyRQ==} + engines: {node: '>=20.9.0'} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-s390x@0.35.5': + resolution: {integrity: sha512-UZasTOFiYzotTsGOCu42BfUzP6Tu6Do/947iRm1RsLKvlllxwGcn4RN27LibGWceix4Y+Pmw3jsnTcCQIgWjqA==} + engines: {node: '>=20.9.0'} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-x64@0.35.5': + resolution: {integrity: sha512-SxFtLTeJInhAA9Q836kux2vZNeOBQEx658qvbboZScr0wIARym3IcGmW7KpVD5sbVg0Ojy+udFQdayYIZyoNog==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-linuxmusl-arm64@0.35.5': + resolution: {integrity: sha512-9HbMclmI1zlNkFRs3z9/eBtDjfD0sGlrX1z6b1qwmiFY5ElDLh4BC0LPBdVp7z1DXFiKlIcznf+ZlsuZzLxQqg==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-x64@0.35.5': + resolution: {integrity: sha512-4KOphqB035HrVdqLZfCgMzzERrQkkzOwRhl4OAkRO1YCldbaFjySXMaK534Mo0V+LndnlJk+sbUyLeU0ULyD1A==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-wasm32@0.35.5': + resolution: {integrity: sha512-Ptsga1su4tQx+LLF1ECS9U6nz5kmrXKo6XVbtR48Ke3ZRxxgaWBu7IDtEe1quo8hiupwm6WFqxVlXaSf7IINGQ==} + engines: {node: '>=20.9.0'} + + '@img/sharp-webcontainers-wasm32@0.35.5': + resolution: {integrity: sha512-hfhF/FmoQyTUkA0bIKFOtw536BQSeBMe6BF6QyWlrPxT754+TFLaZ7sKKTfvvM0yJgKgaYTwnFCIZ/GuDw5SUA==} + engines: {node: '>=20.9.0'} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.35.5': + resolution: {integrity: sha512-X4t7g+7ZA5DKblCBEXGjUqqemj4vczING/5viFwAL8h4N3qYeyjwdCvRLHi4EdOUI+2Z7UFlp1VM+p/AuEtm6Q==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.35.5': + resolution: {integrity: sha512-5Zm82LoBc43nhwNybZlG7Y1KO//Zhsn306fQl29ZOuStHLGTo3BWL83q3cznX0poxSAMuYL1On/BHBxkBeKr6A==} + engines: {node: ^20.9.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.35.5': + resolution: {integrity: sha512-x76eH0vEiHlcMQu8Y8IenntaACtddpT6W0wmXtWrnKcnKI7ME5DdgqhAD6SEWOEl1v2zDvkZDhFA9KnURwpfqg==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [win32] + + '@jridgewell/sourcemap-codec@1.6.0': + resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==} + + '@napi-rs/wasm-runtime@1.2.5': + resolution: {integrity: sha512-HshSvXzmBxNzqejd3k/KemgQ3hdREUYFRRrgxOZ+gPljDIsO2SDZrVZMd4Z/HsxudQbE62OVyVFE8z9BCurfjA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} + peerDependencies: + '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.4 + '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.4 + + '@oslojs/encoding@1.1.0': + resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==} + + '@oxc-project/types@0.155.0': + resolution: {integrity: sha512-SeE8JPwW1xs1tHeNycjUtUBdhorRa8o4jlvjwk49R7/Z291i+4DQa7JJIgOm/TaYQZx+QrPQbVJ/9c8dMIZN8Q==} + + '@rolldown/binding-android-arm-eabi@1.2.15': + resolution: {integrity: sha512-aLcgK9gIJ3YRvrrtfSBbRa27F5WrpiTaPulnFpsHPxpUHgFlSgnU4854MHwoRGEBhfRJDWCS2WQ7lIjskE9Olw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@rolldown/binding-android-arm64@1.2.15': + resolution: {integrity: sha512-xD7DdZCrbThKuxNg7ooQmvp07ys4J/pnSEMTG3/OdOWl6daC67m/Q4fL78sRHMxTH/N4fGUbYhcPM0MF5WFHkg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.2.15': + resolution: {integrity: sha512-m2WuQ6r0B4OTYxyPpNLtXaMRbRDUbG8YQV2Q3KTdSSK8Th6KHCnC8jVCJt8bvYeSB5WivkkNbc85mKadaSdOxA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.2.15': + resolution: {integrity: sha512-5RtnsHM36nodM9WbMy+zip0LGS/G+y5wro5RHrpOlr4ac24+1zSi9kiV2MP1myZeZ/ifEHfulQcWjnAXzc2C2A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.2.15': + resolution: {integrity: sha512-g3l09pyFqhu+135JKkbkwiKGQmwU5hUMUPJ4VdBADvuqR8d33L6H578rh8m7rtxbdp+VmX/+nzI7nvhSZlzpUQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.2.15': + resolution: {integrity: sha512-nIe3VugI97nGQtspPxDqA4sXMUpeiocKIP/CqpY/u/vgbT+alX+cVxu1C/oVBPKg4feNTmYovE91v4DgXvXNwQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.2.15': + resolution: {integrity: sha512-iTBjXx+B5QSvgI89lJfmqh4wTh8NabR1YZIIN3hNx4zSG0EVfVqkOvLulNpG4251pbd6/IAmZ/LefVk1Y4rPhw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-arm64-musl@1.2.15': + resolution: {integrity: sha512-uN26XOnVR7rqQupG3V9oAG2EGGatWjcJHOeDOHUFCh4TBWmP2tHTFoVN13aYbwfm0aHqJAEmcwhAu6sooIjfqQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-ppc64-gnu@1.2.15': + resolution: {integrity: sha512-9nWkcdd+H+XhaA3fQIwpHnKIrfx/PQ6rO0pivr78Og07tXlUlctBBJoEYLPfhTmCR/QxEVdn6uPjHV5SymPhdw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.2.15': + resolution: {integrity: sha512-Ggh0ciFjLwIusLSLz7LZYEaGdxOAUJXI+Qu5JCbhPJJHEt8vP+IjRATTJheiJsdzzTYgUiHUiw3X1Ea3ZpMBdA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-gnu@1.2.15': + resolution: {integrity: sha512-FHg60rS6DBePAYZ9X9F67x+JObFdmgn6tupA1C/a3B+CufFmTD4mX+e8M75tCiAO3foR/6xwVBI0KQiI7sn/rw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-musl@1.2.15': + resolution: {integrity: sha512-/cvV/7v5VGz/moiz0XKRj2dE8DzsKyhIu1KpOvJGPjRywg3yscON889UGvAe8zfiJLHup7VLjBduoGWi3HusWQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rolldown/binding-openharmony-arm64@1.2.15': + resolution: {integrity: sha512-MyzC5Hrv/sm+Z7TSGKP/j8001RO2xQm1zOpCNVL4j0cY/VhBZviludA2YFQ7i4lH6ZAXxQm0lcMdBzM+99mE7w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-win32-arm64-msvc@1.2.15': + resolution: {integrity: sha512-+PgYiS+AH5omy6L45ZLxybasauJaj3M8buoT83D+nzPmCayXlxUV9hydhciCKVyIg0B/v0BtXPDE1uGqNwCPpg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.2.15': + resolution: {integrity: sha512-HFZd2QNQYn1JbIi+Hpd7H+r/lkWxcfIu28nirZ6eCn2LafuvmExMlb/P96Sfx5tf7pPArw39IdhmCF8vmV+NhQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + + '@shikijs/core@4.5.0': + resolution: {integrity: sha512-6CIgwq+bt2JZ3OSjb/nBkkwEf/CfpHcbam+Mg5Pllco7HAGRQ2/EFhZrrJtbyNTgKwknfVS+llsXGygiDGwJWw==} + engines: {node: '>=20'} + + '@shikijs/engine-javascript@4.5.0': + resolution: {integrity: sha512-Ed6UdEj84LyYkwnxM5CvSMWAD+id9ExTYri0/+x41U9zrgNifPSS9lZm0JqBP0VfYI8yr8tY5nbNq9+p9R0kFA==} + engines: {node: '>=20'} + + '@shikijs/engine-oniguruma@4.5.0': + resolution: {integrity: sha512-dKVmbJecVdB9recl8a/CU4jdpNXyjJQrIcesIkpS70s5HS02ohpnCSpMUbotPnEUzbAcLQ+S4hwZYbkBBiTcJw==} + engines: {node: '>=20'} + + '@shikijs/langs@4.5.0': + resolution: {integrity: sha512-wwBTqwduXSz0X4v9Qa2EWeFaYJEw1clCncWjoRNQRbVDu3SPRTRWucnouYapKj3b8Q+sk/41Vbc4B5c8nuYzLA==} + engines: {node: '>=20'} + + '@shikijs/primitive@4.5.0': + resolution: {integrity: sha512-UM7ShlA8oz0OWxLLO8BmO9Ip6fVqdkt8yF0EH7nOCqHfrx1eEAzF0ZUVK7L+I8NEgeu1PEWSRlxaiPPeCb4iDg==} + engines: {node: '>=20'} + + '@shikijs/themes@4.5.0': + resolution: {integrity: sha512-zGb87H3UBbpuI4yoh5UguB1XbU+2BDU3kflM7UfZ+Cy2hWo9lBtqjSVK20gmLY6ukYl040hAypGXMgud9vul8Q==} + engines: {node: '>=20'} + + '@shikijs/types@4.5.0': + resolution: {integrity: sha512-drtPrtD8N0DENyD2cyt6Ajy+IWsiCLgMxODwLTpvH1UsN6a9jf90tNTPjqwHvA+0Lzu9e0txk8DjfqH1p9UJRw==} + engines: {node: '>=20'} + + '@shikijs/vscode-textmate@10.1.0': + resolution: {integrity: sha512-cVBuhDQjBZaNMTwBquYfPydrUP+E3hE6oYGasx8h6ZrODIM7/r+gxLDXdd66oszbrggZHEntdE6j+5gYIVyMWQ==} + + '@tybys/wasm-util@0.10.4': + resolution: {integrity: sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==} + + '@types/estree-jsx@1.0.5': + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/hast@3.0.5': + resolution: {integrity: sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/nlcst@2.0.3': + resolution: {integrity: sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@ungap/structured-clone@1.4.0': + resolution: {integrity: sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ==} + + am-i-vibing@0.5.0: + resolution: {integrity: sha512-KLcsDhqf1XRrJmJr+9I/C0EX2K+sGrAGZFgkmd84c8TJO9zJBu+/kFInjazu1KfJWFhWDKdRWkpBzEs7s35DVA==} + hasBin: true + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + astro@7.3.8: + resolution: {integrity: sha512-LHzDHSaV+YzZiR3EFndDYTLLeNeuMtP1qX1FLcCNUUHOCqTTIWPczy2UV3zpA5VqvJe5cWZolqM9Z8JFqR2i9w==} + engines: {node: '>=22.12.0', npm: '>=9.6.5', pnpm: '>=7.1.0'} + hasBin: true + peerDependencies: + '@astrojs/markdown-remark': ^7.3.0 + peerDependenciesMeta: + '@astrojs/markdown-remark': + optional: true + + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} + + ci-info@4.4.0: + resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} + engines: {node: '>=8'} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + + commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + + common-ancestor-path@2.0.0: + resolution: {integrity: sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng==} + engines: {node: '>= 18'} + + cookie-es@1.2.3: + resolution: {integrity: sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw==} + + cookie@2.0.1: + resolution: {integrity: sha512-yuToqVvRrj6pfDXREyQAAv8SkAEk/8GS3jQRTiUMm66TVtBYmqQeoEjL2Lmq8Rpo6271vH76InTChTitEAm65w==} + engines: {node: '>=22'} + + crossws@0.3.5: + resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==} + + css-select@6.0.0: + resolution: {integrity: sha512-rZZVSLle8v0+EY8QAkDWrKhpgt6SA5OtHsgBnsj6ZaLb5dmDVOWUDtQitd9ydxxvEjhewNudS6eTVU7uOyzvXw==} + + css-tree@2.2.0: + resolution: {integrity: sha512-7y32czN0VBL8WkevhC/mrHnoHOmQaJ1Wvp8sjRuTz6/n9cjL83jQaUru2MvP7kzjpGVwrSy5CE4XyQObWGIHQQ==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + + css-tree@3.2.1: + resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + + css-what@7.0.0: + resolution: {integrity: sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ==} + engines: {node: '>= 6'} + + csso@5.0.5: + resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + + defu@6.1.7: + resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + destr@2.0.5: + resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + devalue@5.9.4: + resolution: {integrity: sha512-sPAT4pztbu6586/hrhOnMKS17IJrvg12mXiSPSS3W5qDeN2RGgvZ0diZCm31dBbnevfVmujNO3IM2wrS4Y2Rhg==} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + diff@9.0.0: + resolution: {integrity: sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==} + engines: {node: '>=0.3.1'} + + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + + dset@3.1.4: + resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==} + engines: {node: '>=4'} + + entities@4.2.0: + resolution: {integrity: sha512-wEJa03bJgqEwPnkUqYdgmcfUXfm6+4hePQhntIvRy/1/+C4dFuhYHsgKBRjbQ6OWBh42P+VhAoCDO77DUh0e/Q==} + engines: {node: '>=0.12'} + + es-module-lexer@3.0.4: + resolution: {integrity: sha512-BldNY5mwkVu+cQ5Ymn3e6hB9Sx8XHx4ZevWbiUyZbfKxJxYO27Hf0wfzkxIaD5CAJMaGl3YspKELj0ff/7nCMA==} + + eventemitter3@5.0.4: + resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + fast-string-truncated-width@3.0.3: + resolution: {integrity: sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==} + + fast-string-width@3.0.2: + resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} + + fast-wrap-ansi@0.2.2: + resolution: {integrity: sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + find-proc@0.2.0: + resolution: {integrity: sha512-a6h2nTrgB3g5Wrn4au9Ux4kMk7IJtyF6oA8uGn+mk3weLZssUtc1cp6meHIzzuW2o1srrBAxzkmXLbqjRkgB6w==} + engines: {node: ^20.19.0 || >=22.12.0} + + flattie@1.1.1: + resolution: {integrity: sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==} + engines: {node: '>=8'} + + fontace@0.4.1: + resolution: {integrity: sha512-lDMvbAzSnHmbYMTEld5qdtvNH2/pWpICOqpean9IgC7vUbUJc3k+k5Dokp85CegamqQpFbXf0rAVkbzpyTA8aw==} + + fontkitten@1.0.3: + resolution: {integrity: sha512-Wp1zXWPVUPBmfoa3Cqc9ctaKuzKAV6uLstRqlR56kSjplf5uAce+qeyYym7F+PHbGTk+tCEdkCW6RD7DX/gBZw==} + engines: {node: '>=20'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + get-tsconfig@5.0.0-beta.6: + resolution: {integrity: sha512-X6fBC0pmImC70gvX2zm56go9hx0MyoGVdG0tUCkg/D+Xnh5TJsOZ7iDbOdI3PvmtrDxnu1YdDufpK2QJX1Meqw==} + engines: {node: '>=20.20.0'} + + github-slugger@2.0.0: + resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} + + h3@1.15.11: + resolution: {integrity: sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg==} + + hast-util-to-html@9.0.5: + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + + html-escaper@3.0.3: + resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==} + + html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + + http-cache-semantics@4.3.0: + resolution: {integrity: sha512-M5t5LlJpS1UHMjvwRQVdFHvPISGeLAxNcrWuJkeGh0KxsqCHZ1O3NXZU/8x7cD0BDcGW8kapxMKTvwlqrNkHkA==} + + iron-webcrypto@1.2.1: + resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} + + is-docker@4.0.0: + resolution: {integrity: sha512-LHE+wROyG/Y/0ZnbktRCoTix2c1RhgWaZraMZ8o1Q7zCh0VSrICJQO5oqIIISrcSBtrXv0o233w1IYwsWCjTzA==} + engines: {node: '>=20'} + hasBin: true + + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + + jsonc-parser@3.3.1: + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + + lightningcss-android-arm64@1.33.0: + resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.33.0: + resolution: {integrity: sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.33.0: + resolution: {integrity: sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.33.0: + resolution: {integrity: sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.33.0: + resolution: {integrity: sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.33.0: + resolution: {integrity: sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.33.0: + resolution: {integrity: sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.33.0: + resolution: {integrity: sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.33.0: + resolution: {integrity: sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.33.0: + resolution: {integrity: sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.33.0: + resolution: {integrity: sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.33.0: + resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==} + engines: {node: '>= 12.0.0'} + + lru-cache@11.5.3: + resolution: {integrity: sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==} + engines: {node: 20 || >=22} + + magic-string@1.4.3: + resolution: {integrity: sha512-z12OxmaPGE0F4xlpGdjuAUckipLpQlTAuAmyGhNoD7ODpYUzvDfvtxUbjM/jwznyP178oju/KDdyi220wNJ0RQ==} + + magicast@0.5.5: + resolution: {integrity: sha512-UicdXN8zQ3JHlxVq+28afMXPr1z7WNY6+7EJnzTdQWkTAlMLF5fNCCKxJHBQwGaNGR11581EiQmQzx73+MvszA==} + + mdast-util-to-hast@13.2.1: + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} + + mdn-data@2.0.28: + resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} + + mdn-data@2.27.1: + resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} + + micromark-util-character@2.0.0: + resolution: {integrity: sha512-DtHHqgTRz32ylwiGSZwoK+BTx4gaq//ig71g20pwBwRLxo3CfInyD+NyTrriLOhPz5WQOfAOSLLbKOaaGXWz9Q==} + + micromark-util-encode@2.0.0: + resolution: {integrity: sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==} + + micromark-util-sanitize-uri@2.0.0: + resolution: {integrity: sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==} + + micromark-util-symbol@2.0.0: + resolution: {integrity: sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==} + + micromark-util-types@2.0.3: + resolution: {integrity: sha512-oxB2Ik03hI0gv+VNn9tnh1t1YEe9MDPptViAEgfdf3YQHsn0pzGTgCdlSCJXcwhqm8phaEuM7zeEu3QQzVBrPg==} + + mrmime@2.0.1: + resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} + engines: {node: '>=10'} + + nanoid@3.3.20: + resolution: {integrity: sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + neotraverse@1.0.1: + resolution: {integrity: sha512-WmmLty1YWwJl9yZi77v2dVIV6X2kuYV8YYBI/G3LWGKdGHmHUvL1z7FW0iDvEvGAwNEoc5x1tOOOyDnf5jJw/w==} + engines: {node: '>= 10'} + + nlcst-to-string@4.0.0: + resolution: {integrity: sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==} + + node-fetch-native@1.6.7: + resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} + + node-mock-http@1.0.5: + resolution: {integrity: sha512-KQyt/wLjG3TAc7DOUhpqWzgd4ERxR80JOlTK5VE5R1S12IaPVN5qkj4klBce9HPG1Njuup4Sb5bljaT34lIyjw==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + + obug@3.0.0: + resolution: {integrity: sha512-5vvB5+W7ePv+p3uqxi+RcW1XAzLW0/hxt3/4X4Lc4qHudzOhmBiBwOY6DRob4WnanAEGvNcLjF+KNOufrUoEQw==} + engines: {node: '>=12.20.0'} + + ofetch@1.5.1: + resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} + + ohash@2.0.12: + resolution: {integrity: sha512-65S/5gk9YSsaRjcyf7Nfa6h/d3E8/1gslpXfI4W7Dxn/oap8IKRuNT5VXkLQ1YFKIEg4apRY4Pj6aiwFzrDdmw==} + + oniguruma-parser@0.12.2: + resolution: {integrity: sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==} + + oniguruma-to-es@4.3.6: + resolution: {integrity: sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==} + + p-limit@7.3.3: + resolution: {integrity: sha512-SKgVvDU5TNIxQ4r30U75BNLC6a+6GOEjngrk/ysM5+Zu3oJuk1SC5ApzIzY/7PjCEjoVPMWJ0zho/4QUiEB7TQ==} + engines: {node: '>=20'} + + p-queue@9.3.5: + resolution: {integrity: sha512-Lki/zhXFVmDhesBUn/yHRLW9Bte7mE7xoFHzTR8sIomV7a2z+LxYAPkGvdfidNiu4fKSfjtawixxSHcZci5QcQ==} + engines: {node: '>=20'} + + p-timeout@7.0.2: + resolution: {integrity: sha512-prbX4Z3YszrFNgH+MW5Zoeq3baXrMtP/MQnFeET90UB/GtGcGDQ5Usg9OCy6ETjTTntOw1SL2z9fMPUppN3Guw==} + engines: {node: '>=20'} + + package-manager-detector@1.9.0: + resolution: {integrity: sha512-zAMfbta9nPA8AKkA4WdmNAT8R8s6Dk0/xwPsqNnRidMFcLo1YkLuPDTgs2f64XdzS8vbLNnoJ+uUIkgbz7oRHA==} + + piccolore@0.1.3: + resolution: {integrity: sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} + engines: {node: '>=8.6'} + + picomatch@4.0.7: + resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==} + engines: {node: '>=12'} + + postcss@8.5.31: + resolution: {integrity: sha512-YUbWYCgErwnMAVkjUnYa+KlMBzGpHwiIt/DE7f0G33AuX2LH9UcTk6KgWxd3zRU+pN3u/C+Xl3EnMLM4Hea7Sg==} + engines: {node: ^10 || ^12 || >=14} + + prismjs@1.30.0: + resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} + engines: {node: '>=6'} + + process-ancestry@0.1.0: + resolution: {integrity: sha512-tGqJW/UnclpYASFcM6Xh8D8l/BMtaQ9+CSG0vlJSJTcdMM4lDRv4c6H0Pdcsfted+bVczdYSfk2fdukg2gQkZg==} + engines: {node: '>=18.0.0'} + + property-information@7.2.0: + resolution: {integrity: sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==} + + radix3@1.1.2: + resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} + + readdirp@5.1.1: + resolution: {integrity: sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==} + engines: {node: '>= 20.19.0'} + + regex-recursion@6.0.2: + resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} + + regex-utilities@2.3.0: + resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} + + regex@6.1.0: + resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + retext-smartypants@6.2.0: + resolution: {integrity: sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==} + + rolldown@1.2.15: + resolution: {integrity: sha512-6odND+fel5zVw3I4Yc2e69gvguDnX0CAAGiNDZSq4ik5WUcaLrkD2GLuog0XcODbor31hZ5ayEMgVDno+KPV5g==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + satteri@0.10.5: + resolution: {integrity: sha512-Ao1LKpAEa9Wdg0otgbVKViZHEq9ebdXe4DMrp3s9vQAU0HNIuHnFEuMuOcm0ZIXyV0Yzxj91NvhLpvXZJO/5ZQ==} + + sax@1.6.1: + resolution: {integrity: sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==} + engines: {node: '>=11.0.0'} + + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + + sharp@0.35.5: + resolution: {integrity: sha512-Ywn4OnzGukp7CDMrp08RQ50YKmuwG47brZgIVPTvBaaAfQlRlygrRqSrxdCiL9M+LlzLBiJ68IR1QqvzHyjC7g==} + engines: {node: '>=20.9.0'} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + shiki@4.5.0: + resolution: {integrity: sha512-OcRW72ngQvc+MSVWBRIovC/BTW589iUE/Vxav7VeM4RcY9MUjqB+IR6ILG1k9nuW6LiG/nct9uma4/MBtnZbmQ==} + engines: {node: '>=20'} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + smol-toml@1.9.1: + resolution: {integrity: sha512-j7WyPdf0CJoutMzMoPLF/bVXHtKZIT9Rb4eGeEbWw8X2t5oirjPgpL+OpaENZrILYaXqYwnVH+qgUwVbl+pUJQ==} + engines: {node: '>= 18'} + + source-map-js@1.2.2: + resolution: {integrity: sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==} + engines: {node: '>=0.10.0'} + + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + + svgo@4.1.0: + resolution: {integrity: sha512-bkxnTg1kSU0guhIBmibA6UUhrQmPVA1XsQLN+ylCd+UWzbnLkySOcXpyk1mrl05f+pcaCx2eHb+sp6BgMZWX+Q==} + engines: {node: '>=16'} + hasBin: true + + tiny-inflate@1.0.3: + resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==} + + tinyclip@1.0.3: + resolution: {integrity: sha512-nTv2raKFMzGG6JJp0lpNDsRPdfFE6UHlu2rVEjXo8vkx1ZS3LW2CVXqIaLu8xZlu+6tbFs9V58Qc/Jmk/Ii7wA==} + engines: {node: ^16.14.0 || >= 17.3.0} + + tinyexec@1.3.1: + resolution: {integrity: sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==} + engines: {node: '>=18'} + + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} + + ultrahtml@1.7.0: + resolution: {integrity: sha512-2xRd0VHoAQE4M+vF/DvFFB7pUV0ZxTW1TLi7lHQWnF/Sb5TPeEUV/l+hxcNnGO00ZXGnR0voCMmYRKQf+rvJ2g==} + + uncrypto@0.1.3: + resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} + + undici@8.12.3: + resolution: {integrity: sha512-+fdndUTwBP86cVjihTp21hZHo7d6oj1c/47XPA3lL8mM0XHs+C4EkcjmgRsFnFk2f/UONGDy9ItBItmXsLOQHw==} + engines: {node: '>=22.19.0'} + + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unifont@0.7.5: + resolution: {integrity: sha512-ULe/Cs+ZIsq+dcFofNkhqielCrUJnb5mr+Yc4EBM2VlL+6OZR6+cjtI2mT1bJvRBrVncqHAbLURxmPLcCXzWMg==} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.1.0: + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} + + unstorage@1.17.6: + resolution: {integrity: sha512-gjKtcmn/KwZuJZO9o2sc0esAQnhmTw0LviDHwevTXbJMYs0dRTp8ZEEWXHU0vTpzbN3cA0yxlTeyXssMp3zDqw==} + peerDependencies: + '@azure/app-configuration': ^1.8.0 + '@azure/cosmos': ^4.2.0 + '@azure/data-tables': ^13.3.0 + '@azure/identity': ^4.6.0 + '@azure/keyvault-secrets': ^4.9.0 + '@azure/storage-blob': ^12.26.0 + '@capacitor/preferences': ^6 || ^7 || ^8 + '@deno/kv': '>=0.9.0' + '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 + '@planetscale/database': ^1.19.0 + '@upstash/redis': ^1.34.3 + '@vercel/blob': '>=0.27.1' + '@vercel/functions': ^2.2.12 || ^3.0.0 + '@vercel/kv': ^1 || ^2 || ^3 + aws4fetch: ^1.0.20 + db0: '>=0.2.1' + idb-keyval: ^6.2.1 + ioredis: ^5.4.2 + uploadthing: ^7.4.4 + peerDependenciesMeta: + '@azure/app-configuration': + optional: true + '@azure/cosmos': + optional: true + '@azure/data-tables': + optional: true + '@azure/identity': + optional: true + '@azure/keyvault-secrets': + optional: true + '@azure/storage-blob': + optional: true + '@capacitor/preferences': + optional: true + '@deno/kv': + optional: true + '@netlify/blobs': + optional: true + '@planetscale/database': + optional: true + '@upstash/redis': + optional: true + '@vercel/blob': + optional: true + '@vercel/functions': + optional: true + '@vercel/kv': + optional: true + aws4fetch: + optional: true + db0: + optional: true + idb-keyval: + optional: true + ioredis: + optional: true + uploadthing: + optional: true + + verkit@0.5.0: + resolution: {integrity: sha512-u4J1hr6Y+C/hit34GwL3eIcUf3wngT8TlYUjK7tk0jxydKLAq3sYvifjdTDA6U3KCKRcQCQDGf/srjxfZF3l7g==} + engines: {node: '>=18.12.0'} + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + + vite@8.3.5: + resolution: {integrity: sha512-z1YpjieJ9g0ebTmQpLBv/oq9E3F9EIlOe+7LahW8SrE3LTiG3udBRUXQOlYXP9b+IC2q2phHeVxj9xGlw34OEQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.7.1 || ^0.8.0 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + 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.1.3: + resolution: {integrity: sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==} + peerDependencies: + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + vite: + optional: true + + xxhash-wasm@1.1.0: + resolution: {integrity: sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==} + + yaml@2.9.1: + resolution: {integrity: sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==} + engines: {node: '>= 14.6'} + hasBin: true + + yargs-parser@22.0.0: + resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + + yocto-queue@1.2.2: + resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} + engines: {node: '>=12.20'} + + zod@4.6.7: + resolution: {integrity: sha512-g8W2D2kU6a8untc053fX1uVBKzM7yqAxW/3zwk83+6RyF2+SKOuV+c0wBDhUwzV1PaGapmZH+rmcUzPf+3CGwg==} + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + +snapshots: + + '@astrojs/compiler-binding-android-arm64@0.5.2': + optional: true + + '@astrojs/compiler-binding-darwin-arm64@0.5.2': + optional: true + + '@astrojs/compiler-binding-darwin-x64@0.5.2': + optional: true + + '@astrojs/compiler-binding-linux-arm64-gnu@0.5.2': + optional: true + + '@astrojs/compiler-binding-linux-arm64-musl@0.5.2': + optional: true + + '@astrojs/compiler-binding-linux-x64-gnu@0.5.2': + optional: true + + '@astrojs/compiler-binding-linux-x64-musl@0.5.2': + optional: true + + '@astrojs/compiler-binding-wasm32-wasi@0.5.2': + dependencies: + '@emnapi/core': 1.11.3 + '@emnapi/runtime': 1.11.3 + '@napi-rs/wasm-runtime': 1.2.5(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) + optional: true + + '@astrojs/compiler-binding-win32-arm64-msvc@0.5.2': + optional: true + + '@astrojs/compiler-binding-win32-x64-msvc@0.5.2': + optional: true + + '@astrojs/compiler-binding@0.5.2': + optionalDependencies: + '@astrojs/compiler-binding-android-arm64': 0.5.2 + '@astrojs/compiler-binding-darwin-arm64': 0.5.2 + '@astrojs/compiler-binding-darwin-x64': 0.5.2 + '@astrojs/compiler-binding-linux-arm64-gnu': 0.5.2 + '@astrojs/compiler-binding-linux-arm64-musl': 0.5.2 + '@astrojs/compiler-binding-linux-x64-gnu': 0.5.2 + '@astrojs/compiler-binding-linux-x64-musl': 0.5.2 + '@astrojs/compiler-binding-wasm32-wasi': 0.5.2 + '@astrojs/compiler-binding-win32-arm64-msvc': 0.5.2 + '@astrojs/compiler-binding-win32-x64-msvc': 0.5.2 + + '@astrojs/compiler-rs@0.5.2': + dependencies: + '@astrojs/compiler-binding': 0.5.2 + + '@astrojs/internal-helpers@0.12.0': + dependencies: + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + picomatch: 4.0.7 + retext-smartypants: 6.2.0 + shiki: 4.5.0 + smol-toml: 1.9.1 + unified: 11.0.5 + yaml: 2.9.1 + + '@astrojs/markdown-satteri@0.4.3': + dependencies: + '@astrojs/internal-helpers': 0.12.0 + '@astrojs/prism': 4.0.2 + github-slugger: 2.0.0 + satteri: 0.10.5 + + '@astrojs/prism@4.0.2': + dependencies: + prismjs: 1.30.0 + + '@astrojs/telemetry@3.3.3': + dependencies: + ci-info: 4.4.0 + dset: 3.1.4 + is-docker: 4.0.0 + package-manager-detector: 1.9.0 + + '@babel/helper-string-parser@7.29.7': {} + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/parser@7.29.9': + dependencies: + '@babel/types': 7.29.8 + + '@babel/types@7.29.8': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + + '@bruits/satteri-darwin-arm64@0.10.5': + optional: true + + '@bruits/satteri-darwin-x64@0.10.5': + optional: true + + '@bruits/satteri-linux-arm64-gnu@0.10.5': + optional: true + + '@bruits/satteri-linux-arm64-musl@0.10.5': + optional: true + + '@bruits/satteri-linux-x64-gnu@0.10.5': + optional: true + + '@bruits/satteri-linux-x64-musl@0.10.5': + optional: true + + '@bruits/satteri-wasm32-wasi@0.10.5': + dependencies: + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 + '@napi-rs/wasm-runtime': 1.2.5(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) + optional: true + + '@bruits/satteri-win32-arm64-msvc@0.10.5': + optional: true + + '@bruits/satteri-win32-x64-msvc@0.10.5': + optional: true + + '@capsizecss/unpack@4.0.1': + dependencies: + fontkitten: 1.0.3 + + '@clack/core@1.5.1': + dependencies: + fast-wrap-ansi: 0.2.2 + sisteransi: 1.0.5 + + '@clack/prompts@1.8.1': + dependencies: + '@clack/core': 1.5.1 + fast-string-width: 3.0.2 + fast-wrap-ansi: 0.2.2 + sisteransi: 1.0.5 + + '@emnapi/core@1.11.1': + dependencies: + '@emnapi/wasi-threads': 1.2.2 + tslib: 2.8.1 + optional: true + + '@emnapi/core@1.11.3': + dependencies: + '@emnapi/wasi-threads': 1.2.3 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.11.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.11.3': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.2': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.3': + dependencies: + tslib: 2.8.1 + optional: true + + '@img/colour@1.1.0': + optional: true + + '@img/sharp-darwin-arm64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.3.4 + optional: true + + '@img/sharp-darwin-x64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.3.4 + optional: true + + '@img/sharp-freebsd-wasm32@0.35.5': + dependencies: + '@img/sharp-wasm32': 0.35.5 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.3.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.3.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.3.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.3.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.3.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.3.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.3.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.3.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.3.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.3.4': + optional: true + + '@img/sharp-linux-arm64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.3.4 + optional: true + + '@img/sharp-linux-arm@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.3.4 + optional: true + + '@img/sharp-linux-ppc64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.3.4 + optional: true + + '@img/sharp-linux-riscv64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.3.4 + optional: true + + '@img/sharp-linux-s390x@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.3.4 + optional: true + + '@img/sharp-linux-x64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.3.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.3.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.35.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.3.4 + optional: true + + '@img/sharp-wasm32@0.35.5': + dependencies: + '@emnapi/runtime': 1.11.3 + optional: true + + '@img/sharp-webcontainers-wasm32@0.35.5': + dependencies: + '@img/sharp-wasm32': 0.35.5 + optional: true + + '@img/sharp-win32-arm64@0.35.5': + optional: true + + '@img/sharp-win32-ia32@0.35.5': + optional: true + + '@img/sharp-win32-x64@0.35.5': + optional: true + + '@jridgewell/sourcemap-codec@1.6.0': {} + + '@napi-rs/wasm-runtime@1.2.5(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': + dependencies: + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 + '@tybys/wasm-util': 0.10.4 + optional: true + + '@napi-rs/wasm-runtime@1.2.5(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)': + dependencies: + '@emnapi/core': 1.11.3 + '@emnapi/runtime': 1.11.3 + '@tybys/wasm-util': 0.10.4 + optional: true + + '@oslojs/encoding@1.1.0': {} + + '@oxc-project/types@0.155.0': {} + + '@rolldown/binding-android-arm-eabi@1.2.15': + optional: true + + '@rolldown/binding-android-arm64@1.2.15': + optional: true + + '@rolldown/binding-darwin-arm64@1.2.15': + optional: true + + '@rolldown/binding-darwin-x64@1.2.15': + optional: true + + '@rolldown/binding-freebsd-x64@1.2.15': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.2.15': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.2.15': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.2.15': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.2.15': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.2.15': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.2.15': + optional: true + + '@rolldown/binding-linux-x64-musl@1.2.15': + optional: true + + '@rolldown/binding-openharmony-arm64@1.2.15': + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.2.15': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.2.15': + optional: true + + '@rolldown/pluginutils@1.0.1': {} + + '@shikijs/core@4.5.0': + dependencies: + '@shikijs/primitive': 4.5.0 + '@shikijs/types': 4.5.0 + '@shikijs/vscode-textmate': 10.1.0 + '@types/hast': 3.0.5 + hast-util-to-html: 9.0.5 + + '@shikijs/engine-javascript@4.5.0': + dependencies: + '@shikijs/types': 4.5.0 + '@shikijs/vscode-textmate': 10.1.0 + oniguruma-to-es: 4.3.6 + + '@shikijs/engine-oniguruma@4.5.0': + dependencies: + '@shikijs/types': 4.5.0 + '@shikijs/vscode-textmate': 10.1.0 + + '@shikijs/langs@4.5.0': + dependencies: + '@shikijs/types': 4.5.0 + + '@shikijs/primitive@4.5.0': + dependencies: + '@shikijs/types': 4.5.0 + '@shikijs/vscode-textmate': 10.1.0 + '@types/hast': 3.0.5 + + '@shikijs/themes@4.5.0': + dependencies: + '@shikijs/types': 4.5.0 + + '@shikijs/types@4.5.0': + dependencies: + '@shikijs/vscode-textmate': 10.1.0 + '@types/hast': 3.0.5 + + '@shikijs/vscode-textmate@10.1.0': {} + + '@tybys/wasm-util@0.10.4': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/estree-jsx@1.0.5': + dependencies: + '@types/estree': 1.0.9 + + '@types/estree@1.0.9': {} + + '@types/hast@3.0.5': + dependencies: + '@types/unist': 3.0.3 + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/nlcst@2.0.3': + dependencies: + '@types/unist': 3.0.3 + + '@types/unist@3.0.3': {} + + '@ungap/structured-clone@1.4.0': {} + + am-i-vibing@0.5.0: + dependencies: + process-ancestry: 0.1.0 + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.2 + + aria-query@5.3.2: {} + + astro@7.3.8(yaml@2.9.1): + dependencies: + '@astrojs/compiler-rs': 0.5.2 + '@astrojs/internal-helpers': 0.12.0 + '@astrojs/markdown-satteri': 0.4.3 + '@astrojs/telemetry': 3.3.3 + '@capsizecss/unpack': 4.0.1 + '@clack/prompts': 1.8.1 + '@oslojs/encoding': 1.1.0 + am-i-vibing: 0.5.0 + aria-query: 5.3.2 + axobject-query: 4.1.0 + ci-info: 4.4.0 + clsx: 2.1.1 + common-ancestor-path: 2.0.0 + cookie: 2.0.1 + devalue: 5.9.4 + diff: 9.0.0 + dset: 3.1.4 + es-module-lexer: 3.0.4 + find-proc: 0.2.0 + flattie: 1.1.1 + fontace: 0.4.1 + get-tsconfig: 5.0.0-beta.6 + github-slugger: 2.0.0 + html-escaper: 3.0.3 + http-cache-semantics: 4.3.0 + jsonc-parser: 3.3.1 + magic-string: 1.4.3 + magicast: 0.5.5 + mrmime: 2.0.1 + neotraverse: 1.0.1 + obug: 3.0.0 + p-limit: 7.3.3 + p-queue: 9.3.5 + package-manager-detector: 1.9.0 + piccolore: 0.1.3 + picomatch: 4.0.7 + rolldown: 1.2.15 + shiki: 4.5.0 + smol-toml: 1.9.1 + svgo: 4.1.0 + tinyclip: 1.0.3 + tinyexec: 1.3.1 + tinyglobby: 0.2.17 + ultrahtml: 1.7.0 + unifont: 0.7.5 + unstorage: 1.17.6 + verkit: 0.5.0 + vite: 8.3.5(yaml@2.9.1) + vitefu: 1.1.3(vite@8.3.5(yaml@2.9.1)) + xxhash-wasm: 1.1.0 + yargs-parser: 22.0.0 + zod: 4.6.7 + optionalDependencies: + sharp: 0.35.5 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@types/node' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - '@vitejs/devtools' + - aws4fetch + - db0 + - esbuild + - idb-keyval + - ioredis + - jiti + - less + - sass + - sass-embedded + - stylus + - sugarss + - terser + - tsx + - uploadthing + - yaml + + axobject-query@4.1.0: {} + + bail@2.0.2: {} + + boolbase@1.0.0: {} + + ccount@2.0.1: {} + + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + chokidar@5.0.0: + dependencies: + readdirp: 5.1.1 + + ci-info@4.4.0: {} + + clsx@2.1.1: {} + + comma-separated-tokens@2.0.3: {} + + commander@11.1.0: {} + + common-ancestor-path@2.0.0: {} + + cookie-es@1.2.3: {} + + cookie@2.0.1: {} + + crossws@0.3.5: + dependencies: + uncrypto: 0.1.3 + + css-select@6.0.0: + dependencies: + boolbase: 1.0.0 + css-what: 7.0.0 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + + css-tree@2.2.0: + dependencies: + mdn-data: 2.0.28 + source-map-js: 1.2.2 + + css-tree@3.2.1: + dependencies: + mdn-data: 2.27.1 + source-map-js: 1.2.2 + + css-what@7.0.0: {} + + csso@5.0.5: + dependencies: + css-tree: 2.2.0 + + defu@6.1.7: {} + + dequal@2.0.3: {} + + destr@2.0.5: {} + + detect-libc@2.1.2: {} + + devalue@5.9.4: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + diff@9.0.0: {} + + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.2.0 + + domelementtype@2.3.0: {} + + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + + domutils@3.2.2: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + + dset@3.1.4: {} + + entities@4.2.0: {} + + es-module-lexer@3.0.4: {} + + eventemitter3@5.0.4: {} + + extend@3.0.2: {} + + fast-string-truncated-width@3.0.3: {} + + fast-string-width@3.0.2: + dependencies: + fast-string-truncated-width: 3.0.3 + + fast-wrap-ansi@0.2.2: + dependencies: + fast-string-width: 3.0.2 + + fdir@6.5.0(picomatch@4.0.7): + optionalDependencies: + picomatch: 4.0.7 + + find-proc@0.2.0: {} + + flattie@1.1.1: {} + + fontace@0.4.1: + dependencies: + fontkitten: 1.0.3 + + fontkitten@1.0.3: + dependencies: + tiny-inflate: 1.0.3 + + fsevents@2.3.3: + optional: true + + get-tsconfig@5.0.0-beta.6: + dependencies: + resolve-pkg-maps: 1.0.0 + + github-slugger@2.0.0: {} + + h3@1.15.11: + dependencies: + cookie-es: 1.2.3 + crossws: 0.3.5 + defu: 6.1.7 + destr: 2.0.5 + iron-webcrypto: 1.2.1 + node-mock-http: 1.0.5 + radix3: 1.1.2 + ufo: 1.6.4 + uncrypto: 0.1.3 + + hast-util-to-html@9.0.5: + dependencies: + '@types/hast': 3.0.5 + '@types/unist': 3.0.3 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + property-information: 7.2.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.5 + + html-escaper@3.0.3: {} + + html-void-elements@3.0.0: {} + + http-cache-semantics@4.3.0: {} + + iron-webcrypto@1.2.1: {} + + is-docker@4.0.0: {} + + is-plain-obj@4.1.0: {} + + jsonc-parser@3.3.1: {} + + lightningcss-android-arm64@1.33.0: + optional: true + + lightningcss-darwin-arm64@1.33.0: + optional: true + + lightningcss-darwin-x64@1.33.0: + optional: true + + lightningcss-freebsd-x64@1.33.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.33.0: + optional: true + + lightningcss-linux-arm64-gnu@1.33.0: + optional: true + + lightningcss-linux-arm64-musl@1.33.0: + optional: true + + lightningcss-linux-x64-gnu@1.33.0: + optional: true + + lightningcss-linux-x64-musl@1.33.0: + optional: true + + lightningcss-win32-arm64-msvc@1.33.0: + optional: true + + lightningcss-win32-x64-msvc@1.33.0: + optional: true + + lightningcss@1.33.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.33.0 + lightningcss-darwin-arm64: 1.33.0 + lightningcss-darwin-x64: 1.33.0 + lightningcss-freebsd-x64: 1.33.0 + lightningcss-linux-arm-gnueabihf: 1.33.0 + lightningcss-linux-arm64-gnu: 1.33.0 + lightningcss-linux-arm64-musl: 1.33.0 + lightningcss-linux-x64-gnu: 1.33.0 + lightningcss-linux-x64-musl: 1.33.0 + lightningcss-win32-arm64-msvc: 1.33.0 + lightningcss-win32-x64-msvc: 1.33.0 + + lru-cache@11.5.3: {} + + magic-string@1.4.3: + dependencies: + '@jridgewell/sourcemap-codec': 1.6.0 + + magicast@0.5.5: + dependencies: + '@babel/parser': 7.29.9 + '@babel/types': 7.29.8 + source-map-js: 1.2.2 + + mdast-util-to-hast@13.2.1: + dependencies: + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.4.0 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.0 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + + mdn-data@2.0.28: {} + + mdn-data@2.27.1: {} + + micromark-util-character@2.0.0: + dependencies: + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.3 + + micromark-util-encode@2.0.0: {} + + micromark-util-sanitize-uri@2.0.0: + dependencies: + micromark-util-character: 2.0.0 + micromark-util-encode: 2.0.0 + micromark-util-symbol: 2.0.0 + + micromark-util-symbol@2.0.0: {} + + micromark-util-types@2.0.3: {} + + mrmime@2.0.1: {} + + nanoid@3.3.20: {} + + neotraverse@1.0.1: {} + + nlcst-to-string@4.0.0: + dependencies: + '@types/nlcst': 2.0.3 + + node-fetch-native@1.6.7: {} + + node-mock-http@1.0.5: {} + + normalize-path@3.0.0: {} + + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + + obug@3.0.0: {} + + ofetch@1.5.1: + dependencies: + destr: 2.0.5 + node-fetch-native: 1.6.7 + ufo: 1.6.4 + + ohash@2.0.12: {} + + oniguruma-parser@0.12.2: {} + + oniguruma-to-es@4.3.6: + dependencies: + oniguruma-parser: 0.12.2 + regex: 6.1.0 + regex-recursion: 6.0.2 + + p-limit@7.3.3: + dependencies: + yocto-queue: 1.2.2 + + p-queue@9.3.5: + dependencies: + eventemitter3: 5.0.4 + p-timeout: 7.0.2 + + p-timeout@7.0.2: {} + + package-manager-detector@1.9.0: {} + + piccolore@0.1.3: {} + + picocolors@1.1.1: {} + + picomatch@2.3.2: {} + + picomatch@4.0.7: {} + + postcss@8.5.31: + dependencies: + nanoid: 3.3.20 + picocolors: 1.1.1 + source-map-js: 1.2.2 + + prismjs@1.30.0: {} + + process-ancestry@0.1.0: {} + + property-information@7.2.0: {} + + radix3@1.1.2: {} + + readdirp@5.1.1: {} + + regex-recursion@6.0.2: + dependencies: + regex-utilities: 2.3.0 + + regex-utilities@2.3.0: {} + + regex@6.1.0: + dependencies: + regex-utilities: 2.3.0 + + resolve-pkg-maps@1.0.0: {} + + retext-smartypants@6.2.0: + dependencies: + '@types/nlcst': 2.0.3 + nlcst-to-string: 4.0.0 + unist-util-visit: 5.1.0 + + rolldown@1.2.15: + dependencies: + '@oxc-project/types': 0.155.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm-eabi': 1.2.15 + '@rolldown/binding-android-arm64': 1.2.15 + '@rolldown/binding-darwin-arm64': 1.2.15 + '@rolldown/binding-darwin-x64': 1.2.15 + '@rolldown/binding-freebsd-x64': 1.2.15 + '@rolldown/binding-linux-arm-gnueabihf': 1.2.15 + '@rolldown/binding-linux-arm64-gnu': 1.2.15 + '@rolldown/binding-linux-arm64-musl': 1.2.15 + '@rolldown/binding-linux-ppc64-gnu': 1.2.15 + '@rolldown/binding-linux-s390x-gnu': 1.2.15 + '@rolldown/binding-linux-x64-gnu': 1.2.15 + '@rolldown/binding-linux-x64-musl': 1.2.15 + '@rolldown/binding-openharmony-arm64': 1.2.15 + '@rolldown/binding-win32-arm64-msvc': 1.2.15 + '@rolldown/binding-win32-x64-msvc': 1.2.15 + + satteri@0.10.5: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + optionalDependencies: + '@bruits/satteri-darwin-arm64': 0.10.5 + '@bruits/satteri-darwin-x64': 0.10.5 + '@bruits/satteri-linux-arm64-gnu': 0.10.5 + '@bruits/satteri-linux-arm64-musl': 0.10.5 + '@bruits/satteri-linux-x64-gnu': 0.10.5 + '@bruits/satteri-linux-x64-musl': 0.10.5 + '@bruits/satteri-wasm32-wasi': 0.10.5 + '@bruits/satteri-win32-arm64-msvc': 0.10.5 + '@bruits/satteri-win32-x64-msvc': 0.10.5 + + sax@1.6.1: {} + + semver@7.8.5: + optional: true + + sharp@0.35.5: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.5 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.35.5 + '@img/sharp-darwin-x64': 0.35.5 + '@img/sharp-freebsd-wasm32': 0.35.5 + '@img/sharp-libvips-darwin-arm64': 1.3.4 + '@img/sharp-libvips-darwin-x64': 1.3.4 + '@img/sharp-libvips-linux-arm': 1.3.4 + '@img/sharp-libvips-linux-arm64': 1.3.4 + '@img/sharp-libvips-linux-ppc64': 1.3.4 + '@img/sharp-libvips-linux-riscv64': 1.3.4 + '@img/sharp-libvips-linux-s390x': 1.3.4 + '@img/sharp-libvips-linux-x64': 1.3.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.4 + '@img/sharp-libvips-linuxmusl-x64': 1.3.4 + '@img/sharp-linux-arm': 0.35.5 + '@img/sharp-linux-arm64': 0.35.5 + '@img/sharp-linux-ppc64': 0.35.5 + '@img/sharp-linux-riscv64': 0.35.5 + '@img/sharp-linux-s390x': 0.35.5 + '@img/sharp-linux-x64': 0.35.5 + '@img/sharp-linuxmusl-arm64': 0.35.5 + '@img/sharp-linuxmusl-x64': 0.35.5 + '@img/sharp-webcontainers-wasm32': 0.35.5 + '@img/sharp-win32-arm64': 0.35.5 + '@img/sharp-win32-ia32': 0.35.5 + '@img/sharp-win32-x64': 0.35.5 + optional: true + + shiki@4.5.0: + dependencies: + '@shikijs/core': 4.5.0 + '@shikijs/engine-javascript': 4.5.0 + '@shikijs/engine-oniguruma': 4.5.0 + '@shikijs/langs': 4.5.0 + '@shikijs/themes': 4.5.0 + '@shikijs/types': 4.5.0 + '@shikijs/vscode-textmate': 10.1.0 + '@types/hast': 3.0.5 + + sisteransi@1.0.5: {} + + smol-toml@1.9.1: {} + + source-map-js@1.2.2: {} + + space-separated-tokens@2.0.2: {} + + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + + svgo@4.1.0: + dependencies: + commander: 11.1.0 + css-select: 6.0.0 + css-tree: 3.2.1 + css-what: 7.0.0 + csso: 5.0.5 + picocolors: 1.1.1 + sax: 1.6.1 + + tiny-inflate@1.0.3: {} + + tinyclip@1.0.3: {} + + tinyexec@1.3.1: {} + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 + + trim-lines@3.0.1: {} + + trough@2.2.0: {} + + tslib@2.8.1: + optional: true + + ufo@1.6.4: {} + + ultrahtml@1.7.0: {} + + uncrypto@0.1.3: {} + + undici@8.12.3: {} + + unified@11.0.5: + dependencies: + '@types/unist': 3.0.3 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 + + unifont@0.7.5: + dependencies: + css-tree: 3.2.1 + ohash: 2.0.12 + undici: 8.12.3 + + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.1.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + unstorage@1.17.6: + dependencies: + anymatch: 3.1.3 + chokidar: 5.0.0 + destr: 2.0.5 + h3: 1.15.11 + lru-cache: 11.5.3 + node-fetch-native: 1.6.7 + ofetch: 1.5.1 + ufo: 1.6.4 + + verkit@0.5.0: {} + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.3 + + vite@8.3.5(yaml@2.9.1): + dependencies: + lightningcss: 1.33.0 + picomatch: 4.0.7 + postcss: 8.5.31 + rolldown: 1.2.15 + tinyglobby: 0.2.17 + optionalDependencies: + fsevents: 2.3.3 + yaml: 2.9.1 + + vitefu@1.1.3(vite@8.3.5(yaml@2.9.1)): + optionalDependencies: + vite: 8.3.5(yaml@2.9.1) + + xxhash-wasm@1.1.0: {} + + yaml@2.9.1: {} + + yargs-parser@22.0.0: {} + + yocto-queue@1.2.2: {} + + zod@4.6.7: {} + + zwitch@2.0.4: {} diff --git a/src/pages/index.astro b/src/pages/index.astro new file mode 100644 index 0000000..b3d436f --- /dev/null +++ b/src/pages/index.astro @@ -0,0 +1,8 @@ +--- +// T1 占位首页:T5 起替换为 BaseLayout + 真实首页结构 +import '../styles/global.css'; +--- + + wait4x + Phase 1 skeleton + diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..8bf91d3 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "astro/tsconfigs/strict", + "include": [".astro/types.d.ts", "**/*"], + "exclude": ["dist"] +} From 4cb1c85cc3c9ea023ff52110ca49d97b5a5542c9 Mon Sep 17 00:00:00 2001 From: wait4xx Date: Sat, 24 Oct 2026 23:07:11 +0800 Subject: [PATCH 03/10] =?UTF-8?q?feat(design):=20=E8=AE=BE=E8=AE=A1=20toke?= =?UTF-8?q?ns=20=E4=B8=8E=E5=85=A8=E5=B1=80=E6=A0=B7=E5=BC=8F=E2=80=94?= =?UTF-8?q?=E2=80=94=E4=B8=99=E8=B7=AF=E7=BA=BF=E3=80=8C=E7=81=B0=E9=98=B6?= =?UTF-8?q?=E9=AA=A8=E6=9E=B6=C3=97=E5=88=86=E8=BD=A8=E6=AD=A3=E6=96=87?= =?UTF-8?q?=E3=80=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - tokens.css:四档灰阶/单强调蓝/蓝黑暗色/纸墨面板/情绪色五档/ 字体三轨栈/排版三角(书评20-1.75-720 技术19-1.7)/唯一缓动曲线 - global.css:轻量reset/双轨正文(.prose-reading/.prose-tech)/ 引文A墨线+D金句62px水印/终端风代码块/::selection半透明/ 560px降档18px/动效总闸prefers-reduced-motion 验证: pnpm astro build exit 0;参数与调研报告 §3 一一对应 Spec: 2026-10-24_add-blog-skeleton Co-authored-by: GLM-5.3 --- src/styles/global.css | 162 ++++++++++++++++++++++++++++++++++++++++++ src/styles/tokens.css | 108 ++++++++++++++++++++++++++++ 2 files changed, 270 insertions(+) create mode 100644 src/styles/global.css create mode 100644 src/styles/tokens.css diff --git a/src/styles/global.css b/src/styles/global.css new file mode 100644 index 0000000..84b7474 --- /dev/null +++ b/src/styles/global.css @@ -0,0 +1,162 @@ +/* ============================================================ + 全局样式 —— 建立在 tokens.css 之上 + 约束:零运行时框架;动效全部包 prefers-reduced-motion + ============================================================ */ +@import "./tokens.css"; + +/* ---------- 轻量 reset ---------- */ +*, *::before, *::after { box-sizing: border-box; } +* { margin: 0; } +html { -webkit-text-size-adjust: 100%; } +body { + font-family: var(--font-sans); + font-size: 16px; + line-height: 1.6; + color: var(--ink-2); + background: var(--bg); +} +img, svg, video { display: block; max-width: 100%; height: auto; } +input, button, textarea, select { font: inherit; color: inherit; } + +/* 键盘焦点可见但克制 */ +:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; } + +/* 跳过导航(无障碍动线) */ +.skip-link { + position: absolute; left: -9999px; top: var(--space-2); + padding: var(--space-2) var(--space-3); background: var(--bg); z-index: 100; +} +.skip-link:focus { left: var(--space-2); } + +/* ---------- 链接(全站唯一强调色纪律) ---------- */ +a { color: inherit; text-decoration: none; } +.link, .prose a { + color: var(--accent); + text-decoration: underline; + text-decoration-color: color-mix(in oklab, var(--accent) 40%, transparent); + text-underline-offset: 0.2em; + transition: text-decoration-color var(--dur) var(--ease), color var(--dur) var(--ease); +} +.link:hover, .prose a:hover { text-decoration-color: var(--accent); } + +/* ---------- 版心 ---------- */ +.container { max-width: var(--measure); margin-inline: auto; padding-inline: var(--space-3); } +.container-wide { max-width: calc(var(--measure) + 200px); margin-inline: auto; padding-inline: var(--space-3); } + +/* ============================================================ + 正文分轨(丙路线核心:书评纸墨 × 技术灰阶) + ============================================================ */ + +/* ---- 书评轨:纸面板 + 衬线 + 20/1.75 ---- */ +.prose-reading { + font-family: var(--font-serif); + font-size: var(--prose-size-reading); + line-height: var(--leading-reading); + color: var(--paper-ink); + background: var(--paper); + max-width: var(--measure); + padding: var(--space-5) var(--space-4); + border-block: 1px solid var(--paper-line); + overflow-wrap: break-word; +} +.prose-reading p + p { margin-top: 0.9em; } /* 段间距制,无首行缩进 */ +.prose-reading h2, .prose-reading h3 { line-height: var(--leading-heading); text-wrap: balance; } +.prose-reading h2 { font-size: var(--text-h2); margin-top: 1.8em; } +.prose-reading h3 { font-size: var(--text-h3); margin-top: 1.5em; } + +/* ---- 技术轨:无衬线 + 19/1.7 ---- */ +.prose-tech { + font-family: var(--font-sans); + font-size: var(--prose-size-tech); + line-height: var(--leading-tech); + color: var(--ink-2); + max-width: var(--measure); +} +.prose-tech p + p { margin-top: 0.9em; } +.prose-tech h2 { font-size: var(--text-h2); margin-top: 1.8em; line-height: var(--leading-heading); text-wrap: balance; } +.prose-tech h3 { font-size: var(--text-h3); margin-top: 1.5em; line-height: var(--leading-heading); } + +/* ---------- 引文组件(报告 §3:A 墨线长书摘 / D 金句) ---------- */ +/* 模式 A:学术极简(长书摘) */ +blockquote.quote-block { + border-left: 1px solid var(--paper-line); + border-left-width: 2px; + padding-left: 1.35em; + margin-block: 1.2em; + color: color-mix(in oklab, var(--paper-ink) 72%, transparent); + font-size: 1em; + font-style: normal; /* 反例修正:higan 整段加粗弃用 */ + font-weight: 400; +} +.quote-cite { + display: block; + margin-top: 0.6em; + font-size: 0.875rem; + font-family: var(--font-sans); + color: var(--ink-3); +} +/* 模式 D:金句(62px 巨型引号水印) */ +.pull-quote { + position: relative; + margin-block: 1.6em; + padding-left: 2.2em; + font-size: 0.96em; +} +.pull-quote::before { + content: "\201C"; + position: absolute; left: 0; top: -0.12em; + font-family: Georgia, serif; + font-size: 62px; + line-height: 1; + opacity: 0.18; + color: var(--mood); +} + +/* ---------- 代码(终端风,亮暗同底) ---------- */ +code, kbd, samp { font-family: var(--font-mono); } +:not(pre) > code { + font-size: 0.875em; + background: var(--bg-soft); + padding: 0.15em 0.4em; + border-radius: 4px; + border: 1px solid var(--line); +} +pre { + background: var(--code-bg); + color: var(--code-ink); + font-size: 16px; + line-height: 1.6; + padding: var(--space-3) var(--space-4); + border-radius: 8px; + overflow-x: auto; /* 禁 break-all:正文横向滚动绝不发生 */ + tab-size: 2; +} +pre code { background: none; border: none; padding: 0; font-size: inherit; } +/* 终端窗点缀(圆点由组件层加,此处只管字色纪律) */ +.term-dots { display: flex; gap: 6px; margin-bottom: var(--space-2); } +.term-dots span { width: 10px; height: 10px; border-radius: 50%; background: #30363d; } + +/* ---------- 列表/分隔 ---------- */ +hr { border: none; border-top: 1px solid var(--line); margin-block: var(--space-4); } + +/* ---------- 选区(半透明强调,避免刺眼实心) ---------- */ +::selection { background: var(--accent-soft); } + +/* ---------- 触屏与安全区(§4e:交互组件显式 .tap 类达 44px 目标) ---------- */ +.tap { min-height: 44px; min-width: 44px; display: inline-flex; align-items: center; justify-content: center; } +.safe-area { padding-left: env(safe-area-inset-left); padding-right: env(safe-area-inset-right); } + +/* ---------- 移动端排版降档(≤560px:书评 20→18) ---------- */ +@media (max-width: 560px) { + :root { --prose-size-reading: 18px; --prose-size-tech: 18px; --text-h1: 24px; } + .prose-reading { padding: var(--space-4) var(--space-3); } +} + +/* ---------- 动效总闸(唯一曲线已入 tokens) ---------- */ +@media (prefers-reduced-motion: reduce) { + *, *::before, *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } +} diff --git a/src/styles/tokens.css b/src/styles/tokens.css new file mode 100644 index 0000000..c881564 --- /dev/null +++ b/src/styles/tokens.css @@ -0,0 +1,108 @@ +/* ============================================================ + 设计 tokens —— 丙路线「灰阶骨架 × 分轨正文」 + 参数依据:docs/博客重设计调研报告.md §2/§3(v1.8 定稿) + 命名约定:--<类别>-<语义>,暗色经 [data-theme="dark"] 整套覆盖 + ============================================================ */ + +:root { + color-scheme: light dark; + + /* ---- 底色与文字(骨架四档灰阶) ---- */ + --bg: #ffffff; + --bg-soft: #f7f7f8; /* 次级面板:代码块外框、卡片衬底 */ + --ink-1: #111113; /* 标题 */ + --ink-2: #33343a; /* 正文 */ + --ink-3: #6b6e78; /* 次要:日期、元信息 */ + --ink-4: #a0a3ad; /* 装饰:分隔线、icon 底 */ + --line: #e6e7eb; /* 分隔线 */ + + /* ---- 强调色(全站唯一,链接/hover/选中) ---- */ + --accent: #3454d1; + --accent-soft: rgba(52, 84, 209, 0.12); /* ::selection / 轻底 */ + + /* ---- 分轨:书评纸面板(正文阅读区) ---- */ + --paper: #f8f6f1; /* 米白纸底 */ + --paper-ink: #2c2a26; /* 纸上墨字(比骨架 ink 暖) */ + --paper-line: #d9d4c8; + + /* ---- 书评情绪色(frontmatter mood 覆盖,此处为缺省五档) ---- */ + --mood: var(--ink-3); + --mood-1: #b45309; /* 琥珀 */ + --mood-2: #0f766e; /* 松绿 */ + --mood-3: #7c3aed; /* 紫晶 */ + --mood-4: #9f1239; /* 绛红 */ + --mood-5: #166534; /* 苔绿 */ + + /* ---- 字体三轨 ---- */ + /* 书评正文:霞鹜文楷屏显版(T3 以预分片自托管替换栈首) */ + --font-serif: "LXGW WenKai Screen", "Songti SC", STSong, "Noto Serif CJK SC", + "Source Han Serif SC", SimSun, serif; + /* UI / 技术文:思源黑 */ + --font-sans: "Noto Sans SC", system-ui, -apple-system, "PingFang SC", + "Hiragino Sans GB", "Microsoft YaHei", sans-serif; + /* 代码 */ + --font-mono: "JetBrains Mono", ui-monospace, Consolas, "Courier New", monospace; + + /* ---- 排版三角(报告 §3:书评 20/1.75/720;技术 19/1.7) ---- */ + --prose-size-reading: 20px; + --prose-size-tech: 19px; + --leading-reading: 1.75; + --leading-tech: 1.7; + --measure: 720px; /* 版心 ≈36 汉字 */ + --leading-heading: 1.3; + + /* ---- 标题字阶 ---- */ + --text-h1: 27px; + --text-h2: 22px; + --text-h3: 19px; + + /* ---- 代码块(终端风,亮暗同底) ---- */ + --code-bg: #0d1117; + --code-ink: #e6edf3; + + /* ---- 动效纪律:全站唯一曲线与时长 ---- */ + --ease: cubic-bezier(0.19, 1, 0.22, 1); + --dur: 350ms; + + /* ---- 间距阶 ---- */ + --space-1: 4px; + --space-2: 8px; + --space-3: 16px; + --space-4: 24px; + --space-5: 40px; + --space-6: 64px; + + /* ---- 布局断点(§4e:1120/820/760/560,供媒体查询引用的文档锚) ---- + --bp-1: 1120px 宽屏:TOC 侧栏常驻 + --bp-2: 820px 笔电:TOC 收起 + --bp-3: 760px 平板竖屏 + --bp-4: 560px 手机(正文降到 18px,见 global.css) */ +} + +/* ---------- 暗色:蓝黑骨架(#191d23 系),纸面板转暗室书页 ---------- */ +[data-theme="dark"] { + color-scheme: dark; + + --bg: #191d23; + --bg-soft: #1f242b; + --ink-1: #f5f5f7; + --ink-2: #c9ccd4; + --ink-3: #8b8f98; + --ink-4: #5c6066; + --line: #2c313a; + + --accent: #8ea2ff; + --accent-soft: rgba(142, 162, 255, 0.18); + + --paper: #201d18; /* 暗室里的书页 */ + --paper-ink: #d8d2c4; + --paper-line: #38342c; + + --code-bg: #0d1117; + --code-ink: #e6edf3; +} + +/* 用户显式选择 light 时钉住亮色(防系统翻转闪烁的配合面) */ +[data-theme="light"] { + color-scheme: light; +} From ee532798222bd75eb67aabfa0c008339a940f66e Mon Sep 17 00:00:00 2001 From: wait4xx Date: Sat, 24 Oct 2026 23:08:36 +0800 Subject: [PATCH 04/10] =?UTF-8?q?feat(fonts):=20=E5=AD=97=E4=BD=93?= =?UTF-8?q?=E4=B8=89=E8=BD=A8=E9=A2=84=E5=88=86=E7=89=87=E8=87=AA=E6=89=98?= =?UTF-8?q?=E7=AE=A1=E6=8E=A5=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - lxgw-wenkai-screen-webfont + @fontsource/noto-sans-sc(400/500/700) + @fontsource/jetbrains-mono(400/700),均 OFL - unicode-range 按需加载 + font-display swap;家族名与 tokens 栈首一致 - 教训:包 css 不能经 .css 文件 ESM import,须组件 frontmatter 持有 验证: pnpm astro build exit 0;dist woff2 分片 399 个(>50 门槛) Spec: 2026-10-24_add-blog-skeleton Co-authored-by: GLM-5.3 --- package.json | 5 ++++- pnpm-lock.yaml | 24 ++++++++++++++++++++++++ src/pages/index.astro | 7 +++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 48999c3..705bd0f 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,9 @@ "astro": "astro" }, "dependencies": { - "astro": "^7.3.8" + "@fontsource/jetbrains-mono": "^5.3.0", + "@fontsource/noto-sans-sc": "^5.3.1", + "astro": "^7.3.8", + "lxgw-wenkai-screen-webfont": "^1.7.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index da59a85..064927b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,9 +8,18 @@ importers: .: dependencies: + '@fontsource/jetbrains-mono': + specifier: ^5.3.0 + version: 5.3.0 + '@fontsource/noto-sans-sc': + specifier: ^5.3.1 + version: 5.3.1 astro: specifier: ^7.3.8 version: 7.3.8(yaml@2.9.1) + lxgw-wenkai-screen-webfont: + specifier: ^1.7.0 + version: 1.7.0 packages: @@ -195,6 +204,12 @@ packages: '@emnapi/wasi-threads@1.2.3': resolution: {integrity: sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g==} + '@fontsource/jetbrains-mono@5.3.0': + resolution: {integrity: sha512-fqDfB5I9f1p1TV486aUgB9t8zP84P0O1FtQR5Ol9vjwPy+S+EIGlVYm1cvj2W5shcZMTg2nZFdVMoH5wFu8a1A==} + + '@fontsource/noto-sans-sc@5.3.1': + resolution: {integrity: sha512-YxZ/VWAWo9FWzH08Q6fGTzIW6vYNP2TMhUFCnfhlimbhdXnWrxJLrzX3KWt2FKnV0s8XiM5vjpGHQiyFRlTj0w==} + '@img/colour@1.1.0': resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} engines: {node: '>=18'} @@ -830,6 +845,9 @@ packages: resolution: {integrity: sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==} engines: {node: 20 || >=22} + lxgw-wenkai-screen-webfont@1.7.0: + resolution: {integrity: sha512-xvfF4V26Mb335xKg3uxljz+V2nq4F5ek0ku9pmyKgT0Dzo/d2rHi7WpnqgvM9mlXAcAKOrxrcDmUZiIs/ZQ9bQ==} + magic-string@1.4.3: resolution: {integrity: sha512-z12OxmaPGE0F4xlpGdjuAUckipLpQlTAuAmyGhNoD7ODpYUzvDfvtxUbjM/jwznyP178oju/KDdyi220wNJ0RQ==} @@ -1400,6 +1418,10 @@ snapshots: tslib: 2.8.1 optional: true + '@fontsource/jetbrains-mono@5.3.0': {} + + '@fontsource/noto-sans-sc@5.3.1': {} + '@img/colour@1.1.0': optional: true @@ -1973,6 +1995,8 @@ snapshots: lru-cache@11.5.3: {} + lxgw-wenkai-screen-webfont@1.7.0: {} + magic-string@1.4.3: dependencies: '@jridgewell/sourcemap-codec': 1.6.0 diff --git a/src/pages/index.astro b/src/pages/index.astro index b3d436f..02c52b0 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -1,5 +1,12 @@ --- // T1 占位首页:T5 起替换为 BaseLayout + 真实首页结构 +// 字体三轨在此预挂(T5 移入 BaseLayout):unicode-range 预分片自托管 +import 'lxgw-wenkai-screen-webfont/lxgwwenkaiscreen.css'; +import '@fontsource/noto-sans-sc/400.css'; +import '@fontsource/noto-sans-sc/500.css'; +import '@fontsource/noto-sans-sc/700.css'; +import '@fontsource/jetbrains-mono/400.css'; +import '@fontsource/jetbrains-mono/700.css'; import '../styles/global.css'; --- From b50eddf2bb2602a375f0f8b62a681b6398ca4695 Mon Sep 17 00:00:00 2001 From: wait4xx Date: Sat, 24 Oct 2026 23:09:45 +0800 Subject: [PATCH 05/10] =?UTF-8?q?feat(layout):=20=E5=9F=BA=E7=A1=80?= =?UTF-8?q?=E5=B8=83=E5=B1=80/=E5=AF=BC=E8=88=AA/=E9=A1=B5=E8=84=9A/?= =?UTF-8?q?=E6=98=8E=E6=9A=97=E4=B8=8D=E9=97=AA=E7=83=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - BaseLayout:字体三轨统持、viewport-fit=cover、theme-color 双套、skip-link - Header:≤4 项导航纪律 + sticky 毛玻璃 + aria-current;搜索 icon 占位待 T8 - Footer:ICP 备案链接(法定保留)+ built-from 具名槽位待 T7 - ThemeScript:head 内联先于首帧,手选 > 系统偏好,防白闪 验证: pnpm astro build exit 0;dist/index.html 含 ICP 文案与跳到正文链 Spec: 2026-10-24_add-blog-skeleton Co-authored-by: GLM-5.3 --- src/components/Footer.astro | 39 +++++++++++++++ src/components/Header.astro | 84 ++++++++++++++++++++++++++++++++ src/components/ThemeScript.astro | 14 ++++++ src/layouts/BaseLayout.astro | 44 +++++++++++++++++ src/pages/index.astro | 17 ++----- 5 files changed, 185 insertions(+), 13 deletions(-) create mode 100644 src/components/Footer.astro create mode 100644 src/components/Header.astro create mode 100644 src/components/ThemeScript.astro create mode 100644 src/layouts/BaseLayout.astro diff --git a/src/components/Footer.astro b/src/components/Footer.astro new file mode 100644 index 0000000..9b53d13 --- /dev/null +++ b/src/components/Footer.astro @@ -0,0 +1,39 @@ +--- +// 页脚:版权 + ICP 备案(法定保留)+ 构建透明槽位(T7 built-from 填充) +--- + + + + diff --git a/src/components/Header.astro b/src/components/Header.astro new file mode 100644 index 0000000..d1c17a9 --- /dev/null +++ b/src/components/Header.astro @@ -0,0 +1,84 @@ +--- +// 顶部导航:≤4 项纪律(防 higan 十项复发);当前页 aria-current +const nav = [ + { href: '/archives/', label: '文章' }, + { href: '/gallery/', label: '图库' }, + { href: '/about/', label: '关于' }, +]; +const path = Astro.url.pathname; +const isCurrent = (href: string) => + path === href || path === href.replace(/\/$/, '') || path.startsWith(href); +--- + + + + diff --git a/src/components/ThemeScript.astro b/src/components/ThemeScript.astro new file mode 100644 index 0000000..e3ab50b --- /dev/null +++ b/src/components/ThemeScript.astro @@ -0,0 +1,14 @@ +--- +// 明暗不闪烁脚本: 内联、先于首帧。 +// 优先级:用户手选(localStorage) > 系统偏好;切换按钮(T7 键盘/组件)写同一 key。 +--- + + diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro new file mode 100644 index 0000000..b89774e --- /dev/null +++ b/src/layouts/BaseLayout.astro @@ -0,0 +1,44 @@ +--- +// 基础布局:字体/样式统一在此持有(页面不再各自引包) +// 明暗不闪烁:ThemeScript 必须在 内联先于首帧执行 +import 'lxgw-wenkai-screen-webfont/lxgwwenkaiscreen.css'; +import '@fontsource/noto-sans-sc/400.css'; +import '@fontsource/noto-sans-sc/500.css'; +import '@fontsource/noto-sans-sc/700.css'; +import '@fontsource/jetbrains-mono/400.css'; +import '@fontsource/jetbrains-mono/700.css'; +import '../styles/global.css'; +import Header from '../components/Header.astro'; +import Footer from '../components/Footer.astro'; +import ThemeScript from '../components/ThemeScript.astro'; + +interface Props { + title: string; + description?: string; + /** 正文轨:reading 书评纸墨 / tech 技术(body 级字体氛围) */ + track?: 'reading' | 'tech'; +} +const { title, description = 'wait4x 的博客:阅读 · 技术 · 摄影', track = 'tech' } = Astro.props; +--- + + + + + + + + + + + {title} + + + + +
+
+ +
+
+ + diff --git a/src/pages/index.astro b/src/pages/index.astro index 02c52b0..307e816 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -1,15 +1,6 @@ --- -// T1 占位首页:T5 起替换为 BaseLayout + 真实首页结构 -// 字体三轨在此预挂(T5 移入 BaseLayout):unicode-range 预分片自托管 -import 'lxgw-wenkai-screen-webfont/lxgwwenkaiscreen.css'; -import '@fontsource/noto-sans-sc/400.css'; -import '@fontsource/noto-sans-sc/500.css'; -import '@fontsource/noto-sans-sc/700.css'; -import '@fontsource/jetbrains-mono/400.css'; -import '@fontsource/jetbrains-mono/700.css'; -import '../styles/global.css'; +import BaseLayout from '../layouts/BaseLayout.astro'; --- - - wait4x - Phase 1 skeleton - + +

Phase 1 · T5 布局就绪,首页结构 T6 填充。

+
From 725bfde21f6184856d808940f9384d8c20a2c7e9 Mon Sep 17 00:00:00 2001 From: wait4xx Date: Sat, 24 Oct 2026 23:13:23 +0800 Subject: [PATCH 06/10] =?UTF-8?q?feat(geek):=20=E6=9E=81=E5=AE=A2=E5=B1=82?= =?UTF-8?q?=20P0=20=E5=9B=9B=E4=BB=B6=E5=A5=97=E2=80=94=E2=80=94=E9=94=AE?= =?UTF-8?q?=E7=9B=98/=E6=9E=84=E5=BB=BA=E9=80=8F=E6=98=8E/=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E8=BD=AC=E5=9C=BA/=E9=A1=B9=E7=9B=AE=E5=A2=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Keyboard:? 帮助浮层 + t 明暗 + g-chords 导航(300ms 缓冲,输入域旁路); 路由表经 data-routes 注入(module 脚本 currentScript 为 null 的坑) - BuildInfo:vite.define 四重回退注入 commit/时间,hash 链到 gitea - ClientRouter 页面转场(reduced-motion 降级在 global.css 总闸) - ProjectWall:构建时双源拉取(gitea+github)置顶排序+缓存兜底,零运行时 JS - Header 补主题可视切换钮:键盘 t 的触屏等价物(同 key 同逻辑) 验证: pnpm astro build exit 0;dist 标记 built from×2/kbd-help×4/ view-transition×2; astro check 未跑(无类型错误构建期可证伪面有限) Spec: 2026-10-24_add-blog-skeleton Co-authored-by: GLM-5.3 --- astro.config.mjs | 19 +++++- src/components/Header.astro | 19 ++++++ src/components/geek/BuildInfo.astro | 13 ++++ src/components/geek/Keyboard.astro | 98 +++++++++++++++++++++++++++ src/components/geek/ProjectWall.astro | 71 +++++++++++++++++++ src/data/projects-fallback.json | 11 +++ src/layouts/BaseLayout.astro | 9 ++- src/lib/projects.ts | 86 +++++++++++++++++++++++ 8 files changed, 324 insertions(+), 2 deletions(-) create mode 100644 src/components/geek/BuildInfo.astro create mode 100644 src/components/geek/Keyboard.astro create mode 100644 src/components/geek/ProjectWall.astro create mode 100644 src/data/projects-fallback.json create mode 100644 src/lib/projects.ts diff --git a/astro.config.mjs b/astro.config.mjs index 85f1596..6c48e8b 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -1,7 +1,24 @@ // @ts-check import { defineConfig } from 'astro/config'; +import { execSync } from 'node:child_process'; + +// 构建透明(T7):commit/时间经 vite.define 注入,页脚与 /about 引用。 +// 四重回退:CI 环境变量优先(GITEA_ACTIONS/GITHUB_SHA)→ 本地 git → dev 占位。 +const sha = + process.env.GITEA_COMMIT_SHA || + process.env.GITHUB_SHA || + (() => { try { return execSync('git rev-parse HEAD').toString().trim(); } catch { return 'dev'; } })(); +const date = + process.env.GITEA_COMMIT_DATE || + process.env.GITHUB_COMMIT_DATE || + (() => { try { return execSync('git log -1 --format=%cI').toString().trim(); } catch { return new Date().toISOString(); } })(); -// 极简起点:集成(pagefind/rss/sitemap)在 T8 按任务加入,保持骨架可构建 export default defineConfig({ site: 'https://wait4x.online', + vite: { + define: { + 'import.meta.env.GIT_COMMIT_SHA': JSON.stringify(sha), + 'import.meta.env.GIT_COMMIT_DATE': JSON.stringify(date), + }, + }, }); diff --git a/src/components/Header.astro b/src/components/Header.astro index d1c17a9..44dd19b 100644 --- a/src/components/Header.astro +++ b/src/components/Header.astro @@ -35,11 +35,30 @@ const isCurrent = (href: string) => + +
  • + +
  • + + diff --git a/src/components/geek/ProjectWall.astro b/src/components/geek/ProjectWall.astro new file mode 100644 index 0000000..af60f34 --- /dev/null +++ b/src/components/geek/ProjectWall.astro @@ -0,0 +1,71 @@ +--- +// 开源项目墙(极客层 P0):构建时渲染,零运行时 JS +// 双源数据见 src/lib/projects.ts;语言色点用 linguist 常用色映射 +import { loadProjects, type RepoCard } from '../../lib/projects'; + +const LANG_COLORS: Record = { + Astro: '#ff5a03', TypeScript: '#3178c6', JavaScript: '#f1e05a', + Python: '#3572a5', Go: '#00add8', Rust: '#dea584', Shell: '#89e051', + HTML: '#e34c26', CSS: '#563d7c', Dockerfile: '#384d54', +}; + +let projects: RepoCard[] = []; +try { + projects = await loadProjects(); +} catch { + projects = []; // 兜底已在 lib 内处理,此处再守一层:空墙不破构建 +} +--- + +
    +

    开源 · Projects

    + +
    + + diff --git a/src/data/projects-fallback.json b/src/data/projects-fallback.json new file mode 100644 index 0000000..fe3abcf --- /dev/null +++ b/src/data/projects-fallback.json @@ -0,0 +1,11 @@ +[ + { + "source": "gitea", + "name": "blog", + "description": "本站源码:Astro SSG + 双写作流,内容即代码", + "language": "Astro", + "stars": 0, + "url": "https://git.wait4x.online/wait4x/blog", + "updatedAt": "" + } +] diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro index b89774e..e6f33ca 100644 --- a/src/layouts/BaseLayout.astro +++ b/src/layouts/BaseLayout.astro @@ -11,6 +11,9 @@ import '../styles/global.css'; import Header from '../components/Header.astro'; import Footer from '../components/Footer.astro'; import ThemeScript from '../components/ThemeScript.astro'; +import Keyboard from '../components/geek/Keyboard.astro'; +import BuildInfo from '../components/geek/BuildInfo.astro'; +import { ClientRouter } from 'astro:transitions'; interface Props { title: string; @@ -32,6 +35,7 @@ const { title, description = 'wait4x 的博客:阅读 · 技术 · 摄影', tr {title} + @@ -39,6 +43,9 @@ const { title, description = 'wait4x 的博客:阅读 · 技术 · 摄影', tr
    -
    +
    + +
    + diff --git a/src/lib/projects.ts b/src/lib/projects.ts new file mode 100644 index 0000000..5897725 --- /dev/null +++ b/src/lib/projects.ts @@ -0,0 +1,86 @@ +// 项目墙数据(极客层 P0):构建时双源拉取 + 仓内缓存兜底 +// 双源 = 自家 gitea(数据自控叙事)+ GitHub(社区 star 真值);置顶清单人工维护 +export interface RepoCard { + source: 'gitea' | 'github'; + name: string; + description: string; + language: string | null; + stars: number; + url: string; + updatedAt: string; +} + +interface RawRepo { + full_name?: string; + name?: string; + description?: string | null; + language?: string | null; + stars_count?: number; + stargazers_count?: number; + html_url?: string; + updated_at?: string; +} + +export const GITEA_API = 'https://git.wait4x.online/api/v1/users/wait4x/repos?limit=50'; +export const GITHUB_API = 'https://api.github.com/users/wait4xx/repos?per_page=100&sort=updated'; + +/** 置顶清单:跨源手选,图钉顺序即展示顺序(name = 仓库短名) */ +export const PINNED: string[] = ['blog']; + +async function fetchJson(url: string): Promise { + const res = await fetch(url, { + headers: { Accept: 'application/json', 'User-Agent': 'wait4x-blog-build' }, + signal: AbortSignal.timeout(10_000), + }); + if (!res.ok) throw new Error(`${url} -> ${res.status}`); + return (await res.json()) as RawRepo[]; +} + +function toCard(r: RawRepo, source: RepoCard['source']): RepoCard | null { + const name = r.name ?? r.full_name?.split('/')[1]; + if (!name || !r.html_url) return null; + return { + source, + name, + description: r.description ?? '', + language: r.language ?? null, + stars: r.stars_count ?? r.stargazers_count ?? 0, + url: r.html_url, + updatedAt: r.updated_at ?? '', + }; +} + +/** + * 拉双源合并去重(同名优先 gitea 自托管叙事,star 取 GitHub 真值)。 + * 任一源失败不抛:置顶项回落仓内缓存 JSON(构建产物绝不被网络单点卡死)。 + */ +export async function loadProjects(): Promise { + const [gitea, github] = await Promise.allSettled([fetchJson(GITEA_API), fetchJson(GITHUB_API)]); + const byName = new Map(); + + for (const r of gitea.status === 'fulfilled' ? gitea.value : []) { + const c = toCard(r, 'gitea'); + if (c) byName.set(c.name, c); + } + for (const r of github.status === 'fulfilled' ? github.value : []) { + const c = toCard(r, 'github'); + if (!c) continue; + const existing = byName.get(c.name); + if (!existing) byName.set(c.name, c); + else if (c.stars > existing.stars) existing.stars = c.stars; // 社区真值覆盖镜像计数 + } + + if (byName.size === 0) { + const fb = (await import('../data/projects-fallback.json')).default as RepoCard[]; + return orderPinned(fb); + } + return orderPinned([...byName.values()]); +} + +function orderPinned(list: RepoCard[]): RepoCard[] { + return [...list].sort((a, b) => { + const pa = PINNED.indexOf(a.name), pb = PINNED.indexOf(b.name); + if (pa !== -1 || pb !== -1) return (pa === -1 ? 99 : pa) - (pb === -1 ? 99 : pb); + return b.stars - a.stars; + }).slice(0, 6); +} From 80ff67e8faef3355d1454dcb1c30baac6a22bf48 Mon Sep 17 00:00:00 2001 From: wait4xx Date: Sat, 24 Oct 2026 23:36:59 +0800 Subject: [PATCH 07/10] =?UTF-8?q?feat(content):=20=E4=B8=89=E9=9B=86?= =?UTF-8?q?=E5=90=88=20schema=20=E4=B8=8E=20EXIF=20=E6=9E=84=E5=BB=BA?= =?UTF-8?q?=E6=9C=9F=E8=A1=A5=E5=85=A8=EF=BC=88T4=20=E8=BD=A6=E9=81=93?= =?UTF-8?q?=E6=94=B6=E7=BC=96=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - src/content.config.ts(Astro 7 唯一合法路径,旧 config.ts 会抛 LegacyContentConfigError——车道实测发现,经批复的边界修正) - posts(category→track 派生单源)/moments(text-image 互斥 refine)/ photos(json sidecar + jpg,exif 构建期 exifr 补全、frontmatter 可覆盖) - 样例:书评+技术文各 1、瞬间 3、照片 3(横竖方三比例,EXIF 三路径覆盖) - 附带 scripts/check-responsive.sh(T9 预置,随 T6 产物生效) - 车道 30min 超时于过度验证循环,产物完好,主会话收编续跑 验证: pnpm astro build exit 0(1.63s,含三集合加载) Spec: 2026-10-24_add-blog-skeleton Co-authored-by: GLM-5.3 --- .../2026-10-24_add-blog-skeleton/tasks.md | 4 +- content/moments/2026-10-02-doctor-issue.md | 5 + .../moments/2026-10-12-ren-shu-zhi-jian.md | 5 + content/moments/2026-10-19-bang-wan-de-yun.md | 6 + content/moments/bang-wan-de-yun.jpg | Bin 0 -> 3217 bytes content/photos/chen-guang-jie-kou.jpg | Bin 0 -> 5640 bytes content/photos/chen-guang-jie-kou.json | 7 + content/photos/xue-xian.jpg | Bin 0 -> 6013 bytes content/photos/xue-xian.json | 6 + content/photos/yu-hou-wu-yan.jpg | Bin 0 -> 4201 bytes content/photos/yu-hou-wu-yan.json | 16 +++ content/posts/cs-ge-lei-pei-zhi.md | 37 ++++++ content/posts/deng-dai-ge-duo.md | 29 +++++ package.json | 1 + pnpm-lock.yaml | 8 ++ scripts/check-responsive.sh | 34 +++++ src/content.config.ts | 94 ++++++++++++++ src/lib/exif.ts | 120 ++++++++++++++++++ 18 files changed, 370 insertions(+), 2 deletions(-) create mode 100644 content/moments/2026-10-02-doctor-issue.md create mode 100644 content/moments/2026-10-12-ren-shu-zhi-jian.md create mode 100644 content/moments/2026-10-19-bang-wan-de-yun.md create mode 100644 content/moments/bang-wan-de-yun.jpg create mode 100644 content/photos/chen-guang-jie-kou.jpg create mode 100644 content/photos/chen-guang-jie-kou.json create mode 100644 content/photos/xue-xian.jpg create mode 100644 content/photos/xue-xian.json create mode 100644 content/photos/yu-hou-wu-yan.jpg create mode 100644 content/photos/yu-hou-wu-yan.json create mode 100644 content/posts/cs-ge-lei-pei-zhi.md create mode 100644 content/posts/deng-dai-ge-duo.md create mode 100644 scripts/check-responsive.sh create mode 100644 src/content.config.ts create mode 100644 src/lib/exif.ts diff --git a/.spec/specs/2026-10-24_add-blog-skeleton/tasks.md b/.spec/specs/2026-10-24_add-blog-skeleton/tasks.md index 5019867..17348ef 100644 --- a/.spec/specs/2026-10-24_add-blog-skeleton/tasks.md +++ b/.spec/specs/2026-10-24_add-blog-skeleton/tasks.md @@ -23,10 +23,10 @@ - boundary: 只加字体 npm 依赖与 src/styles/fonts.css 引入;不引入 cn-font-split 构建步(预分片包方案,证伪则回退并记 2.5) - verify: `pnpm astro build && test $(find dist -name "*.woff2" | wc -l) -gt 50` -- [ ] T4 内容集合与 EXIF loader(posts/moments/photos) +- [x] T4 内容集合与 EXIF loader(posts/moments/photos) - depends-on: task_0001 - claim: lane-content(子代理,预留 src/content 与 src/lib) - - boundary: 只写 src/content/config.ts、src/lib/{exif.ts,collections 辅助}、content/ 样例(书评/技术/瞬间各 1+、照片 3 张占位图含两种比例);EXIF 空值容错 + - boundary: 只写 src/content.config.ts(2026-10-24 修正:Astro 7 已移除 src/content/config.ts 旧路径,唯一合法位置为 src/ 直下,经 supervisor 批复)、src/lib/{exif.ts,collections 辅助}、content/ 样例(书评/技术/瞬间各 1+、照片 3 张占位图含两种比例);EXIF 空值容错 - verify: `pnpm astro build` - [ ] T5 布局/导航/页脚/明暗不闪烁 diff --git a/content/moments/2026-10-02-doctor-issue.md b/content/moments/2026-10-02-doctor-issue.md new file mode 100644 index 0000000..cb67573 --- /dev/null +++ b/content/moments/2026-10-02-doctor-issue.md @@ -0,0 +1,5 @@ +--- +pubDate: 2026-10-02 +tags: [开源] +text: 给上游提的 doctor 误报 issue 当天被采纳,第三天随新版本发布——开源最好的正反馈。 +--- diff --git a/content/moments/2026-10-12-ren-shu-zhi-jian.md b/content/moments/2026-10-12-ren-shu-zhi-jian.md new file mode 100644 index 0000000..d222057 --- /dev/null +++ b/content/moments/2026-10-12-ren-shu-zhi-jian.md @@ -0,0 +1,5 @@ +--- +pubDate: 2026-10-12 +tags: [阅读, 一句话书评] +text: 《人鼠之间》——梦越简单,碎的时候越响。 +--- diff --git a/content/moments/2026-10-19-bang-wan-de-yun.md b/content/moments/2026-10-19-bang-wan-de-yun.md new file mode 100644 index 0000000..363c40b --- /dev/null +++ b/content/moments/2026-10-19-bang-wan-de-yun.md @@ -0,0 +1,6 @@ +--- +pubDate: 2026-10-19 +tags: [随手拍, 手机] +text: 傍晚的云压得很低,路灯提前亮了。 +image: ./bang-wan-de-yun.jpg +--- diff --git a/content/moments/bang-wan-de-yun.jpg b/content/moments/bang-wan-de-yun.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a4255641e52f43d2a429596648134e3cd65b8df3 GIT binary patch literal 3217 zcmb_eQE$^$6iz5Y&0feP2^!yp+zGTYFX1+$u>2K3R-%j?SWO= zBS;pI&g`jq+44YHM;hWOZn3w=644-48xmDpIq3^8laL0#q5IBtI|^fhAyTQ*wSDhB z=R4o`owMey-S_P{+4oVO&+qs7{P^>&t@@7nS^|OQz}A-L=H}LxmR6x%5Zc-V@r@m? zx9=9E-MhqHJ3IFt+}HWmfwy+<+W+p`2fD+`Aw}Bv-jT!dk%O`#(;@zr)>dJg5E6ut zyl2-Q`G5b`=6u0c|A+qjP5ynpEkS=%(7$%u_a;K6U?2bdzAY_yA?|qUIkE}j`EL52 zew%g#nzlC6o{r$Ar{4RuhVQi|92sm1`abae6%AE>{qw7zqJkjA@GrD|K08qy62*nN zGGp1nhfJ2Y*W-yuKP`_{tcrEITCFXG&yJ=uiZL})3DeGmln@43R+%`T2q&Zgc~FUA zquhp_M>bB}n-8Zm)5$NH+2ai5_d2R0PP&>FpH4&)Qoy?D3|-YUt#KuXw+r<<)Mt;l{_4$#kYmH*+~P zzc5cR4#;fiR!_CM6duW_rK_XK;k+n{lUl0p=WrNs@s;trX-YDHX@4c6u_M z9v)LwvGm{v+{fy_ilXQzYynr!*%LGnI)P)%n^aQDwGsgF29-!UhK*^mjBZ5r#9a8_QW3%e5C& z5HBgrloyB0tt`Vm>EdbE)#4X%djUSIsx1f&wn?nMyHZ=?EIWFrwpdRbo-=`PG2bng zsB{5VmIost&qgn}rcs*mxcOXP@%%2a2^3CIa+i(`&qeWxM$l3DG`MI33ql zsj6BUQ=!IHZZF_1-&%s}YN1)12Sb`or&EPXZd?Zt%86bV#UY6F+{Ki`Ik+Pcvh2Zi zd)FRcKLzIoZx{LXuxf*N3q(D$y^eD;djRDHa`~s2LcME%$j6y7iHsW5dO+plNBz=D|kU!D?TC?WOk zO`ZZfna%a4_V*x$DHNBaXg*j^+ejK{eVjp zuTA!>5UHOeO5r7mB1lk_XZOpPSgLbo0a^h>V1gtCPu*se3e`B02#G7z>Ma?;V%}lO zF&aP+2Fsr41p&oTVv0saUn+oY7&pj)sqN%d2jd227!*q>U^3wI0LK@UL9ud3jHpNB z3cp|UrV&yBoQ+I9A_eVF1OYUM)qp@cH^ewKGk1^YNN{ahT}L-D!RtmMeCD^1@p1xs zCAg4{TPN#0@ka#HDr7)iWOEC8E?o#j0Or{mx*9bZULwGtX-NK3V;XITCQQPshr18D zIAd%(wbLk`_m}%H90ESCAgHe@(A*HaHztbWAKxyl&vE~{zZ{HvTfAJKB_@(7mbZYt3%4s?~7au1owm%@gkFT$_f4BYl{qB#cpwFj7?-lg> z9Q^--_pR-F{_y)_`uq=Y{!jW|5?|pj&qK@~o`3b^;bSKczv>-6aq`Ig$)iVcnx5xt zXP4)XzWL_zkynm+O>gD2_wy!g{+)hCW2RX&jj>{}SQ;BEm8<2lWtAtMv-ehCnArcq zzKMO42RwiJz)J^Tn%wvD;U66g4$ZwXw|{#6_>tM;{_NZ=zeJ3cO6BpgTQ0k^FYbGB z_W%Cb{DdkcdA9IwK}?gZh(bkd-l9oVA3wZ=tsha8W4PklJ5S?s1*e~X=zbD~A}%A zW)x)`3#nAXm#$Emh!WGh`01gEFfl{nrzO)!Rp=)!Sv*{`6Z)Q0ZKuiAMP=a@{%!cw z<1tHR<-0QTc(4q!xU@)_H&-{$U5agrwnnfzq0vuzPNa;!9AMtor7&~rzOo~$t>S7j z6^3bS`3d!k|1r+reujmphvB)lYS6`7A07;`>`Qg(Q%tugV)UyDuh&r^8aLtE9U?c%xObX>XS!+&!*P<25wGtw1`FvNj%sqhR=I4WzGk%}7>F3vk1dHolaCGe0st)WIG%H|)WublHM4p+ z7`ye@N~H3!G+#O*A8nY`WLp5c4oZk_`#d-FwG+nNXQ32YiM5!~^l*^F)l-JJnY}!5 z=;`8us$EP|rh%^DMpy?ZblZfyr2IZHLn(3UvBnZtojivw{-tyN^QQz0u3i_tkfUE0#L$}yhmbH9BM61C*q$_hO%;k6Xc(jf76SsW zNyUc4rigBbFc%P?4M%erO%D5Alpcdp!)$J_g0Th?#F{ap@!;*O64rbuLEM0n( zCaFn~A!j z!4jZ8qT+z7&8tddf(z!HEosMYwdyd!k#(fIYQ!in3^(8$3dE>s-Ri(Lf=?41VMcVb=McpXB%Z2;h3j$5}*#sEsL-6;bVeb;B_WmgY0w}R`m(yNk;m}?KB)}yZ>~ycQymBd5y{i#o52_NoAuH`pK%8USMU^Z{ zOgQ#8Llv@wuhnq1wJ?&1h`k4h!u<|Aw}V$KrqD?3G@PbbLs2W6hj9RX)h*`y$d-x%C*$?H-*a(*0gBxgz2cw~`t7SAo45C$?&S6OK|J8; z9Z}+1{fY5_L|X$Q5Lz%pFg#?RLxbVBI>B%NS)9E7fMuYN`fiYYd`S+z+cIQs84GL3 z5l|K8Jl5HROnDpJ;+|7otv6S5w`DBEq-{fXgLRHC$Q}Za6*q%DXFEDYFyA?{ZP7vp za}SY@jb^t*g;)~XuD>4pkQHgNhM}8yL2em$D+{~A0g(W1ixCjwA+y=nM4rTmICY%by@v& zj)KpcjPoV9&9+$(+*0Q(mOQtmV@roOgc?x!&f+6BTY0y#)TjGXjm!2fBAE{}qB`RC z8b>$8XQBF6RfcLxm@`4Pc<y zs;GA~$dBt>He_N%Q6`e)qxPYJ(*dzDMBiA|6Ewd~txtWwn!@mDifW=0z!lsO6 z;nB)~eYnS7KnTQa9=zk^1g&|?d1K#^9fA7$YQshtU<=4`5;_ZKaIN;WT(ekPb*_L0 zas*b@gujw8^URBx$rQWle-#c+Q(qB7K#e1ffu>@;wMWlf`K)D!45-hv@~k0~sn4q7$=88YaHn}7Wu*#iNC literal 0 HcmV?d00001 diff --git a/content/photos/chen-guang-jie-kou.json b/content/photos/chen-guang-jie-kou.json new file mode 100644 index 0000000..c2cb027 --- /dev/null +++ b/content/photos/chen-guang-jie-kou.json @@ -0,0 +1,7 @@ +{ + "title": "晨光街口", + "image": "./chen-guang-jie-kou.jpg", + "group": "street", + "alt": "晨光斜切进街口,行人拖着长影子过马路", + "exif": {} +} diff --git a/content/photos/xue-xian.jpg b/content/photos/xue-xian.jpg new file mode 100644 index 0000000000000000000000000000000000000000..93c497e7fcf6efee3cab206e3f9759fd730d4281 GIT binary patch literal 6013 zcmcIoO>f-R6}^u$9C0Wsr4-VQl#g;;NuU|KXl2EVZ2CAc(~)We9GP@$pxp$5p|)Q7 z2T)^8V9aVF#|4sXsDWb8tP!BjALybB2dDwtiy&z?UDo*%>bZ|Imd3UmCrGS?EDnc! z@4R!)J@@W?wfA4LR^MHDmxLe^_@TZ3&^t7t>ovVPQLELAi3wwJW^&RrCy)NbnwptA z`s&>5(b-pCbG>7)y|MVlE3-fU<@}=m=E+~2eD&DUTfaK-mUrUh34Vx}FpSCiq%%3` zoOpfq^%LLu-`+oH+Nf-4zpsd6q)m&;wAlM6{S-^(#qR$Tq)p%h#~Qzk8`S-L``G;? zDmC11Pmf>4{d@nWBNaSux-w0_rvH8De)ETKYQ3z;e1obHJ&+Y?8f`t)Lm69DE9(q8 z>knkRCBjBL?=_SC)A;z4GP^*e^w$s9*StEt&D66yPt=bB-5 z26EFX1HAXGX8`vhV&e0u1GdGiJiF^CE zZk~I&w3g|Xdu6k={x84@EUB{-1|$YON9sV&qNDgea7e-xX=Dy|sja7cZWjwT*N1mn z5-k z&XMq4Ee_k#_~WleqPZb&7+M>t;LRAV~%3pRX_h- zYo~U$k3D-iNYifSI7AJ1-&K3=<+nUxYdHELQelL}88l@_1>-xwG12)$k-~HIdi>G{ zVQ_t+X#!&?V+bc9j9}wd@8RCvTUkWF%HX*=EH1#rGCl zWE8Z)C(Im89BR2&(v9`IQS%y8M$1yS3rJpGgopsOx#K^fzFuk?3NsNg(bQT@A57K? zgN#fJ(gClf4Yh5EwQ`&O?S~Zi-Avge@G3`cPplYA>pvz`FoSNj z3$tIFU80ok07f?-6#goO#8N9Q{Xwi1Pgr_FH&e&;`FwG>$_uQb%O?&OCd;dR&IaM5 zt^{EyEji;p*9nu&e@~)~F3vBC8l#I^HqJ>f5CG=^R&WMl^wA0fyLtt0yRzSz2c}sxW(R zcj-Ov#egb{bMjq)0;GvZg37M`4i0`hot8eT8hn)NOF~5&TQukGJSGs`?CLF(^+G5* z94@N<4yThGaieOA+xOXEaz`B{M+=6u-j-lu^`&jc`D6i1LrQ?q?y}1>x1UG}`$oml z=PC7VDWifmX`>LFm1ek{DV7C|=5(aGA^WsjSvI8r9T7WXt|k7Qb7|SxL5jD7gx4{ z4%;Pi5QFX|Bl^(sonQ?~2PZwuSD+79LLs&XmqP zg2ahC>#Sant(XBQtDz)G-L@W?2K*ZDD1%)utEGrKKAz>M+&pyifNK-2a@lwJl1c)K zD`}$Wdwt>i5(>d$Xi@ywF+y?9L{Nf5>&W!<;NlWJ!_6b@V|(1qoijjl-_3i(uB80pEBtZK(4n~4jz_6YBsN@(WQJpfcZ;YG$9C8rg;E;K2Nj%ajaBVT zw4CVP_P05?e+^9vjA-cOHX$n(C<=C26#)Tf%$u8Gna_p3*6ENcOGucv8h>>C*}spR zJZh#^3Tufol{xVQW)Fo?MZJQ%9mY+iBoDTr0`mg%&T95lBvwmrGw@RIQlOgH`fS@d z@>PL!T6!VatC|O&wzvKxvxmj?J#OaV^Hs=v{$s9G=dQ_4|XP2FqX4w^M z=BLU}j2IyR!8e+8xu5a+@{w)b>sMXPwi3^CQTO4^crbe4$Bmw^6&7C0(}EsC3)nbH z1=b)_ZRe0DX0MMZsG9g;lJ^>|XnymdmoKp=?&xJEN8^v?9BX?a3-271Tp1xbL^?|> zNUMo%-@$2g!}Yu06D1ZuD+8nh1e$8$RC_Q&2~J+H@Aj?RAN>$ys`E@hby6jnjHubq z)Ocng`s{<|k*~7c;h{(-GH#>c5RbcI9=?>50uL1iy=|F`^a#~VQ>D!``(@ZMRD$#| z-+|h?Z8TdrLkGzuY@J#^JU9)?amrZ2v{rk_*-!b>-V5s@qFOt8)BpKncycGV}XX)DEa=`YI)IW=TpYf=Lz4ByK6mkMCH9<8cVzhP)Kbge+$(U2|OS(wG2yJz*dP7U4&C8lmIbG43$8H|J^o$b&Uo-Nc{bbH24`{cP{+{{#7D=YIeI literal 0 HcmV?d00001 diff --git a/content/photos/xue-xian.json b/content/photos/xue-xian.json new file mode 100644 index 0000000..c8a6b10 --- /dev/null +++ b/content/photos/xue-xian.json @@ -0,0 +1,6 @@ +{ + "title": "雪线", + "image": "./xue-xian.jpg", + "group": "landscape", + "alt": "山脊上的积雪线在蓝天下格外清晰" +} diff --git a/content/photos/yu-hou-wu-yan.jpg b/content/photos/yu-hou-wu-yan.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d924dc523954fee775fb4734eda795bf8a967336 GIT binary patch literal 4201 zcmb_eO>fjl5bgHZp2oun8%;uH0+HoKXhbGxLCJaTC5Z&5AR#2~9QYa5>>i@r_8*Km z!zI6f0|$;dvdd-v0KZ{))m?43lgYp^&WDn+yQg2jdiAR2U*`Xd`1$d(VhD{z=>cR08XK z$!>@jgShz=3-EM{RyWs6&ktyQa&`TG;$}zUtWF~S5Z_LA{`$KRx%5T+LijQM^?L{#2x;7o}n7OtKP4V;kO~`A@619^C|Y`o z-!rA&DUPubpVOD}H9!RQNx;jf=vZL`$?$ohG>8xJ^vL&L_#ES^`Uc^2x|^o&%*h6# zMMcLd8!&teiLX}Tdb9Ejx2vwIFY9%3|7FWa4Y%H`MNakQkdBL!Bcz%r1S$BBI5K>4 zVBe8CY6ZktK8TY;trpq}wK!YlZ1zx5vcU~8362ryY?{>aJ8nydF&&*wK3zf*Fq;qktHf~=(AM+h7VgXhT9fYBum?Z>!vKfb)XW#`|;76CQOpWYE>nz^mXgitzr~;=T+i~ zArSmiuIg4*-KI6ckWuGP)L`i$1X4`-DHwrc%~WD6-# zNVei>oscgKLGF^NYKd355Vez4<~@qU=jBt?%18lRU~YVKY5KQBF>g*+T~Pnpto86? z%-0wqgsUo7sQJ;pN#Sgf{j&>@K#_Hx7!cTgs4zByAAJsuwpT|gx1}!6J-x+8QJ({` zQ(YDHp*p1q>oLWGa-7Pf+$sS1X9dvxXdW*tk9-bK<942M`l-R;T#4G4X)L5(6A<9A z1SVU=z{i6)4}JuwIcDkiR}~6`SZb~Uem?~Mur3TbnCfI5oYacLQa!nhXAM4au?UFa W1>qqV@*4VNPY^K;;^?{af4>87`s 希望迟迟不来,苦死了等的人。 + +——萨缪尔·贝克特《等待戈多》 + +就戏剧动作而言,《等待戈多》几乎什么都没有发生,而这正是它最残忍的地方:它不安排绝望的事件,只安排绝望的节奏。对话膨胀又塌缩,约定立起又被推翻,戏在「咱们走吧」与「他们不动」之间原地打转。等待本身成了全部的情节,也成了全部的刑罚。 + +> 爱斯特拉冈:咱们走吧。 +> +> 弗拉季米尔:咱们不能。 +> +> 爱斯特拉冈:为什么不能? +> +> 弗拉季米尔:咱们在等待戈多。 + +可我并不觉得这是全然的黑暗。两个流浪汉在无望之待里,仍然留住了几样东西:他们拌嘴,也互相系鞋带;他们想上吊,又舍不得用裤腰带;他们每天遇见,每天确认「你又来了」。无望之待没有被拔高成救赎,但陪伴让囚笼有了呼吸的缝隙——自我救赎未必是走出困境,有时只是在困境里替对方把靴子脱下来。 + +合上书那天傍晚,我在站台等一班迟迟不来的车,忽然想起幸运儿的思想独白:原来我们都站在各自的乡间小路上,书包里装着胡萝卜,等一个不会来的戈多。贝克特没有给我们答案,只留下一句温柔的嘲讽——他们许诺明天一切都会好起来。信不信,由等的人自己决定。 diff --git a/package.json b/package.json index 705bd0f..9c4efd9 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "@fontsource/jetbrains-mono": "^5.3.0", "@fontsource/noto-sans-sc": "^5.3.1", "astro": "^7.3.8", + "exifr": "^7.1.3", "lxgw-wenkai-screen-webfont": "^1.7.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 064927b..19b4c18 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,9 @@ importers: astro: specifier: ^7.3.8 version: 7.3.8(yaml@2.9.1) + exifr: + specifier: ^7.1.3 + version: 7.1.3 lxgw-wenkai-screen-webfont: specifier: ^1.7.0 version: 1.7.0 @@ -686,6 +689,9 @@ packages: eventemitter3@5.0.4: resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} + exifr@7.1.3: + resolution: {integrity: sha512-g/aje2noHivrRSLbAUtBPWFbxKdKhgj/xr1vATDdUXPOFYJlQ62Ft0oy+72V6XLIpDJfHs6gXLbBLAolqOXYRw==} + extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} @@ -1863,6 +1869,8 @@ snapshots: eventemitter3@5.0.4: {} + exifr@7.1.3: {} + extend@3.0.2: {} fast-string-truncated-width@3.0.3: {} diff --git a/scripts/check-responsive.sh b/scripts/check-responsive.sh new file mode 100644 index 0000000..12ade6c --- /dev/null +++ b/scripts/check-responsive.sh @@ -0,0 +1,34 @@ +#!/bin/sh +# 响应式结构自查(§4e):四档断点 + 触屏 44px + 安全区 + dvh 的静态断言 +# 依据:docs/博客重设计调研报告.md §4e;断点 1120/820/760/560 +set -e +cd "$(dirname "$0")/.." +fail=0 +check() { if eval "$2"; then echo " ok $1"; else echo " FAIL $1"; fail=1; fi } + +CSS_SRC="src/styles/global.css src/components/*.astro src/layouts/*.astro" + +check "断点 1120px(宽屏 TOC 常驻档)" \ + "grep -rqE 'max-width: ?1120px|min-width: ?1120px|@container' \$CSS_SRC src/pages/*.astro 2>/dev/null" +check "断点 820px(笔电 TOC 收起档)" \ + "grep -rqE 'max-width: ?820px|min-width: ?820px' \$CSS_SRC src/pages/*.astro 2>/dev/null" +check "断点 760px(平板竖屏档)" \ + "grep -rqE 'max-width: ?760px|min-width: ?760px' \$CSS_SRC src/pages/*.astro 2>/dev/null" +check "断点 560px(手机档 + 正文降 18px)" \ + "grep -rq 'max-width: 560px' src/styles/global.css" +check "移动端降档:--prose-size 到 18px" \ + "grep -q 'prose-size-reading: 18px' src/styles/global.css" +check "触屏 44px 目标类(.tap)存在且被使用" \ + "grep -rq 'class=\"tap' src/components src/layouts" +check "安全区 env(safe-area-inset-*) 使用" \ + "grep -rq 'safe-area-inset' src/styles src/components src/layouts" +check "视口 viewport-fit=cover(刘海屏)" \ + "grep -q 'viewport-fit=cover' src/layouts/BaseLayout.astro" +check "100dvh 或未使用视口高度陷阱(出现 100vh 即 FAIL)" \ + "! grep -rn '100vh' src/ ; true" +check "动效总闸 prefers-reduced-motion" \ + "grep -q 'prefers-reduced-motion: reduce' src/styles/global.css" +check "构建产物含 viewport-fit 与主题色 meta" \ + "grep -q 'viewport-fit=cover' dist/index.html && grep -q 'theme-color' dist/index.html" + +[ "$fail" = "0" ] && echo "responsive check: all ok" || { echo "responsive check: FAILURES above"; exit 1; } diff --git a/src/content.config.ts b/src/content.config.ts new file mode 100644 index 0000000..1fd7f97 --- /dev/null +++ b/src/content.config.ts @@ -0,0 +1,94 @@ +import { defineCollection, z } from 'astro:content'; +import { glob } from 'astro/loaders'; +import { photosWithExifLoader, type PhotoExif } from './lib/exif'; + +/** + * posts 的 track(首页分轨标签)由 category 派生,不接受 frontmatter 直写, + * 单一事实源在此映射,消费端用 trackOf(entry.data.category)。 + */ +export const POST_TRACKS = { + reading: '阅读', + tech: '技术', + photo: '照片', +} as const; + +export type PostCategory = keyof typeof POST_TRACKS; +export type PostTrack = (typeof POST_TRACKS)[PostCategory]; + +export function trackOf(category: PostCategory): PostTrack { + return POST_TRACKS[category]; +} + +const postsSchema = z.object({ + title: z.string(), + pubDate: z.coerce.date(), + category: z.enum(['reading', 'tech', 'photo']), + tags: z.array(z.string()), + /** 情绪色,仅书评轨使用;#RRGGBB */ + mood: z.string().regex(/^#[0-9a-fA-F]{6}$/).optional(), + draft: z.boolean().optional(), +}); + +// 与 src/lib/exif.ts 的 PhotoExif 对齐;loader 已保证构建期补全,frontmatter 只需部分覆盖 +const photoExifSchema = z.object({ + make: z.string().optional(), + model: z.string().optional(), + lens: z.string().optional(), + fNumber: z.number().optional(), + exposureTime: z.number().optional(), + iso: z.number().optional(), + focalLength: z.number().optional(), + dateTimeOriginal: z.string().optional(), +}); + +const photosFields = { + title: z.string(), + group: z.enum(['street', 'landscape']), + alt: z.string().optional(), + exif: photoExifSchema.optional(), +}; + +// 编译期双向断言:photoExifSchema 与 PhotoExif 漂移时在此报错,防止两处形状各自演化 +type _PhotoExifOut = z.infer; +const _exifShapeOk: _PhotoExifOut extends PhotoExif + ? PhotoExif extends _PhotoExifOut + ? true + : never + : never = true; + +export const collections = { + // slug 即文件名(glob loader 默认按文件名生成 id) + posts: defineCollection({ + loader: glob({ pattern: '**/*.md', base: './content/posts' }), + schema: postsSchema, + }), + // image 字段必须走函数式 schema 的 image() helper:zod/v4 的 z 上没有 .image(), + // 相对路径由 Astro 传入的 helper 按 entry 文件位置解析 + moments: defineCollection({ + loader: glob({ pattern: '**/*.md', base: './content/moments' }), + schema: ({ image }) => + z + .object({ + pubDate: z.coerce.date(), + tags: z.array(z.string()), + text: z.string().optional(), + image: image().optional(), + }) + // 瞬间的存在性约束:一句话、一张图至少有其一 + .refine((moment) => moment.text !== undefined || moment.image !== undefined, { + message: 'text 与 image 至少提供一项', + }), + }), + // photos 的 exif 字段在加载期由 exif 车道补全,schema 只声明形状 + photos: defineCollection({ + loader: photosWithExifLoader(), + schema: ({ image }) => + z.object({ + ...photosFields, + /** 相对本条 JSON 文件的图片路径 */ + image: image(), + }), + }), +}; + +export type PostData = z.infer; diff --git a/src/lib/exif.ts b/src/lib/exif.ts new file mode 100644 index 0000000..a3a107e --- /dev/null +++ b/src/lib/exif.ts @@ -0,0 +1,120 @@ +import { readFile } from 'node:fs/promises'; +import { dirname, join } from 'node:path'; +import { fileURLToPath, pathToFileURL } from 'node:url'; +import { glob } from 'astro/loaders'; +import type { Loader } from 'astro/loaders'; +// exifr 的 Node 出口是 UMD/CJS(package.json 无 exports,main 指向 full.umd.js), +// 其上没有 `exifr` 命名导出,具名导入在裸 Node(cjs-module-lexer 不识别 UMD 包装)下会炸; +// default 导入在 Vite SSR interop 与裸 Node 两种语境都拿到同一 namespace 对象。 +import exifr from 'exifr'; + +/** + * 照片 EXIF 的统一形状,photos 集合的 `exif` 字段与灯箱/卡片展示都消费它。 + * 单位约定:exposureTime 为秒(1/500s → 0.002)、focalLength 为毫米、 + * dateTimeOriginal 为 ISO 8601 字符串;任何字段缺失即为 undefined(空值容错)。 + */ +export interface PhotoExif { + make?: string; + model?: string; + lens?: string; + fNumber?: number; + exposureTime?: number; + iso?: number; + focalLength?: number; + dateTimeOriginal?: string; +} + +/** exifr.parse 对无 EXIF 的图返回 undefined;有 EXIF 时字段也可能残缺,故值全部按 unknown 取 */ +type ExifRaw = Record | undefined; + +function firstString(raw: ExifRaw, keys: string[]): string | undefined { + for (const key of keys) { + const value = raw?.[key]; + if (typeof value === 'string' && value.length > 0) return value; + } + return undefined; +} + +function firstNumber(raw: ExifRaw, keys: string[]): number | undefined { + for (const key of keys) { + const value = raw?.[key]; + if (typeof value === 'number' && Number.isFinite(value)) return value; + } + return undefined; +} + +/** exifr 原始 tag 输出 → PhotoExif;大小写两种键名都兼容(translateKeys 行为随版本/配置浮动) */ +export function mapExifTags(raw: ExifRaw): PhotoExif { + const dto = raw?.DateTimeOriginal ?? raw?.dateTimeOriginal; + return { + make: firstString(raw, ['Make', 'make']), + model: firstString(raw, ['Model', 'model']), + lens: firstString(raw, ['LensModel', 'lensModel']), + fNumber: firstNumber(raw, ['FNumber', 'fNumber']), + exposureTime: firstNumber(raw, ['ExposureTime', 'exposureTime']), + iso: firstNumber(raw, ['ISO', 'iso']), + focalLength: firstNumber(raw, ['FocalLength', 'focalLength']), + dateTimeOriginal: + dto instanceof Date ? dto.toISOString() : typeof dto === 'string' ? dto : undefined, + }; +} + +/** + * 从图片文件提取 EXIF(接受文件路径 / URL / 字节)。 + * 无 EXIF、损坏文件、读取失败一律返回空对象——单张图的意外不许炸掉整次构建。 + * 坑:exifr 的 Input 白名单不含 URL 对象(抛 Invalid input argument), + * 必须先归一成文件路径字符串。 + */ +export async function extractPhotoExif(input: string | URL | Uint8Array): Promise { + try { + const source = input instanceof URL ? fileURLToPath(input) : input; + return mapExifTags(await exifr.parse(source, { tiff: true, exif: true })); + } catch { + return {}; + } +} + +/** + * 构建期补全的覆盖语义:frontmatter 写过的字段优先,缺口由图片 EXIF 填补。 + * overrides 为 undefined / 空对象时等于纯提取。 + */ +export async function resolvePhotoExif( + overrides: Partial | undefined, + imageInput: string | URL | Uint8Array, +): Promise { + return { ...(await extractPhotoExif(imageInput)), ...overrides }; +} + +/** + * photos 集合加载器 = glob(JSON) + EXIF 构建期补全。 + * entry.data.image 经 z.image() 校验后已是 ImageMetadata(不含源文件路径), + * 因此从 JSON 原文重读 `image` 字符串,按“相对 JSON 文件”定位源图交给 exifr。 + * + * 坑:dev 模式下单文件变更由内层 glob loader 的 watcher 增量处理,会绕过本包装层, + * 改图或改 JSON 后需重启 dev server 才能补全 EXIF;SSG 构建每次全量 sync,无此问题。 + */ +export function photosWithExifLoader(base = './content/photos'): Loader { + const baseLoader = glob({ pattern: '**/*.json', base }); + return { + name: 'photos-with-exif', + load: async (ctx) => { + await baseLoader.load(ctx); + const root = fileURLToPath(ctx.config.root); + await Promise.all( + ctx.store.keys().map(async (id) => { + const entry = ctx.store.get(id); + if (!entry?.filePath) return; + const jsonPath = join(root, entry.filePath); + const raw = JSON.parse(await readFile(jsonPath, 'utf8')) as { + image?: string; + exif?: Partial; + }; + if (typeof raw.image !== 'string') return; + const imagePath = new URL(raw.image, pathToFileURL(dirname(jsonPath) + '/')); + const exif = await resolvePhotoExif(raw.exif, imagePath); + ctx.store.set({ ...entry, data: { ...entry.data, exif } }); + }), + ); + }, + }; +} From 945a9ee610471151c228bf5b269544d65e9e4493 Mon Sep 17 00:00:00 2001 From: wait4xx Date: Sun, 25 Oct 2026 00:11:34 +0800 Subject: [PATCH 08/10] =?UTF-8?q?feat(pages):=20=E4=BA=94=E9=A1=B5?= =?UTF-8?q?=E5=9E=8B=E8=90=BD=E5=9C=B0=E2=80=94=E2=80=94=E9=A6=96=E9=A1=B5?= =?UTF-8?q?/=E6=96=87=E7=AB=A0=E5=8F=8C=E6=A8=A1=E6=9D=BF/=E5=9B=BE?= =?UTF-8?q?=E5=BA=93=20masonry/=E7=9E=AC=E9=97=B4/=E5=85=B3=E4=BA=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 首页:名片+身份陈述空槽+按年分组分轨列表(情绪色/mono标签)+影像格+项目墙 - 文章 /archives/{slug}(与 Halo 旧 URL 1:1):reading→衬线纸墨 / tech→ TOC 侧栏(≥1120 sticky)+2px 进度条+Artalk 容器占位 - 图库:grid masonry(构建期 aspect-ratio 零 JS)+原生 dialog lightbox (←→/Esc+EXIF 底栏)+分组筛选 - 瞬间时间线 / 关于(三轨版图+构建说明) - sharp ^0.35.5 入依赖(Astro 7 不内置,astro:assets 缩略图管线前提) - 裸 blockquote 默认吃 A 墨线样式(markdown 原生输出无类名的缝隙) - 车道 30min 超时,产物完整,主会话补 sharp+断言脚本递归修正后收编 验证: pnpm astro build exit 0(7 页);五路由产物断言过; scripts/check-responsive.sh 11/11 ok(1120/820/760/560 全档) Spec: 2026-10-24_add-blog-skeleton Co-authored-by: GLM-5.3 --- .../2026-10-24_add-blog-skeleton/tasks.md | 6 +- package.json | 3 +- pnpm-lock.yaml | 10 +- scripts/check-responsive.sh | 13 +- src/components/Avatar.astro | 42 +++ src/components/IdCard.astro | 27 ++ src/components/PostList.astro | 137 +++++++ src/pages/about.astro | 118 ++++++ src/pages/archives/[...slug].astro | 270 +++++++++++++ src/pages/archives/index.astro | 31 ++ src/pages/gallery/index.astro | 357 ++++++++++++++++++ src/pages/index.astro | 139 ++++++- src/pages/moments/index.astro | 142 +++++++ src/styles/global.css | 4 +- 14 files changed, 1281 insertions(+), 18 deletions(-) create mode 100644 src/components/Avatar.astro create mode 100644 src/components/IdCard.astro create mode 100644 src/components/PostList.astro create mode 100644 src/pages/about.astro create mode 100644 src/pages/archives/[...slug].astro create mode 100644 src/pages/archives/index.astro create mode 100644 src/pages/gallery/index.astro create mode 100644 src/pages/moments/index.astro diff --git a/.spec/specs/2026-10-24_add-blog-skeleton/tasks.md b/.spec/specs/2026-10-24_add-blog-skeleton/tasks.md index 17348ef..f0fd69c 100644 --- a/.spec/specs/2026-10-24_add-blog-skeleton/tasks.md +++ b/.spec/specs/2026-10-24_add-blog-skeleton/tasks.md @@ -35,10 +35,10 @@ - boundary: 只写 src/layouts/BaseLayout.astro 与 src/components/{Header,Footer,ThemeScript}.astro;导航 ≤4 项;页脚 ICP+built-from 槽位;inline 防闪烁脚本 - verify: `pnpm astro build && grep -q "陕ICP备2026014860号" dist/index.html` -- [ ] T6 五页型(首页/文章双模板/图库/瞬间/关于) +- [x] T6 五页型(首页/文章双模板/图库/瞬间/关于) - depends-on: task_0004, task_0005 - - claim: lane-pages(子代理,预留 src/components 与 src/pages 除 index 外路由) - - boundary: 只写页面与页面级组件(名片开场/分轨列表/书评衬线模板+引文组件/技术模板+TOC+进度条/图库 masonry+lightbox/瞬间时间线/关于含身份陈述空槽位);排版参数按报告 §3 + - claim: lane-pages(子代理)→ 超时由主会话收编 + - boundary: 只写页面与页面级组件(名片开场/分轨列表/书评衬线模板+引文组件/技术模板+TOC+进度条/图库 masonry+lightbox/瞬间时间线/关于含身份陈述空槽位);排版参数按报告 §3。豁免注记:sharp ^0.35.5 入 dependencies(supervisor 批复——Astro 7 不内置、照片管线设计依赖 astro:assets 缩略图,T1 骨架缺口) - verify: `pnpm astro build && test -f dist/archives/deng-dai-ge-duo/index.html -a -f dist/gallery/index.html -a -f dist/moments/index.html -a -f dist/about/index.html` - [ ] T7 极客层 P0(键盘+帮助/build-info/View Transitions/项目墙) diff --git a/package.json b/package.json index 9c4efd9..c3c1954 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "@fontsource/noto-sans-sc": "^5.3.1", "astro": "^7.3.8", "exifr": "^7.1.3", - "lxgw-wenkai-screen-webfont": "^1.7.0" + "lxgw-wenkai-screen-webfont": "^1.7.0", + "sharp": "^0.35.5" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 19b4c18..aa10da9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,6 +23,9 @@ importers: lxgw-wenkai-screen-webfont: specifier: ^1.7.0 version: 1.7.0 + sharp: + specifier: ^0.35.5 + version: 0.35.5 packages: @@ -1428,8 +1431,7 @@ snapshots: '@fontsource/noto-sans-sc@5.3.1': {} - '@img/colour@1.1.0': - optional: true + '@img/colour@1.1.0': {} '@img/sharp-darwin-arm64@0.35.5': optionalDependencies: @@ -2181,8 +2183,7 @@ snapshots: sax@1.6.1: {} - semver@7.8.5: - optional: true + semver@7.8.5: {} sharp@0.35.5: dependencies: @@ -2215,7 +2216,6 @@ snapshots: '@img/sharp-win32-arm64': 0.35.5 '@img/sharp-win32-ia32': 0.35.5 '@img/sharp-win32-x64': 0.35.5 - optional: true shiki@4.5.0: dependencies: diff --git a/scripts/check-responsive.sh b/scripts/check-responsive.sh index 12ade6c..dfbde7b 100644 --- a/scripts/check-responsive.sh +++ b/scripts/check-responsive.sh @@ -1,19 +1,20 @@ #!/bin/sh # 响应式结构自查(§4e):四档断点 + 触屏 44px + 安全区 + dvh 的静态断言 # 依据:docs/博客重设计调研报告.md §4e;断点 1120/820/760/560 +# 扫描用 -r 递归(src/pages 有子目录,一层 glob 会漏检 archives/gallery/moments) set -e cd "$(dirname "$0")/.." fail=0 check() { if eval "$2"; then echo " ok $1"; else echo " FAIL $1"; fail=1; fi } -CSS_SRC="src/styles/global.css src/components/*.astro src/layouts/*.astro" +DIRS="src/styles src/components src/layouts src/pages" check "断点 1120px(宽屏 TOC 常驻档)" \ - "grep -rqE 'max-width: ?1120px|min-width: ?1120px|@container' \$CSS_SRC src/pages/*.astro 2>/dev/null" + "grep -rEq '(max|min)-width: ?1120px|@container' $DIRS" check "断点 820px(笔电 TOC 收起档)" \ - "grep -rqE 'max-width: ?820px|min-width: ?820px' \$CSS_SRC src/pages/*.astro 2>/dev/null" + "grep -rEq '(max|min)-width: ?820px' $DIRS" check "断点 760px(平板竖屏档)" \ - "grep -rqE 'max-width: ?760px|min-width: ?760px' \$CSS_SRC src/pages/*.astro 2>/dev/null" + "grep -rEq '(max|min)-width: ?760px' $DIRS" check "断点 560px(手机档 + 正文降 18px)" \ "grep -rq 'max-width: 560px' src/styles/global.css" check "移动端降档:--prose-size 到 18px" \ @@ -24,8 +25,8 @@ check "安全区 env(safe-area-inset-*) 使用" \ "grep -rq 'safe-area-inset' src/styles src/components src/layouts" check "视口 viewport-fit=cover(刘海屏)" \ "grep -q 'viewport-fit=cover' src/layouts/BaseLayout.astro" -check "100dvh 或未使用视口高度陷阱(出现 100vh 即 FAIL)" \ - "! grep -rn '100vh' src/ ; true" +check "无 100vh 视口陷阱(属性值上下文;注释提及不算)" \ + "! grep -rEq ':\\s*100vh|100vh\\s*[;)]' src/ --include='*.astro' --include='*.css' && ! grep -rEq 'height:\\s*100vh|min-height:\\s*100vh' src/" check "动效总闸 prefers-reduced-motion" \ "grep -q 'prefers-reduced-motion: reduce' src/styles/global.css" check "构建产物含 viewport-fit 与主题色 meta" \ diff --git a/src/components/Avatar.astro b/src/components/Avatar.astro new file mode 100644 index 0000000..90b472b --- /dev/null +++ b/src/components/Avatar.astro @@ -0,0 +1,42 @@ +--- +// 名片头像占位:内联 SVG 渐变 60px;真实头像接入后整体替换本组件即可 +--- + + + + + + + + + + + + + w4 + + + + diff --git a/src/components/IdCard.astro b/src/components/IdCard.astro new file mode 100644 index 0000000..5e5b33c --- /dev/null +++ b/src/components/IdCard.astro @@ -0,0 +1,27 @@ +--- +// 名片区(首页/关于共用):渐变头像占位 + 称呼;图标行等内容由使用页经 slot 注入 +import Avatar from './Avatar.astro'; +--- + +
    + +
    +

    wait4x

    + + +
    +
    + + diff --git a/src/components/PostList.astro b/src/components/PostList.astro new file mode 100644 index 0000000..af3f718 --- /dev/null +++ b/src/components/PostList.astro @@ -0,0 +1,137 @@ +--- +// 年份分组 + 轨道分节的文章列表(首页与 /archives/ 共用) +// 轨道标签单一事实源:content.config 的 POST_TRACKS,此处不另立词表 +import type { CollectionEntry } from 'astro:content'; +import { POST_TRACKS, trackOf, type PostCategory } from '../content.config'; + +interface Props { + /** 调用方已完成 draft 过滤与 pubDate 倒序 */ + posts: CollectionEntry<'posts'>[]; +} +const { posts } = Astro.props; + +const byYear = new Map[]>(); +for (const post of posts) { + const year = post.data.pubDate.getUTCFullYear(); + const bucket = byYear.get(year); + if (bucket) bucket.push(post); + else byYear.set(year, [post]); +} +const mmdd = (d: Date) => + `${String(d.getUTCMonth() + 1).padStart(2, '0')}-${String(d.getUTCDate()).padStart(2, '0')}`; +--- + +
    + {[...byYear.entries()].map(([year, list]) => ( +
    +

    {year}

    + {(Object.keys(POST_TRACKS) as PostCategory[]).map((cat) => { + const rows = list.filter((post) => post.data.category === cat); + if (rows.length === 0) return null; + return ( +