diff --git a/src/pages/RightClickRestorer/__tests__/index.test.tsx b/src/pages/RightClickRestorer/__tests__/index.test.tsx index f74b947..2ca97b1 100644 --- a/src/pages/RightClickRestorer/__tests__/index.test.tsx +++ b/src/pages/RightClickRestorer/__tests__/index.test.tsx @@ -8,8 +8,7 @@ vi.mock('../useRightClickRestorer', () => ({ useRightClickRestorer: () => ({ domain: 'example.com', isLoading: false, - isUnlocked: false, - isUnsupported: false, + status: 'locked', unlock: mockUnlock, }), })); diff --git a/src/pages/RightClickRestorer/__tests__/useRightClickRestorer.test.ts b/src/pages/RightClickRestorer/__tests__/useRightClickRestorer.test.ts index 929051e..51fbf30 100644 --- a/src/pages/RightClickRestorer/__tests__/useRightClickRestorer.test.ts +++ b/src/pages/RightClickRestorer/__tests__/useRightClickRestorer.test.ts @@ -26,8 +26,7 @@ describe('useRightClickRestorer', () => { await waitFor(() => expect(result.current.isLoading).toBe(false)); expect(result.current.domain).toBe('example.com'); - expect(result.current.isUnlocked).toBe(false); - expect(result.current.isUnsupported).toBe(false); + expect(result.current.status).toBe('locked'); expect(sendMessageToContent).toHaveBeenCalledWith('queryRightClickStatus'); }); @@ -39,8 +38,7 @@ describe('useRightClickRestorer', () => { await waitFor(() => expect(result.current.isLoading).toBe(false)); - expect(result.current.isUnsupported).toBe(true); - expect(result.current.isUnlocked).toBe(false); + expect(result.current.status).toBe('unsupported'); expect(sendMessageToContent).not.toHaveBeenCalled(); }); @@ -56,7 +54,7 @@ describe('useRightClickRestorer', () => { await result.current.unlock(); }); - expect(result.current.isUnlocked).toBe(true); + expect(result.current.status).toBe('unlocked'); expect(sendMessageToContent).toHaveBeenLastCalledWith('restoreRightClick'); }); @@ -72,7 +70,7 @@ describe('useRightClickRestorer', () => { await result.current.unlock(); }); - expect(result.current.isUnlocked).toBe(false); + expect(result.current.status).toBe('unsupported'); expect(sendMessageToContent).not.toHaveBeenCalled(); }); @@ -87,6 +85,6 @@ describe('useRightClickRestorer', () => { await result.current.unlock(); }); - expect(result.current.isUnlocked).toBe(false); + expect(result.current.status).toBe('locked'); }); }); diff --git a/src/pages/RightClickRestorer/constants.ts b/src/pages/RightClickRestorer/constants.ts new file mode 100644 index 0000000..5474777 --- /dev/null +++ b/src/pages/RightClickRestorer/constants.ts @@ -0,0 +1,59 @@ +import type { LucideIcon } from 'lucide-react'; +import { AlertTriangle, MousePointerClick, Shield, ShieldCheck } from 'lucide-react'; + +export type RestorerStatus = 'unsupported' | 'locked' | 'unlocked'; + +export const CARD_CLASS = + 'w-full p-4 rounded-xl border border-border bg-card text-card-foreground shadow-sm overflow-hidden space-y-3'; + +export const LOADING_TEXT = '正在加载...'; + +export const DOMAIN_LABEL = '当前域名'; + +interface StatusConfig { + badgeVariant: 'default' | 'secondary' | 'destructive'; + badgeClassName: string; + badgeIcon: LucideIcon; + badgeLabel: string; + description: string; + buttonIcon: LucideIcon; + buttonLabel: string; + buttonDisabled: boolean; + buttonVariant: 'default' | 'secondary'; +} + +export const STATUS_CONFIG: Record = { + unsupported: { + badgeVariant: 'destructive', + badgeClassName: 'gap-1 shrink-0', + badgeIcon: AlertTriangle, + badgeLabel: '不支持', + description: '当前页面为浏览器内部页面或扩展页面,无法解锁右键功能。请切换到普通网页后重试。', + buttonIcon: AlertTriangle, + buttonLabel: '不支持', + buttonDisabled: true, + buttonVariant: 'secondary', + }, + locked: { + badgeVariant: 'secondary', + badgeClassName: 'gap-1 shrink-0', + badgeIcon: Shield, + badgeLabel: '未解锁', + description: '点击下方按钮,为当前网站临时解锁右键菜单。刷新页面后需要重新解锁。', + buttonIcon: MousePointerClick, + buttonLabel: '解锁当前网站右键', + buttonDisabled: false, + buttonVariant: 'default', + }, + unlocked: { + badgeVariant: 'default', + badgeClassName: 'gap-1 bg-green-600 hover:bg-green-700 shrink-0', + badgeIcon: ShieldCheck, + badgeLabel: '已解锁', + description: '点击下方按钮,为当前网站临时解锁右键菜单。刷新页面后需要重新解锁。', + buttonIcon: MousePointerClick, + buttonLabel: '右键已解锁', + buttonDisabled: true, + buttonVariant: 'secondary', + }, +}; diff --git a/src/pages/RightClickRestorer/index.tsx b/src/pages/RightClickRestorer/index.tsx index 61a2540..97121fc 100644 --- a/src/pages/RightClickRestorer/index.tsx +++ b/src/pages/RightClickRestorer/index.tsx @@ -1,82 +1,52 @@ import { Button } from '@/components/ui/button'; import { Label } from '@/components/ui/label'; import { Badge } from '@/components/ui/badge'; -import { Shield, ShieldCheck, MousePointerClick, AlertTriangle } from 'lucide-react'; +import { Loader2 } from 'lucide-react'; +import { CARD_CLASS, DOMAIN_LABEL, LOADING_TEXT, STATUS_CONFIG } from './constants'; import { useRightClickRestorer } from './useRightClickRestorer'; export default function Index() { - const { domain, isLoading, isUnlocked, isUnsupported, unlock } = useRightClickRestorer(); + const { domain, isLoading, status, unlock } = useRightClickRestorer(); if (isLoading) { return (
+ - {'正在加载...'} + {LOADING_TEXT}
); } + const config = STATUS_CONFIG[status]; + const BadgeIcon = config.badgeIcon; + const ButtonIcon = config.buttonIcon; + return (
- {/* Current Domain */} -
-
- -
- - {domain || '—'} - - {isUnsupported ? ( - - - {'不支持'} - - ) : isUnlocked ? ( - - - {'已解锁'} - - ) : ( - - - {'未解锁'} - - )} -
+
+ +
+ + {domain || '—'} + + + + {config.badgeLabel} +
-
- {/* Unlock Action */} -
-
- {isUnsupported ? ( - <> -

- {'当前页面为浏览器内部页面或扩展页面,无法解锁右键功能。请切换到普通网页后重试。'} -

- - - ) : ( - <> -

- {'点击下方按钮,为当前网站临时解锁右键菜单。刷新页面后需要重新解锁。'} -

- - - )} -
+

{config.description}

+
); diff --git a/src/pages/RightClickRestorer/useRightClickRestorer.ts b/src/pages/RightClickRestorer/useRightClickRestorer.ts index b215743..5e56912 100644 --- a/src/pages/RightClickRestorer/useRightClickRestorer.ts +++ b/src/pages/RightClickRestorer/useRightClickRestorer.ts @@ -1,5 +1,6 @@ import { useEffect, useState } from 'react'; import { MessageAction, sendMessageToContent } from '@/utils/messages'; +import type { RestorerStatus } from './constants'; const UNSUPPORTED_PROTOCOLS = new Set([ 'chrome:', @@ -19,11 +20,15 @@ function isUnsupportedPage(url: string | undefined): boolean { } } +function deriveStatus(isUnsupported: boolean, isUnlocked: boolean): RestorerStatus { + if (isUnsupported) return 'unsupported'; + return isUnlocked ? 'unlocked' : 'locked'; +} + export interface UseRightClickRestorerReturn { domain: string; isLoading: boolean; - isUnlocked: boolean; - isUnsupported: boolean; + status: RestorerStatus; unlock: () => Promise; } @@ -76,8 +81,7 @@ export function useRightClickRestorer(): UseRightClickRestorerReturn { return { domain, isLoading, - isUnlocked, - isUnsupported, + status: deriveStatus(isUnsupported, isUnlocked), unlock, }; }