Skip to content

Commit 129df7b

Browse files
authored
🐛 fix: Abnormal animation of tokens (lobehub#10106)
* ✨ feat(TokenDetail): add toggle for short/long format display of token values * ✨ feat(TokenDetail): enhance token display format persistence and toggle functionality * ✨ feat(TokenDetail): adjust popover trigger behavior for mobile and desktop * replace localStorage with global store for token display format management * add animation duration for token value display * ✨ feat: 强制重新挂载以防止在切换 token/credit 时出现不必要的动画
1 parent 190b282 commit 129df7b

File tree

3 files changed

+37
-3
lines changed

3 files changed

+37
-3
lines changed

src/features/Conversation/components/Extras/Usage/UsageDetail/index.tsx

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { useTranslation } from 'react-i18next';
88
import { Center, Flexbox } from 'react-layout-kit';
99

1010
import InfoTooltip from '@/components/InfoTooltip';
11+
import { useIsMobile } from '@/hooks/useIsMobile';
1112
import { aiModelSelectors, useAiInfraStore } from '@/store/aiInfra';
1213
import { useGlobalStore } from '@/store/global';
1314
import { systemStatusSelectors } from '@/store/global/selectors';
@@ -27,6 +28,11 @@ interface TokenDetailProps {
2728
const TokenDetail = memo<TokenDetailProps>(({ meta, model, provider }) => {
2829
const { t } = useTranslation('chat');
2930
const theme = useTheme();
31+
const isMobile = useIsMobile();
32+
33+
// 使用 systemStatus 管理短格式显示状态
34+
const isShortFormat = useGlobalStore(systemStatusSelectors.tokenDisplayFormatShort);
35+
const updateSystemStatus = useGlobalStore((s) => s.updateSystemStatus);
3036

3137
const modelCard = useAiInfraStore(aiModelSelectors.getModelCard(model, provider));
3238
const isShowCredit = useGlobalStore(systemStatusSelectors.isShowCredit) && !!modelCard?.pricing;
@@ -211,12 +217,32 @@ const TokenDetail = memo<TokenDetailProps>(({ meta, model, provider }) => {
211217
</Flexbox>
212218
}
213219
placement={'top'}
214-
trigger={['hover', 'click']}
220+
trigger={isMobile ? ['click'] : ['hover']}
215221
>
216-
<Center gap={2} horizontal style={{ cursor: 'default' }}>
222+
<Center
223+
gap={2}
224+
horizontal
225+
onClick={(e) => {
226+
// 移动端:让 Popover 处理点击事件
227+
if (isMobile) return;
228+
229+
// 桌面端:阻止 Popover 并切换格式
230+
e.preventDefault();
231+
e.stopPropagation();
232+
updateSystemStatus({ tokenDisplayFormatShort: !isShortFormat });
233+
}}
234+
style={{ cursor: isMobile ? 'default' : 'pointer' }}
235+
>
217236
<Icon icon={isShowCredit ? BadgeCent : CoinsIcon} />
218237
<AnimatedNumber
219-
formatter={(value) => (formatShortenNumber(value) as string).toLowerCase?.()}
238+
duration={1500}
239+
formatter={(value) => {
240+
const roundedValue = Math.round(value);
241+
if (isShortFormat) {
242+
return (formatShortenNumber(roundedValue) as string).toLowerCase?.();
243+
}
244+
return new Intl.NumberFormat('en-US').format(roundedValue);
245+
}}
220246
// Force remount when switching between token/credit to prevent unwanted animation
221247
// See: https://github.com/lobehub/lobe-chat/pull/10098
222248
key={isShowCredit ? 'credit' : 'token'}

src/store/global/initialState.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ export interface SystemStatus {
9999
* theme mode
100100
*/
101101
themeMode?: ThemeMode;
102+
/**
103+
* 是否使用短格式显示 token
104+
*/
105+
tokenDisplayFormatShort?: boolean;
102106
zenMode?: boolean;
103107
}
104108

@@ -151,6 +155,7 @@ export const INITIAL_STATUS = {
151155
showSystemRole: false,
152156
systemRoleExpandedMap: {},
153157
themeMode: 'auto',
158+
tokenDisplayFormatShort: true,
154159
zenMode: false,
155160
} satisfies SystemStatus;
156161

src/store/global/selectors/systemStatus.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ const getAgentSystemRoleExpanded =
6666
const disabledModelProvidersSortType = (s: GlobalState) =>
6767
s.status.disabledModelProvidersSortType || 'default';
6868
const disabledModelsSortType = (s: GlobalState) => s.status.disabledModelsSortType || 'default';
69+
const tokenDisplayFormatShort = (s: GlobalState) =>
70+
s.status.tokenDisplayFormatShort !== undefined ? s.status.tokenDisplayFormatShort : true;
6971

7072
export const systemStatusSelectors = {
7173
chatInputHeight,
@@ -99,5 +101,6 @@ export const systemStatusSelectors = {
99101
showSystemRole,
100102
systemStatus,
101103
themeMode,
104+
tokenDisplayFormatShort,
102105
wideScreen,
103106
};

0 commit comments

Comments
 (0)