10 Commits

Author SHA1 Message Date
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
225c477f8c chore(theme): remove debug prints 2026-06-26 18:27:27 +08:00
xfy
0ff24888ce refactor(theme): use pure CSS View Transitions without WAAPI or style injection
Adopt a fully CSS-driven strategy for the theme transition:
- Use CSS variables (--tt-x, --tt-y, --tt-r) injected onto documentElement
- Define static @keyframes in style.css using these variables
- Key logic: the Dark layer is ALWAYS placed on top (z-index: 2).
  - Light -> Dark: NEW layer is Dark, so NEW expands from circle(0) to cover OLD.
  - Dark -> Light: OLD layer is Dark, so OLD shrinks to circle(0) to reveal NEW.

This completely eliminates reliance on Web Animations API (which had bugs
with clip-path when animation:none is set) and eliminates dynamic <style>
injection (which caused timing gaps and style residue).
The result is perfectly symmetrical and bug-free in both directions.
2026-06-26 18:14:29 +08:00
xfy
0f9c8fb8a3 fix(theme): lock VT pseudo-element opacity/blend via CSS !important
Gray expanding circle was caused by UA default animations (fade-in/out)
and mix-blend-mode: plus-lighter not being fully overridden by WAAPI
opacity animations alone.

Fix: use CSS with !important to hard-lock the VT pseudo-elements:
- animation: none !important — kills UA fade-in/out
- opacity: 1 !important — both layers stay fully opaque
- mix-blend-mode: normal !important — no color addition

WAAPI now only controls clip-path on ::view-transition-new(root),
which doesn't conflict with any CSS property (no CSS clip-path exists).
This cleanly separates concerns: CSS handles static properties,
WAAPI handles the dynamic circle expansion.
2026-06-26 18:08:28 +08:00
xfy
f0ea1a294f refactor(theme): switch VT animation from CSS injection to Web Animations API
Replace dynamic <style> injection (@keyframes + pseudo-element rules)
with document.documentElement.animate({ pseudoElement }) calls.

Previous approach accumulated <style> elements across transitions,
causing subsequent dark→light animations to be invisible. The Web
Animations API:
- Creates per-call Animation objects with no DOM residue
- Has higher composite priority than CSS animations, naturally
  overriding UA default fade-in/out without !important
- Eliminates style element lifecycle management entirely

Static CSS now only sets mix-blend-mode: normal (not animatable via
WAAPI) and the is-theme-transitioning transition suppression.
2026-06-26 18:02:26 +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
ba9db2d75a fix(theme): fix dark→light transition animation invisible
The static CSS rule 'animation: none' on ::view-transition-new(root)
caused the new (light) screenshot to be fully visible before the JS-
injected clip-path @keyframes kicked in. This meant the light layer
was already covering the dark layer, making the expanding circle
invisible.

Fix: move all VT pseudo-element styles (animation, mix-blend-mode)
into the dynamically injected <style> block in vt.ready, so they
apply atomically with the clip-path keyframes.

Also:
- Add transition:none !important during VT to prevent body's
  background-color 0.3s transition from producing a stale capture.
- Restore Dioxus theme.set() that was disabled for debugging, so
  the toggle icon and localStorage persist correctly.
- Use !important on injected animation to reliably override any
  UA default VT animations.
2026-06-26 17:50:45 +08:00
xfy
c1781d7831 fix(theme): VT 期间冻结 CSS 过渡,让圆形展开可见
body 有 transition: background-color .3s,VT 在 toggle dark class
后下一帧拍 NEW 快照时背景色才走了 ~5%,新旧快照几乎一样,
圆形展开看不出颜色差。修复:回调里加 vt-freeze 类禁用所有
过渡,让 NEW 快照立即拿到新主题配色;动画结束(finished)后
移除。补 1 个测试覆盖 freeze 生命周期。
2026-06-26 14:36:41 +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