chore(ui): remove dead props and their render chains

This commit is contained in:
Supra4E8C
2026-07-06 20:49:23 +08:00
parent 3785d759d0
commit 3c91d57357
14 changed files with 47 additions and 284 deletions
@@ -81,51 +81,3 @@
flex-direction: column;
gap: $spacing-lg;
}
.contentWithFloatingAction {
padding-bottom: calc(
var(--secondary-shell-floating-action-height, 56px) + 12px + env(safe-area-inset-bottom)
);
}
.floatingActionContainer {
position: fixed;
left: var(--content-center-x, 50%);
bottom: calc(12px + env(safe-area-inset-bottom));
transform: translateX(-50%);
z-index: 50;
pointer-events: none;
width: fit-content;
max-width: calc(100vw - 24px);
}
.floatingActionSurface {
pointer-events: auto;
display: inline-flex;
align-items: center;
gap: 8px;
padding: 10px 12px;
border-radius: 999px;
--glass-blur: 12px;
background: var(--glass-bg);
backdrop-filter: var(--glass-backdrop-filter);
-webkit-backdrop-filter: var(--glass-backdrop-filter);
border: 1px solid var(--glass-border);
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08);
}
:global([data-theme='dark']) {
.floatingActionSurface {
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.4);
}
}
@media (max-width: 1200px) {
.floatingActionContainer {
max-width: calc(100vw - 16px);
}
.floatingActionSurface {
padding: 8px 10px;
}
}
+32 -90
View File
@@ -1,9 +1,7 @@
import { forwardRef, useLayoutEffect, useRef, type ReactNode } from 'react';
import { createPortal } from 'react-dom';
import { forwardRef, type ReactNode } from 'react';
import { Button } from '@/components/ui/Button';
import { LoadingSpinner } from '@/components/ui/LoadingSpinner';
import { IconChevronLeft } from '@/components/ui/icons';
import { usePageTransitionLayer } from './PageTransitionLayer';
import styles from './SecondaryScreenShell.module.scss';
export type SecondaryScreenShellProps = {
@@ -12,9 +10,6 @@ export type SecondaryScreenShellProps = {
backLabel?: string;
backAriaLabel?: string;
rightAction?: ReactNode;
hideTopBarBackButton?: boolean;
hideTopBarRightAction?: boolean;
floatingAction?: ReactNode;
isLoading?: boolean;
loadingLabel?: ReactNode;
className?: string;
@@ -30,9 +25,6 @@ export const SecondaryScreenShell = forwardRef<HTMLDivElement, SecondaryScreenSh
backLabel = 'Back',
backAriaLabel,
rightAction,
hideTopBarBackButton = false,
hideTopBarRightAction = false,
floatingAction,
isLoading = false,
loadingLabel = 'Loading...',
className = '',
@@ -42,94 +34,44 @@ export const SecondaryScreenShell = forwardRef<HTMLDivElement, SecondaryScreenSh
ref
) {
const containerClassName = [styles.container, className].filter(Boolean).join(' ');
const contentClasses = [
styles.content,
floatingAction ? styles.contentWithFloatingAction : '',
contentClassName,
]
.filter(Boolean)
.join(' ');
const contentClasses = [styles.content, contentClassName].filter(Boolean).join(' ');
const titleTooltip = typeof title === 'string' ? title : undefined;
const resolvedBackAriaLabel = backAriaLabel ?? backLabel;
const pageTransitionLayer = usePageTransitionLayer();
const isCurrentLayer = pageTransitionLayer ? pageTransitionLayer.isCurrentLayer : true;
const shouldRenderFloatingAction = Boolean(floatingAction) && isCurrentLayer;
const floatingActionRef = useRef<HTMLDivElement | null>(null);
useLayoutEffect(() => {
if (!shouldRenderFloatingAction) return;
const element = floatingActionRef.current;
if (!element) return;
const updateHeight = () => {
const height = element.getBoundingClientRect().height;
document.documentElement.style.setProperty(
'--secondary-shell-floating-action-height',
`${height}px`
);
};
updateHeight();
window.addEventListener('resize', updateHeight);
const resizeObserver =
typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(updateHeight);
resizeObserver?.observe(element);
return () => {
resizeObserver?.disconnect();
window.removeEventListener('resize', updateHeight);
document.documentElement.style.removeProperty('--secondary-shell-floating-action-height');
};
}, [shouldRenderFloatingAction]);
return (
<>
<div className={containerClassName} ref={ref}>
<div className={styles.topBar}>
{onBack && !hideTopBarBackButton ? (
<Button
variant="ghost"
size="sm"
onClick={onBack}
className={styles.backButton}
aria-label={resolvedBackAriaLabel}
>
<span className={styles.backIcon}>
<IconChevronLeft size={18} />
</span>
<span className={styles.backText}>{backLabel}</span>
</Button>
) : (
<div />
)}
<div className={styles.topBarTitle} title={titleTooltip}>
{title}
</div>
<div className={styles.rightSlot}>{hideTopBarRightAction ? null : rightAction}</div>
</div>
{isLoading ? (
<div className={styles.loadingState}>
<LoadingSpinner size={16} />
<span>{loadingLabel}</span>
</div>
<div className={containerClassName} ref={ref}>
<div className={styles.topBar}>
{onBack ? (
<Button
variant="ghost"
size="sm"
onClick={onBack}
className={styles.backButton}
aria-label={resolvedBackAriaLabel}
>
<span className={styles.backIcon}>
<IconChevronLeft size={18} />
</span>
<span className={styles.backText}>{backLabel}</span>
</Button>
) : (
<div className={contentClasses}>{children}</div>
<div />
)}
<div className={styles.topBarTitle} title={titleTooltip}>
{title}
</div>
<div className={styles.rightSlot}>{rightAction}</div>
</div>
{shouldRenderFloatingAction && typeof document !== 'undefined'
? createPortal(
<div className={styles.floatingActionContainer}>
<div className={styles.floatingActionSurface} ref={floatingActionRef}>
{floatingAction}
</div>
</div>,
document.body
)
: null}
</>
{isLoading ? (
<div className={styles.loadingState}>
<LoadingSpinner size={16} />
<span>{loadingLabel}</span>
</div>
) : (
<div className={contentClasses}>{children}</div>
)}
</div>
);
}
);
+1 -5
View File
@@ -62,7 +62,6 @@ interface QuotaCardProps<TState extends QuotaStatusState> {
quota?: TState;
resolvedTheme: ResolvedTheme;
i18nPrefix: string;
cardIdleMessageKey?: string;
cardClassName: string;
defaultType: string;
canRefresh?: boolean;
@@ -76,7 +75,6 @@ export function QuotaCard<TState extends QuotaStatusState>({
quota,
resolvedTheme,
i18nPrefix,
cardIdleMessageKey,
cardClassName,
defaultType,
canRefresh = false,
@@ -98,9 +96,7 @@ export function QuotaCard<TState extends QuotaStatusState>({
quota?.errorStatus,
quota?.error || t('common.unknown_error')
);
const idleMessageKey = onRefresh
? `${i18nPrefix}.idle`
: (cardIdleMessageKey ?? `${i18nPrefix}.idle`);
const idleMessageKey = `${i18nPrefix}.idle`;
const getTypeLabel = (type: string): string => {
const key = `auth_files.filter_${type}`;
+3 -13
View File
@@ -37,15 +37,13 @@ interface QuotaPaginationState<T> {
goToPrev: () => void;
goToNext: () => void;
loading: boolean;
loadingScope: 'page' | 'all' | null;
setLoading: (loading: boolean, scope?: 'page' | 'all' | null) => void;
setLoading: (loading: boolean) => void;
}
const useQuotaPagination = <T,>(items: T[], defaultPageSize = 6): QuotaPaginationState<T> => {
const [page, setPage] = useState(1);
const [pageSize, setPageSizeState] = useState(defaultPageSize);
const [loading, setLoadingState] = useState(false);
const [loadingScope, setLoadingScope] = useState<'page' | 'all' | null>(null);
const [loading, setLoading] = useState(false);
const totalPages = useMemo(
() => Math.max(1, Math.ceil(items.length / pageSize)),
@@ -72,11 +70,6 @@ const useQuotaPagination = <T,>(items: T[], defaultPageSize = 6): QuotaPaginatio
setPage((prev) => Math.min(totalPages, prev + 1));
}, [totalPages]);
const setLoading = useCallback((isLoading: boolean, scope?: 'page' | 'all' | null) => {
setLoadingState(isLoading);
setLoadingScope(isLoading ? (scope ?? null) : null);
}, []);
return {
pageSize,
totalPages,
@@ -86,7 +79,6 @@ const useQuotaPagination = <T,>(items: T[], defaultPageSize = 6): QuotaPaginatio
goToPrev,
goToNext,
loading,
loadingScope,
setLoading,
};
};
@@ -182,10 +174,9 @@ export function QuotaSection<TState extends QuotaStatusState, TData>({
if (!wasLoading) return;
pendingQuotaRefreshRef.current = false;
const scope = effectiveViewMode === 'all' ? 'all' : 'page';
const targets = effectiveViewMode === 'all' ? filteredFiles : pageItems;
if (targets.length === 0) return;
loadQuota(targets, scope, setLoading);
loadQuota(targets, setLoading);
}, [loading, effectiveViewMode, filteredFiles, pageItems, loadQuota, setLoading]);
useEffect(() => {
@@ -373,7 +364,6 @@ export function QuotaSection<TState extends QuotaStatusState, TData>({
quota={itemQuota}
resolvedTheme={resolvedTheme}
i18nPrefix={config.i18nPrefix}
cardIdleMessageKey={config.cardIdleMessageKey}
cardClassName={config.cardClassName}
defaultType={config.type}
canRefresh={canUseQuotaAction && !isResettingQuota}
-18
View File
@@ -128,7 +128,6 @@ export interface QuotaStore {
export interface QuotaConfig<TState, TData> {
type: QuotaType;
i18nPrefix: string;
cardIdleMessageKey?: string;
filterFn: (file: AuthFileItem) => boolean;
fetchQuota: (file: AuthFileItem, t: TFunction) => Promise<TData>;
resetQuota?: (file: AuthFileItem, t: TFunction) => Promise<TData>;
@@ -139,8 +138,6 @@ export interface QuotaConfig<TState, TData> {
buildSuccessState: (data: TData) => TState;
buildErrorState: (message: string, status?: number) => TState;
cardClassName: string;
controlsClassName: string;
controlClassName: string;
gridClassName: string;
renderQuotaItems: (quota: TState, t: TFunction, helpers: QuotaRenderHelpers) => ReactNode;
}
@@ -1263,7 +1260,6 @@ export const CLAUDE_CONFIG: QuotaConfig<
> = {
type: 'claude',
i18nPrefix: 'claude_quota',
cardIdleMessageKey: 'quota_management.card_idle_hint',
filterFn: (file) => isClaudeFile(file) && !isDisabledAuthFile(file),
fetchQuota: fetchClaudeQuota,
storeSelector: (state) => state.claudeQuota,
@@ -1282,8 +1278,6 @@ export const CLAUDE_CONFIG: QuotaConfig<
errorStatus: status,
}),
cardClassName: styles.claudeCard,
controlsClassName: styles.claudeControls,
controlClassName: styles.claudeControl,
gridClassName: styles.claudeGrid,
renderQuotaItems: renderClaudeItems,
};
@@ -1291,7 +1285,6 @@ export const CLAUDE_CONFIG: QuotaConfig<
export const ANTIGRAVITY_CONFIG: QuotaConfig<AntigravityQuotaState, AntigravityQuotaData> = {
type: 'antigravity',
i18nPrefix: 'antigravity_quota',
cardIdleMessageKey: 'quota_management.card_idle_hint',
filterFn: (file) => isAntigravityFile(file) && !isDisabledAuthFile(file),
fetchQuota: fetchAntigravityQuota,
storeSelector: (state) => state.antigravityQuota,
@@ -1317,8 +1310,6 @@ export const ANTIGRAVITY_CONFIG: QuotaConfig<AntigravityQuotaState, AntigravityQ
errorStatus: status,
}),
cardClassName: styles.antigravityCard,
controlsClassName: styles.antigravityControls,
controlClassName: styles.antigravityControl,
gridClassName: styles.antigravityGrid,
renderQuotaItems: renderAntigravityItems,
};
@@ -1326,7 +1317,6 @@ export const ANTIGRAVITY_CONFIG: QuotaConfig<AntigravityQuotaState, AntigravityQ
export const CODEX_CONFIG: QuotaConfig<CodexQuotaState, CodexQuotaData> = {
type: 'codex',
i18nPrefix: 'codex_quota',
cardIdleMessageKey: 'quota_management.card_idle_hint',
filterFn: (file) => isCodexFile(file) && !isDisabledAuthFile(file),
fetchQuota: fetchCodexQuota,
resetQuota: resetCodexQuota,
@@ -1357,8 +1347,6 @@ export const CODEX_CONFIG: QuotaConfig<CodexQuotaState, CodexQuotaData> = {
errorStatus: status,
}),
cardClassName: styles.codexCard,
controlsClassName: styles.codexControls,
controlClassName: styles.codexControl,
gridClassName: styles.codexGrid,
renderQuotaItems: renderCodexItems,
};
@@ -1674,7 +1662,6 @@ const renderXaiItems = (
export const KIMI_CONFIG: QuotaConfig<KimiQuotaState, KimiQuotaRow[]> = {
type: 'kimi',
i18nPrefix: 'kimi_quota',
cardIdleMessageKey: 'quota_management.card_idle_hint',
filterFn: (file) => isKimiFile(file) && !isDisabledAuthFile(file),
fetchQuota: fetchKimiQuota,
storeSelector: (state) => state.kimiQuota,
@@ -1688,8 +1675,6 @@ export const KIMI_CONFIG: QuotaConfig<KimiQuotaState, KimiQuotaRow[]> = {
errorStatus: status,
}),
cardClassName: styles.kimiCard,
controlsClassName: styles.kimiControls,
controlClassName: styles.kimiControl,
gridClassName: styles.kimiGrid,
renderQuotaItems: renderKimiItems,
};
@@ -1697,7 +1682,6 @@ export const KIMI_CONFIG: QuotaConfig<KimiQuotaState, KimiQuotaRow[]> = {
export const XAI_CONFIG: QuotaConfig<XaiQuotaState, XaiBillingSummary> = {
type: 'xai',
i18nPrefix: 'xai_quota',
cardIdleMessageKey: 'quota_management.card_idle_hint',
filterFn: (file) => isXaiFile(file) && !isDisabledAuthFile(file),
fetchQuota: fetchXaiQuota,
storeSelector: (state) => state.xaiQuota,
@@ -1711,8 +1695,6 @@ export const XAI_CONFIG: QuotaConfig<XaiQuotaState, XaiBillingSummary> = {
errorStatus: status,
}),
cardClassName: styles.xaiCard,
controlsClassName: styles.xaiControls,
controlClassName: styles.xaiControl,
gridClassName: styles.xaiGrid,
renderQuotaItems: renderXaiItems,
};
+2 -8
View File
@@ -9,8 +9,6 @@ import { useQuotaStore } from '@/stores';
import { getStatusFromError } from '@/utils/quota';
import type { QuotaConfig } from './quotaConfigs';
type QuotaScope = 'page' | 'all';
type QuotaUpdater<T> = T | ((prev: T) => T);
type QuotaSetter<T> = (updater: QuotaUpdater<T>) => void;
@@ -34,15 +32,11 @@ export function useQuotaLoader<TState, TData>(config: QuotaConfig<TState, TData>
const requestIdRef = useRef(0);
const loadQuota = useCallback(
async (
targets: AuthFileItem[],
scope: QuotaScope,
setLoading: (loading: boolean, scope?: QuotaScope | null) => void
) => {
async (targets: AuthFileItem[], setLoading: (loading: boolean) => void) => {
if (loadingRef.current) return;
loadingRef.current = true;
const requestId = ++requestIdRef.current;
setLoading(true, scope);
setLoading(true);
try {
if (targets.length === 0) return;
@@ -257,29 +257,22 @@ export function ProvidersWorkbenchPage({ fixedBrand }: ProvidersWorkbenchPagePro
]);
const totalResources = useMemo(
() =>
groups.reduce((sum, g) => sum + g.resources.filter((r) => !r.flags.isPlaceholder).length, 0),
() => groups.reduce((sum, g) => sum + g.resources.length, 0),
[groups]
);
const totalActive = useMemo(
() =>
groups.reduce(
(sum, g) => sum + g.resources.filter((r) => !r.disabled && !r.flags.isPlaceholder).length,
0
),
() => groups.reduce((sum, g) => sum + g.resources.filter((r) => !r.disabled).length, 0),
[groups]
);
const providerFamilies = useMemo(
() => groups.filter((g) => g.resources.some((r) => !r.flags.isPlaceholder)).length,
() => groups.filter((g) => g.resources.length > 0).length,
[groups]
);
const quickStartResource = useMemo(
() =>
fixedBrand === 'apikeyFun' && activeGroup
? (activeGroup.resources.find((r) => !r.flags.isPlaceholder) ?? null)
: null,
fixedBrand === 'apikeyFun' && activeGroup ? (activeGroup.resources[0] ?? null) : null,
[activeGroup, fixedBrand]
);
@@ -21,9 +21,8 @@ export function ProviderCategoryList({ groups, activeBrand, onSelect }: Provider
<div className={styles.list}>
{items.map((group) => {
const active = group.id === activeBrand;
const realResources = group.resources.filter((r) => !r.flags.isPlaceholder);
const total = realResources.length;
const activeCount = realResources.filter((r) => !r.disabled).length;
const total = group.resources.length;
const activeCount = group.resources.filter((r) => !r.disabled).length;
const logo = PROVIDER_LOGOS[group.id];
const itemClass = `${styles.item} ${active ? styles.active : ''}`;
const logoClassName = [
@@ -55,7 +55,7 @@ export function ProviderResourcePanel({
const { t } = useTranslation();
const logo = PROVIDER_LOGOS[group.id];
const providerTitle = t(`providersPage.providerNames.${group.id}`);
const hasProviderInfo = group.resources.some((r) => !r.flags.isPlaceholder);
const hasProviderInfo = group.resources.length > 0;
const showSponsorRegistrationLink = group.id === 'apikeyFun' && !hasProviderInfo;
const showSponsorDashboardLink = group.id === 'apikeyFun' && hasProviderInfo;
const showClaudeApiSponsorLink = group.id === 'claudeApi';
@@ -77,7 +77,6 @@ export function ProviderResourcePanel({
.join(' ');
const darkLogoClassName = [styles.logo, styles.logoThemeDark].filter(Boolean).join(' ');
const realResources = filteredResources.filter((r) => !r.flags.isPlaceholder);
const titleContent = (
<>
{logo ? (
@@ -168,7 +167,7 @@ export function ProviderResourcePanel({
) : null}
</div>
{realResources.length === 0 ? (
{filteredResources.length === 0 ? (
<div className={styles.empty}>
<div>{emptyText}</div>
<div className={styles.emptyAction}>
@@ -173,7 +173,7 @@ export function ProviderSheet({
const footer =
state.mode === 'detail' ? (
state.resource && !state.resource.flags.isPlaceholder ? (
state.resource ? (
<>
<button
type="button"
-1
View File
@@ -47,7 +47,6 @@ export type ProviderResourceSelector =
export interface ProviderResourceFlags {
cloakEnabled?: boolean;
websockets?: boolean;
isPlaceholder?: boolean;
protocols?: string[];
}
-42
View File
@@ -435,48 +435,6 @@
}
}
.antigravityControls {
display: flex;
gap: $spacing-md;
flex-wrap: wrap;
align-items: flex-end;
margin-bottom: $spacing-md;
}
.antigravityControl {
display: flex;
flex-direction: column;
gap: 4px;
label {
font-size: 12px;
color: var(--text-secondary);
font-weight: 500;
white-space: nowrap;
}
}
.codexControls {
display: flex;
gap: $spacing-md;
flex-wrap: wrap;
align-items: flex-end;
margin-bottom: $spacing-md;
}
.codexControl {
display: flex;
flex-direction: column;
gap: 4px;
label {
font-size: 12px;
color: var(--text-secondary);
font-weight: 500;
white-space: nowrap;
}
}
// 卡片渐变背景 — subtle tint only
.antigravityCard {
background-image: linear-gradient(180deg, rgba(224, 247, 250, 0.06), transparent);
-12
View File
@@ -54,8 +54,6 @@ interface BuiltInOAuthProviderCard {
kind: 'builtin';
id: BuiltInOAuthProvider;
titleKey: string;
hintKey: string;
urlLabelKey: string;
icon: string | { light: string; dark: string };
}
@@ -78,40 +76,30 @@ const PROVIDERS: BuiltInOAuthProviderCard[] = [
kind: 'builtin',
id: 'codex',
titleKey: 'auth_login.codex_oauth_title',
hintKey: 'auth_login.codex_oauth_hint',
urlLabelKey: 'auth_login.codex_oauth_url_label',
icon: iconCodex,
},
{
kind: 'builtin',
id: 'anthropic',
titleKey: 'auth_login.anthropic_oauth_title',
hintKey: 'auth_login.anthropic_oauth_hint',
urlLabelKey: 'auth_login.anthropic_oauth_url_label',
icon: iconClaude,
},
{
kind: 'builtin',
id: 'antigravity',
titleKey: 'auth_login.antigravity_oauth_title',
hintKey: 'auth_login.antigravity_oauth_hint',
urlLabelKey: 'auth_login.antigravity_oauth_url_label',
icon: iconAntigravity,
},
{
kind: 'builtin',
id: 'kimi',
titleKey: 'auth_login.kimi_oauth_title',
hintKey: 'auth_login.kimi_oauth_hint',
urlLabelKey: 'auth_login.kimi_oauth_url_label',
icon: { light: iconKimiLight, dark: iconKimiDark },
},
{
kind: 'builtin',
id: 'xai',
titleKey: 'auth_login.xai_oauth_title',
hintKey: 'auth_login.xai_oauth_hint',
urlLabelKey: 'auth_login.xai_oauth_url_label',
icon: { light: iconGrok, dark: iconGrokDark },
},
];
-29
View File
@@ -124,35 +124,6 @@
}
}
.antigravityControls,
.claudeControls,
.codexControls,
.kimiControls,
.xaiControls {
display: flex;
gap: $spacing-md;
flex-wrap: wrap;
align-items: flex-end;
margin-bottom: $spacing-md;
}
.antigravityControl,
.claudeControl,
.codexControl,
.kimiControl,
.xaiControl {
display: flex;
flex-direction: column;
gap: 4px;
label {
font-size: 12px;
color: var(--text-secondary);
font-weight: 500;
white-space: nowrap;
}
}
.viewModeToggle {
display: inline-flex;
gap: $spacing-xs;