Commit a4dd6fa6 by luoqi

feat(web): 矩阵改用 claude design 的 1b「连续色带」+ 浮层真动效

按产品在 claude design 出的稿子(分配矩阵.dc.html 的 1b 方案)重做:

· 三列共用**一条** amber → emerald → sky 的横向渐变,格子透明浮在这张面上 ——
  列与列之间没有缝,整片读起来是一条"由烫到冷"的轴,只用色相区分窗口。
· 用 shadcn Card(CardHeader/CardContent)承载,浮层只负责定位与动效,宽度交给 Card 自己定
  —— 两处都写宽度必然对不齐,而且改一处会静默留下另一处的白边。
· 表头补列汇总(黄金期 271 / 窗口内 280 / 窗口外 3,254),现算不新增字段。
· hover 文案**保持原样**:只给天数区间,不给解释。

️ 配色是**恢复**但不是回到老样子:老那套是"温度比喻"的冷暖渐变(已撤),
这套是与列头一一对应的三个色相 —— 色相与文字是同一信息的两种编码,
刻意的冗余(色盲靠文字、扫视靠颜色)。「数量不参与配色」这条自始至终没变。

 顺带修掉两处**写了不生效、且完全不报错**的样式:

① popover.tsx 一直挂着 shadcn 官方的 `animate-in fade-in-0 …`,而那套来自
   tailwindcss-animate 插件、**本仓根本没装** → 浮层一帧动画都没有。
   改用原生 keyframes,并**经 @theme 注册成 --animate-***:
   Tailwind 的 variant 只作用在它自己生成的 utility 上,手写同名 class 拿不到
   `data-[state=open]:` —— 实测 animation-name: none(class 在、样式在,就是没被选中)。
   缩放锚点接 --radix-popover-content-transform-origin,浮层从触发按钮那个角长出来。

② 格子的 hover 描边先写成 `shadow-[inset_0_0_0_2px_var(--color-slate-900)]`,
   Tailwind v4 把带 var() 的任意值解析成"只有颜色的阴影",偏移和扩散全丢,
   实测是 `oklab(0 0 0 / 0) 0 0 0 0 inset` —— 完全透明。改用原生 outline;
   ️ 还必须带 `outline-solid`,否则基态的 `outline-none` 把 outline-style 钉成 none,
   只加 outline-2 就是"宽度 2px、样式 none",一条线都不画。

浏览器逐项实测:渐变面(oklab 插值)、hover 内描边(solid 2px, offset -2px)、
出现/消失动画(overlayIn 0.14s / overlayOut 0.1s,Radix 会等动画结束再卸载)、
tooltip 区间不变;next build 通过,971 tests passing,控制台零报错。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
parent c9d70688
...@@ -229,3 +229,25 @@ body { ...@@ -229,3 +229,25 @@ body {
::-webkit-scrollbar-corner { ::-webkit-scrollbar-corner {
background: transparent; background: transparent;
} }
/* ── Radix 浮层的出现/消失 ────────────────────────────────────────
⚠️ shadcn 官方那套 `animate-in fade-in-0 zoom-in-95` 来自 tailwindcss-animate 插件,
**本仓没装**(内网拉包本身是风险)—— 那些 class 写了也不生效,
popover.tsx 里原先就挂着一串,实际一帧动画都没有。这里用原生 keyframes 补上。
⚠️⚠️ 必须经 `@theme` 注册成 `--animate-*`,**不能只写一条 `.animate-overlayIn` 类**:
浮层要靠 `data-[state=open]:animate-overlayIn` 触发,而 Tailwind 的 variant
只作用在**它自己生成的 utility** 上 —— 手写的同名 class 拿不到 variant,
实测算出来 animation-name: none(class 在、样式在,就是没被 variant 选中)。 */
@keyframes overlayIn {
from { opacity: 0; transform: scale(0.96) translateY(-2px); }
to { opacity: 1; transform: scale(1) translateY(0); }
}
@keyframes overlayOut {
from { opacity: 1; transform: scale(1) translateY(0); }
to { opacity: 0; transform: scale(0.96) translateY(-2px); }
}
@theme {
--animate-overlayIn: overlayIn 0.14s cubic-bezier(0.22, 1, 0.36, 1);
--animate-overlayOut: overlayOut 0.1s ease-in;
}
...@@ -267,7 +267,9 @@ export function PatientPickerRail({ ...@@ -267,7 +267,9 @@ export function PatientPickerRail({
分配 分配
</button> </button>
</PopoverTrigger> </PopoverTrigger>
<PopoverContent align="end" sideOffset={6} className="w-[420px] p-0"> {/* 宽度交给 PoolMatrix 里的 Card 自己定(w-auto),浮层只负责定位与动效;
两处都写宽度必然对不齐,而且改一处会静默留下另一处的白边。 */}
<PopoverContent align="end" sideOffset={6} className="w-auto p-0">
<PoolMatrix selected={cell} onPick={pickCell} /> <PoolMatrix selected={cell} onPick={pickCell} />
</PopoverContent> </PopoverContent>
</Popover> </Popover>
......
...@@ -22,7 +22,12 @@ const PopoverContent = React.forwardRef< ...@@ -22,7 +22,12 @@ const PopoverContent = React.forwardRef<
sideOffset={sideOffset} sideOffset={sideOffset}
className={cn( className={cn(
'z-50 w-auto rounded-md border border-slate-100 bg-white p-2 shadow-md outline-none', 'z-50 w-auto rounded-md border border-slate-100 bg-white p-2 shadow-md outline-none',
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0', // ⚠️ 原先挂的是 shadcn 官方那串 `animate-in fade-in-0 …` —— 它们来自
// tailwindcss-animate 插件,**本仓没装**,所以一帧动画都没有(class 写了不报错,
// 只是不生效,最难发现的那种)。改用 globals.css 里的原生 keyframes。
// 缩放锚点跟随 Radix 算出来的位置 → 浮层从触发按钮那个角"长出来",而不是自身中心缩放
'origin-(--radix-popover-content-transform-origin)',
'data-[state=open]:animate-overlayIn data-[state=closed]:animate-overlayOut',
className, className,
)} )}
{...props} {...props}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment