feat: Header 倒计时数字滚动动画 — @number-flow/react 替换静态文本
This commit is contained in:
@@ -1,9 +1,8 @@
|
||||
import NumberFlow from "@number-flow/react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { RefreshIcon } from "tdesign-icons-react";
|
||||
import { Button, Typography } from "tdesign-react";
|
||||
|
||||
import { formatCountdown } from "../utils/time";
|
||||
|
||||
interface RefreshCountdownProps {
|
||||
dashboardUpdatedAt: number;
|
||||
isFetching: boolean;
|
||||
@@ -45,8 +44,55 @@ export function RefreshCountdown({
|
||||
);
|
||||
}
|
||||
|
||||
const refreshText =
|
||||
dashboardUpdatedAt > 0 ? (isFetching ? "刷新中..." : formatCountdown(nextRefreshSeconds ?? 0)) : "等待首次刷新";
|
||||
if (dashboardUpdatedAt <= 0) {
|
||||
return <Typography.Text theme="secondary">等待首次刷新</Typography.Text>;
|
||||
}
|
||||
|
||||
return <Typography.Text theme="secondary">{refreshText}</Typography.Text>;
|
||||
if (isFetching) {
|
||||
return <Typography.Text theme="secondary">刷新中...</Typography.Text>;
|
||||
}
|
||||
|
||||
const seconds = nextRefreshSeconds ?? 0;
|
||||
const isMinuteMode = refreshInterval >= 60000;
|
||||
|
||||
if (isMinuteMode) {
|
||||
const mm = Math.floor(seconds / 60);
|
||||
const ss = seconds % 60;
|
||||
|
||||
return (
|
||||
<span aria-label={formatAccessibleLabel(seconds, true)} className="refresh-countdown-flow">
|
||||
<NumberFlow
|
||||
className="refresh-countdown-flow__number"
|
||||
format={{ minimumIntegerDigits: 1 }}
|
||||
trend={-1}
|
||||
value={mm}
|
||||
/>
|
||||
<span className="refresh-countdown-flow__unit">分</span>
|
||||
<NumberFlow
|
||||
className="refresh-countdown-flow__number"
|
||||
digits={{ 1: { max: 5 } }}
|
||||
format={{ minimumIntegerDigits: 2 }}
|
||||
trend={-1}
|
||||
value={ss}
|
||||
/>
|
||||
<span className="refresh-countdown-flow__unit">秒</span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<span aria-label={formatAccessibleLabel(seconds, false)} className="refresh-countdown-flow">
|
||||
<NumberFlow className="refresh-countdown-flow__number" trend={-1} value={seconds} />
|
||||
<span className="refresh-countdown-flow__unit">秒</span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
function formatAccessibleLabel(seconds: number, isMinuteMode: boolean): string {
|
||||
if (isMinuteMode) {
|
||||
const mm = Math.floor(seconds / 60);
|
||||
const ss = seconds % 60;
|
||||
return `${mm}分${String(ss).padStart(2, "0")}秒`;
|
||||
}
|
||||
return `${seconds}秒`;
|
||||
}
|
||||
|
||||
@@ -63,6 +63,24 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.refresh-countdown-flow {
|
||||
display: inline-flex;
|
||||
align-items: baseline;
|
||||
font-variant-numeric: tabular-nums;
|
||||
white-space: nowrap;
|
||||
color: var(--td-text-color-secondary);
|
||||
}
|
||||
|
||||
.refresh-countdown-flow__number {
|
||||
line-height: 0.85;
|
||||
--number-flow-mask-height: 0.15em;
|
||||
--number-flow-mask-width: 0.25em;
|
||||
}
|
||||
|
||||
.refresh-countdown-flow__unit {
|
||||
margin: 0 1px;
|
||||
}
|
||||
|
||||
.status-dot {
|
||||
display: inline-block;
|
||||
width: 12px;
|
||||
|
||||
Reference in New Issue
Block a user