mirror of
https://github.com/router-for-me/Cli-Proxy-API-Management-Center.git
synced 2026-08-31 02:05:31 +08:00
chore(ui): remove dead props and their render chains
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -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}`;
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -47,7 +47,6 @@ export type ProviderResourceSelector =
|
||||
export interface ProviderResourceFlags {
|
||||
cloakEnabled?: boolean;
|
||||
websockets?: boolean;
|
||||
isPlaceholder?: boolean;
|
||||
protocols?: string[];
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 },
|
||||
},
|
||||
];
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user