10 Commits

Author SHA1 Message Date
xfy
bdfc7a19e9 feat(mermaid): 流程图主题切换跟随 VT 圆形扩散动画
此前 mermaid.render() 异步,而 VT 回调同步,Dioxus effect 重跑发生在 VT 回调
之后的微任务,导致动画期间流程图不变、动画结束后才瞬切。

利用 startViewTransition 回调可返回 Promise 的特性(浏览器等其 resolve 才拍
NEW 快照、播动画),让 VT 回调等 mermaid 重渲染完成,新主题流程图进入快照,
圆形扩散覆盖整页含 mermaid 区域。

改动:
- theme-transition.ts: 新增 onThemeChange registry(回调可返回 Promise)。
  notifyThemeChange 遍历 registry 收集 Promise 返回聚合结果;THEME_CHANGE_EVENT
  事件保留(给 codemirror/xterm 同步换肤,向后兼容)。
  startThemeTransition 的 VT 回调改为 async,await notifyThemeChange 聚合 Promise,
  确保异步换肤组件(mermaid)完成后再拍 NEW 快照。
  applyResolvedTheme(跟随系统瞬切)不等 registry,保持瞬切语义。
- mermaid.ts: 顶层注册 onThemeChange 订阅,listener 调 rerenderExistingBlocks 并
  返回其 Promise,供 VT 回调等待。initMermaid/rerenderExistingBlocks 返回 Promise。
- post_content.rs: VT 期间(is-theme-transitioning)跳过 __initMermaid 调用,避免
  Dioxus effect 抢先重渲染穿透伪元素快照(照搬 code_runner/runner.rs 守卫);
  动画结束后 effect 重跑做幂等兜底。
- theme-transition.test.ts: VT callback 签名 void→Promise<void>,新增 registry
  等待测试 + 降级路径不等 registry 测试。
2026-07-16 16:58:27 +08:00
xfy
70edc5e46c feat(frontend): mermaid 流程图懒加载渲染
mermaid 无官方 SSR 支持,采用客户端 IntersectionObserver 懒加载:服务端
markdown.rs 只产出普通 <pre><code class="language-mermaid"> 代码块,
前端在块进视口时动态 import 独立 bundle(~1MB)渲染成 SVG。

新增 libs/mermaid-renderer/:mermaid 11.16 IIFE bundle,输出 public/mermaid/
yggdrasil-core/mermaid.ts:扫描 language-mermaid 块,视口可见时动态 import
  /mermaid/mermaid.js(单例缓存),mermaid.initialize 适配 light/dark 主题,
  securityLevel=strict;渲染失败加 .mermaid-error class 保留源码;幂等守卫
post-content.ts:initCopyButtons 跳过 language-mermaid 块(图无需 copy)
post_content.rs:use_effect 调 __initMermaid('.post-content', theme),
  读 use_resolved_theme() 传主题并建立订阅

新增 6 个 mermaid 单测(扫描/主题/幂等/非mermaid/未命中/错误回退)。
550 Rust + 28 前端测试全过,双 target 编译通过。
2026-07-16 14:22:43 +08:00
xfy
5ad6ce60cd fix(post): hydration 后点击标题锚点触发整页刷新
WASM 下载完成后点击 TOC/标题 # 锚点会整页刷新且不滚动,而 SSR 阶段(WASM
未就绪)点击正常——这是 Dioxus 0.7 事件委托的副作用:

项目任意位置用 onclick(post_nav_links.rs)即触发 Dioxus 全局 click 委托。
点击 dangerous_inner_html 注入的 <a href="#id"> 时,事件冒泡到根监听器,
handleEvent 发现 <a> 无 Dioxus onclick → 走兜底 handleClickNavigate:
preventDefault 拦掉原生 fragment-scroll,再 browser_open IPC 把 hash 当
外部 URL 整页加载(History::external → location.set_href)。

修复:yggdrasil-core 新增 anchor-click.ts,在 window capture 阶段(早于
Dioxus 的 bubble 委托)拦截同页 hash 锚点点击,stopPropagation 阻止事件
到达 Dioxus,自行 scrollIntoView + replaceState 更新地址栏。中键/修饰键、
外链、目标不存在等情况放行原行为。

81682eb 的 scrollToHash 只在 PostContent 挂载时跑一次,不覆盖点击场景;
本修复与之正交,共同覆盖刷新与点击两条路径。initAnchorClick 幂等。
2026-07-13 18:22:53 +08:00
xfy
81682eb70e fix(post): 修复 hash 锚点跳转失效
内容异步加载(use_server_future)导致骨架屏阶段标题 DOM 缺失,浏览器原生
fragment-scroll 找不到目标留在顶部;刷新页面也因 SSR 出的是骨架屏而失效。

