Files
sundynix-agentix/sundynix-web/src/theme.ts
T
Blizzard 7c67256f87
CI / Go · build + vet + test (pull_request) Failing after 30m3s
CI / Frontend · tsc (sundynix-admin) (pull_request) Failing after 9m42s
CI / Frontend · tsc (sundynix-desktop/frontend) (pull_request) Failing after 16m53s
CI / Frontend · tsc (sundynix-web) (pull_request) Has been cancelled
CI / mcp-py · sandbox guard (pull_request) Has been cancelled
feat(web): 薄 Web 面 sundynix-web —— 注册/组织/团队/账单自助入口
SaaS P3 收口第二刀(设计见 SAAS_DESIGN.md §8)。第三个产品面:desktop=用户
工作产品、admin=平台超管控制塔、web=租户客户的自助柜台——做「装桌面端之前
就要能用」的那些事,三者不合并。

- 骨架抄 admin(HashRouter+路由注册表+me()/sdx:logout 鉴权门+vite/vitest
  单文件配置);UI 整目录搬 desktop 的 ui/ 组件+ink/brand 主题 token(亮暗
  双主题),品牌观感与桌面端一致;api.ts 抄 desktop 的 auth/tenant/usage 段
  (纯 fetch 零 Wails 依赖),成员管理/建组织打新的租户自助接口。
- 页面:登录注册(一页两态)/概览(组织+角色+余额+桌面端下载指引)/团队(名册+
  邀请+改角色+移除,写控件按角色显隐、真闸在后端)/组织(列表+自助新建+切换)/
  用量与账单(余额 hero+趋势+合计+最近消耗,数据全来自现成 /me/usage;充值
  只放说明占位,支付 P5 再接,不做假入口)。
- 工程:vite :5175、launch.json 配置、make webface、ci.yml web 矩阵纳入。
- 测试:tsc 干净;vitest 3 例(fmtCredits 去尾零——测试先行抓出 1.50 毛刺;
  ASSIGNABLE_ROLES 不含 owner)。浏览器 live 全流程:甲(owner)登录→概览→
  团队邀请乙→乙(member)登录写控件全隐藏、名册只读,组织/用量页真数据渲染。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 17:47:23 +08:00

36 lines
1.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 主题(亮/暗)管理:持久化到 localStorage,切换在 <html> 上加/去 .dark 类。
// 默认亮色(暗色为可选)。初始化在 applyInitialThememain 启动时调,先于渲染避免闪烁)。
import { useCallback, useEffect, useState } from "react";
export type Theme = "light" | "dark";
const KEY = "sdx-theme";
export function getStoredTheme(): Theme {
const t = localStorage.getItem(KEY);
return t === "dark" ? "dark" : "light"; // 默认亮色
}
function apply(theme: Theme): void {
document.documentElement.classList.toggle("dark", theme === "dark");
}
// applyInitialTheme 在渲染前调用,依据存储值设好 .dark 类(避免首屏闪烁)。
export function applyInitialTheme(): void {
apply(getStoredTheme());
}
// useTheme 暴露当前主题与切换函数(写 localStorage + 切 .dark 类)。
export function useTheme(): { theme: Theme; toggle: () => void; setTheme: (t: Theme) => void } {
const [theme, setThemeState] = useState<Theme>(getStoredTheme);
useEffect(() => {
apply(theme);
localStorage.setItem(KEY, theme);
}, [theme]);
const setTheme = useCallback((t: Theme) => setThemeState(t), []);
const toggle = useCallback(() => setThemeState((t) => (t === "dark" ? "light" : "dark")), []);
return { theme, toggle, setTheme };
}