- 新增 scripts/generate-tokens.ts 从 SCSS 解析 CSS 变量生成 token-values.ts - 新增 useCanvasTokens hook 供 Canvas 组件适老化/医生端切换 - vitest include 扩展覆盖 scripts/__tests__/ - 10 单元测试覆盖 SCSS 解析和变量替换
90 lines
2.6 KiB
TypeScript
90 lines
2.6 KiB
TypeScript
import { useMemo } from 'react';
|
|
import {
|
|
TOKEN_VALUES,
|
|
ELDER_TOKEN_OVERRIDES,
|
|
DOCTOR_TOKEN_OVERRIDES,
|
|
CANVAS_FONT_NORMAL,
|
|
CANVAS_FONT_ELDER,
|
|
} from '@/styles/token-values';
|
|
import { useUIStore } from '@/stores/ui';
|
|
import { useAuthStore } from '@/stores/auth';
|
|
|
|
/** Canvas 绘制用的合并 Token */
|
|
export interface CanvasTokens {
|
|
pri: string;
|
|
tx: string;
|
|
tx2: string;
|
|
gridColor: string;
|
|
fontH1: number;
|
|
fontBody: number;
|
|
fontBodySm: number;
|
|
fontCap: number;
|
|
yLabelFontSize: number;
|
|
xLabelFontSize: number;
|
|
tooltipFontSize: number;
|
|
pointNormalRadius: number;
|
|
pointAbnormalRadius: number;
|
|
referenceBandColor: string;
|
|
areaGradientStart: string;
|
|
areaGradientEnd: string;
|
|
lineColor: string;
|
|
abnormalColor: string;
|
|
}
|
|
|
|
function pxToInt(val: string | undefined, fallback: number): number {
|
|
if (!val) return fallback;
|
|
return parseInt(val, 10) || fallback;
|
|
}
|
|
|
|
/** 为 Canvas 组件提供适老化/医生端的 Token 值 */
|
|
export function useCanvasTokens(): CanvasTokens {
|
|
const mode = useUIStore((s) => s.mode);
|
|
const isDoctor = useAuthStore((s) => s.isDoctor());
|
|
|
|
return useMemo(() => {
|
|
const tokens = TOKEN_VALUES as Record<string, string>;
|
|
const docTokens = DOCTOR_TOKEN_OVERRIDES as Record<string, string>;
|
|
const elderTokens = ELDER_TOKEN_OVERRIDES as Record<string, string>;
|
|
|
|
let pri = tokens['pri'] || '#C4623A';
|
|
const tx = '#2D2A26';
|
|
|
|
if (isDoctor) {
|
|
pri = docTokens['pri'] || pri;
|
|
}
|
|
|
|
const isElder = mode === 'elder';
|
|
const fontSet = isElder ? CANVAS_FONT_ELDER : CANVAS_FONT_NORMAL;
|
|
|
|
return {
|
|
pri,
|
|
tx,
|
|
tx2: isElder ? '#5A554F' : (tokens['text-secondary'] || '#78716C'),
|
|
gridColor: isElder ? '#E0DBD5' : '#F3F4F6',
|
|
fontH1: pxToInt(tokens['font-h1'], 28),
|
|
fontBody: pxToInt(
|
|
isElder ? elderTokens['font-body'] : tokens['font-body'],
|
|
isElder ? 22 : 16,
|
|
),
|
|
fontBodySm: pxToInt(
|
|
isElder ? elderTokens['font-body-sm'] : tokens['font-body-sm'],
|
|
isElder ? 19 : 14,
|
|
),
|
|
fontCap: pxToInt(
|
|
isElder ? elderTokens['font-cap'] : tokens['font-cap'],
|
|
isElder ? 18 : 13,
|
|
),
|
|
yLabelFontSize: fontSet.yLabel,
|
|
xLabelFontSize: fontSet.xLabel,
|
|
tooltipFontSize: fontSet.tooltip,
|
|
pointNormalRadius: fontSet.pointNormal,
|
|
pointAbnormalRadius: fontSet.pointAbnormal,
|
|
referenceBandColor: isElder ? 'rgba(5,150,105,0.15)' : 'rgba(5,150,105,0.08)',
|
|
areaGradientStart: isElder ? 'rgba(8,145,178,0.20)' : 'rgba(8,145,178,0.15)',
|
|
areaGradientEnd: 'rgba(8,145,178,0.01)',
|
|
lineColor: '#0891B2',
|
|
abnormalColor: '#DC2626',
|
|
};
|
|
}, [mode, isDoctor]);
|
|
}
|