// ===== demos/ui-entrance/floating-glossy-label-pills/FloatingGlossyLabelPills.tsx =====
// floating-glossy-label-pills — Glossy Pills Carousel 高光胶囊横滑走廊(motion-lab 定稿转原生 Remotion)
// 白底四角强调色雾霭,四块浅灰 dashboard 占位 mockup(三栏卡片 / 折线图仪表盘 /
// 列表表格 / 表单+开关列表)横向排队,各顶一枚高光强调色胶囊标签(Feature A–D);
// 轨道环形循环,任一拍居中面板左右都露出相邻面板边缘。开场有上一拍收尾余量
// (偏左 11px 缓归位),随后轨道三拍向右换位(t≈0.20/0.483/0.688,inOutCubic,
// 第一拍带长尾)——居中者放大清晰,两侧缩至 0.62、下沉变淡微模糊;t≈0.717 黑色
// 描白边光标右上硬现,减速斜滑向左下,t≈0.90 停在末位胶囊右端。
// 整卡唯一色相来源是 ACCENT 及其深浅档,按项目品牌色替换即换肤。
// 设计坐标 480×270(DesignStage 等比放大),参数表数值以此坐标系标定。
import React from 'react';
import { DesignStage, E, lerp, rand, seg, useT } from '../../_fixtures/Motion';
export const FLOATING_GLOSSY_LABEL_PILLS_DURATION = 120; // 4000ms @30fps
// ── 模板强调色:实际使用时按项目品牌色替换这一组变量 ──
const ACCENT = '#7a8699'; // 中性蓝灰做默认演示色
const ACCENT_LIGHT = '#a8b2c0', ACCENT_DEEP = '#4c5666';
const A_RGB = '122,134,153', AL_RGB = '168,178,192', AD_RGB = '76,86,102';
const F = '-apple-system,BlinkMacSystemFont,sans-serif';
// 逐帧实测(480×270 裁切系):
// 居中面板 x 105-357(W≈252)、top=75,下缘正好压住画面底 → 真高 H≈195
// 邻位(静止)面板 x -70..86(缩到 0.62)、top=126 → 缩放 + 下沉 51px
// 相邻两块中心距 SP≈232
// 内部 UI 按 330×255 的内容坐标书写,再整体等比 scale 到 252×195
const CW = 330, CH = 255, CS = 252 / CW;
const W = Math.round(CW * CS), H = Math.round(CH * CS), SP = 232;
const PANEL_TOP = 75;
// ── 通用占位(wireframe / skeleton)零件:全部只用灰条 + 色块,不写具体文案 ──
const TITLE = '#a8adb5', TEXT = '#d4d7dd', FAINT = '#e3e5ea', LINE = '#eceef1';
// 骨架条:默认圆角 min(h/2, 3)
const Skel: React.FC<{ x: number; y: number; w: number; h: number; col: string; r?: number }> = ({ x, y, w, h, col, r }) => (
);
// 窗口顶栏:强调色方块 + 字标灰条 + 右侧两枚圆点(各页面通用 chrome)
const Topbar: React.FC = () => (
);
// 左侧导航:一条高亮项 + 若干灰条
const Sidebar: React.FC = () => (
{Array.from({ length: 8 }, (_, i) => (
))}
);
// 1) 三栏卡片占位(居中标题 + 三张卡:标题条/大字块/文本骨架/按钮块)
const BCards: React.FC = () => (
<>
{Array.from({ length: 3 }, (_, i) => (
{Array.from({ length: 5 }, (_, k) => (
))}
))}
>
);
// 2) 仪表盘占位(四枚数值卡 + 折线图占位)
const BDash: React.FC = () => (
<>
{Array.from({ length: 4 }, (_, i) => (
))}
{Array.from({ length: 5 }, (_, i) => (
))}
>
);
// 3) 列表 / 表格占位(小统计条 + 多行骨架 + 状态色块)
const BTable: React.FC = () => (
<>
{Array.from({ length: 4 }, (_, i) => (
))}
{Array.from({ length: 7 }, (_, i) => (
{/* 状态色块保留功能色(异常淡红 / 正常淡绿) */}
))}
>
);
// 4) 表单 + 开关列表占位(左侧字段框,右侧头像色块行 + 开关)
const BForm: React.FC = () => (
<>
{Array.from({ length: 3 }, (_, i) => (
))}
{Array.from({ length: 3 }, (_, i) => (
))}
{Array.from({ length: 4 }, (_, i) => (
1 ? 22 : 0), width: 100, height: 22 }}>
{/* 开关保留功能色(开=蓝 / 关=灰) */}
))}
>
);
// 四组:胶囊 + 占位 mockup 横向排队(i 越大越靠左,滑入中央越晚),轨道循环
const GROUPS: { txt: string; Body: React.FC }[] = [
{ txt: 'Feature A', Body: BCards },
{ txt: 'Feature B', Body: BDash },
{ txt: 'Feature C', Body: BTable },
{ txt: 'Feature D', Body: BForm },
];
// 雾块静态参数(位置 / 颜色)
const FOGS = [
{ left: '68%', top: '8%', rgb: AD_RGB },
{ left: '4%', top: '60%', rgb: A_RGB },
{ left: '40%', top: '82%', rgb: AL_RGB },
];
// 轨道三拍:起点 t≈0.20 / 0.483 / 0.688,inOutCubic 缓起→中段冲→缓收;
// 第一拍明显更慢且带长尾(到 t≈0.48 才完全收住),后两拍干脆些。
const BEATS = [
{ b: 0.200, d: 0.185, tail: 0.28 }, // 第 1 位 → 第 2 位
{ b: 0.483, d: 0.150, tail: 0 }, // 第 2 位 → 第 3 位
{ b: 0.688, d: 0.150, tail: 0 }, // 第 3 位 → 第 4 位
];
export const FloatingGlossyLabelPills: React.FC = () => {
const t = useT();
// 开场有上一拍的收尾余量:t=0 时轨道偏左 11px,t≈0.19 归位
let trackX = -11 * (1 - seg(t, 0, 0.19, E.outQuart));
for (const B of BEATS) {
const p = B.tail
? 0.85 * seg(t, B.b, B.b + B.d, E.inOutCubic) + 0.15 * seg(t, B.b, B.b + B.tail, E.outCubic)
: seg(t, B.b, B.b + B.d, E.inOutCubic);
trackX += p * SP;
}
const N = GROUPS.length, RING = N * SP;
// 光标:t≈0.717 于右上(x≈403,y≈36)一帧硬现,减速斜滑向左下,
// t≈0.90 抵达末位胶囊右端附近(x≈281,y≈56)后几乎静止
const cp = seg(t, 0.717, 0.90, E.outQuart);
return (
{/* 漂移雾块 */}
{FOGS.map(({ left, top, rgb }, i) => (
))}
{GROUPS.map(({ txt, Body }, i) => {
// 环形轨道:面板绕 4 位循环,保证任一拍都有左右邻居各露一截在画面边缘
let wx = trackX - i * SP;
wx = ((wx % RING) + RING * 1.5) % RING - RING / 2;
const d = Math.min(1, Math.abs(wx) / SP); // 0=正居中,1=已到邻位
const close = 1 - d;
const sc = lerp(close, 0.62, 1); // 邻位实测缩到 0.62
return (
0.5 ? 2 : 1,
}}
>
{/* 面板:等比缩小 + 顶边随 d 线性下沉(斜率 ≈80px) */}
{/* 胶囊:实测中心 y 从 45(居中)沉到 102(邻位),比面板沉得更多,
离心时贴近面板顶边 —— 单独一条更陡的下沉曲线 */}
);
})}
{/* 黑色描白边光标(结尾划向末位胶囊,macOS 指针样式) */}
);
};