返回 AiToEarn
index.tsx
1 /**
2 * PluginReady - 插件已就绪状态组件
3 * 使用左侧 Tab 导航布局,包含平台账号和发布列表两个 Tab
4 */
5
6 'use client'
7
8 import type { PublishTask } from '@/store/plugin/types/baseTypes'
9 import { ListTodo, Users } from 'lucide-react'
10 import { useState } from 'react'
11 import { useTranslation } from 'react-i18next'
12 import { useShallow } from 'zustand/react/shallow'
13 import { Badge } from '@/components/ui/badge'
14 import { usePluginStore } from '@/store/plugin'
15 import { cn } from '@/utils/className'
16 import { PluginUpdatePopover } from '../PluginUpdatePopover'
17 import { AccountsTab } from './AccountsTab'
18 import { PublishListTab } from './PublishListTab'
19
20 type TabType = 'accounts' | 'publish'
21
22 interface PluginReadyProps {
23 /** 需要高亮的平台 */
24 highlightPlatform?: string | null
25 /** 点击任务详情回调 */
26 onViewDetail?: (task: PublishTask) => void
27 }
28
29 /**
30 * Tab 配置
31 */
32 const tabs = [
33 { id: 'accounts' as const, icon: Users, labelKey: 'header.platformAccounts' },
34 { id: 'publish' as const, icon: ListTodo, labelKey: 'publishList.title' },
35 ]
36
37 /**
38 * 插件已就绪状态组件
39 */
40 export function PluginReady({ highlightPlatform, onViewDetail }: PluginReadyProps) {
41 const { t } = useTranslation('plugin')
42 const [activeTab, setActiveTab] = useState<TabType>('accounts')
43 const { pluginNeedsUpdate, pluginVersion } = usePluginStore(
44 useShallow(state => ({
45 pluginNeedsUpdate: state.pluginNeedsUpdate,
46 pluginVersion: state.pluginVersion,
47 })),
48 )
49
50 return (
51 <div className="flex h-[420px] flex-1 flex-col">
52 <div className="flex min-h-0 flex-1">
53 <div className="flex w-40 shrink-0 flex-col gap-1 border-r border-border pr-4">
54 {tabs.map((tab) => {
55 const Icon = tab.icon
56 const isActive = activeTab === tab.id
57
58 return (
59 <button
60 key={tab.id}
61 onClick={() => setActiveTab(tab.id)}
62 className={cn(
63 'flex cursor-pointer items-center gap-2 rounded-md px-3 py-2.5 text-left text-sm transition-all',
64 isActive
65 ? 'bg-purple-50 font-medium text-purple-600'
66 : 'text-muted-foreground hover:bg-accent hover:text-foreground',
67 )}
68 >
69 <Icon className="h-4 w-4" />
70 {t(tab.labelKey)}
71 </button>
72 )
73 })}
74 </div>
75
76 <div className="flex min-w-0 flex-1 pl-4">
77 <div className="flex min-h-0 flex-1 flex-col">
78 <div className="min-h-0 flex-1 overflow-auto">
79 {activeTab === 'accounts' && <AccountsTab highlightPlatform={highlightPlatform} />}
80 {activeTab === 'publish' && <PublishListTab onViewDetail={onViewDetail} />}
81 </div>
82
83 {pluginVersion && (
84 <div className="mt-3 flex flex-wrap items-center justify-end gap-2 text-xs">
85 {pluginNeedsUpdate ? (
86 <PluginUpdatePopover currentVersion={pluginVersion}>
87 <button
88 type="button"
89 className="inline-flex cursor-pointer items-center rounded-full border border-warning/20 bg-warning/10 px-3 py-1 text-xs font-medium text-warning transition-colors hover:bg-warning/15"
90 >
91 {t('version.updatableTag')}
92 </button>
93 </PluginUpdatePopover>
94 ) : (
95 <Badge
96 variant="outline"
97 className="rounded-full border-success/20 bg-success/10 px-3 py-1 text-xs font-medium text-success"
98 >
99 {t('version.title')}
100 {' '}
101 {pluginVersion}
102 </Badge>
103 )}
104 </div>
105 )}
106 </div>
107 </div>
108 </div>
109 </div>
110 )
111 }
112
112 lines Plain Text