- 新增 __scrollToHash 全局入口(yggdrasil-core):内容挂载后解码
  location.hash(CJK 百分号编码 → 原始字符)并 scrollIntoView
- PostContent use_effect 末尾复用 invoke_optional_global 调用,标题
  DOM 已就绪时补一次滚动
- 标题加 scroll-margin-top: 6rem,避开 80px sticky header

点击 TOC/标题 hashtag 由原生 anchor + scroll-margin-top 覆盖,无需 JS。
2026-07-10 00:21:08 +08:00
xfy
cb77d28a68 fix(theme): 跟随系统切换改为瞬切,放弃 VT 动画
诊断确认:跟随系统与手动点击的 VT 流程在 JS/CSS 层完全等价(animationName、
--tt-r、bg 翻转、clip-path 全部正确),但视觉上跟随系统场景下圆形展开动画
不显示,仅瞬切。系统偏好变化是后台事件,VT 在此上下文下动画不可靠。

改用设置语义的瞬切:JS 侧新增 applyResolvedTheme(isDark) 入口(非翻转语义,
直接 add/remove dark class),Rust effect 改调 __applyResolvedTheme 传实际
明暗值,移除圆心计算逻辑。职责清晰:
- 手动点击 → __startThemeTransition → VT 圆形展开(用户手势,动画可靠)
- 跟随系统 → __applyResolvedTheme → 瞬切(后台同步语义)
2026-07-03 13:42:17 +08:00
xfy
b1b1c88a74 chore(biome): 引入 Biome v2.5 monorepo 配置并格式化全量源码
新增根 biome.json(v2.5,v2 起原生支持 monorepo,子包自动向上查找):

- formatter: 2 空格缩进、单引号、行宽 100、LF、尾逗号、箭头函数括号
  (匹配现有代码风格)
- linter: recommended preset + 项目化裁剪
  - useTemplate/useTemplate off(geometry.ts 故意保留字符串拼接,
    且测试用精确浮点断言锁定行为)
  - noNonNullAssertion off(测试与 DOM 访问里的 ! 是惯用写法)
  - noConsole off(4 个 lib 用 console.error/warn 做错误上报)
  - CSS 关闭 noDescendingSpecificity/noDuplicateProperties
    (手写 CSS 的 fallback 模式)
  - useImportType/useNodejsImportProtocol/noUnusedVariables warn
- vcs.useIgnoreFile 自动读 .gitignore;排除 public/target/node_modules/
  dist/.dioxus/static + Tailwind 入口 input.css(含 @theme 等 Biome 无法
  解析的 at-rules)

首次格式化覆盖 29 个源文件:import 排序、node: 协议、引号/缩进统一,
并修复 index.ts 两处 forEach 回调隐式返回值(useIterableCallbackReturn)。
90 个 vitest 用例全绿,确认无语义改动。
2026-07-02 17:54:46 +08:00
xfy
b542952619 fix(theme): pre-inject VT styles before startViewTransition
Previous approach injected ::view-transition-new animation in vt.ready,
creating a timing gap where the NEW layer had no clip-path and was fully
visible, making dark→light transitions invisible.

Now:
- Inject <style> with @keyframes + VT pseudo-element rules BEFORE
  calling startViewTransition, so styles are ready when pseudo-elements
  are created.
- Force synchronous getComputedStyle() in VT callback to ensure the
  NEW snapshot captures final background-color, not a mid-transition
  value.
2026-06-26 17:55:45 +08:00
xfy
6979bd1010 feat(theme): 圆形展开主题切换动画(View Transitions API)
点击主题按钮时,新主题从按钮位置以圆形向外展开覆盖全屏。
JS 同步 toggle dark class 拍快照 + CSS clip-path circle keyframes;
Rust theme.set 事后对齐状态(use_effect 幂等)。
reduced-motion 与不支持 VT 的浏览器自动降级为瞬切。
2026-06-26 14:06:23 +08:00
xfy
ac1f92d816 refactor(core): 迁移 post-content 到 yggdrasil-core,删除 public/js
逐行 TypeScript 化(逻辑不变),改走 window.__initPostContent 全局入口。
post-content.js 已迁移进 libs/yggdrasil-core/,public/js/ 目录随之删除。
2026-06-26 13:57:48 +08:00
xfy
afabdf4655 chore(core): 搭建 yggdrasil-core 子工程骨架
照搬 lightbox 的 Vite IIFE 工程结构,作为核心 JS 统一归处。
此 commit 仅打通构建管线,业务逻辑后续 task 填入。
同时把 public/yggdrasil-core 加入根 .gitignore。
2026-06-26 13:51:39 +08:00