@yancyyu/openhermit 1.6.37 → 1.6.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-renderer/assets/ProjectEditorOverlay-krO5vQxX.js +58 -0
- package/dist-renderer/assets/{TeamGraphOverlay-DYT3bwFR.js → TeamGraphOverlay-DqhQzcTr.js} +1 -1
- package/dist-renderer/assets/{_basePickBy-Dbt_EU-e.js → _basePickBy-B7kSYPxr.js} +1 -1
- package/dist-renderer/assets/{_baseUniq-DWo68sXI.js → _baseUniq-CnjxqwAk.js} +1 -1
- package/dist-renderer/assets/{arc-DXH1iZQK.js → arc-CLeZuINP.js} +1 -1
- package/dist-renderer/assets/{architectureDiagram-VXUJARFQ-cjffS2Qr.js → architectureDiagram-VXUJARFQ-QKtqaqdY.js} +1 -1
- package/dist-renderer/assets/{blockDiagram-VD42YOAC-BKdZF02Y.js → blockDiagram-VD42YOAC-BqdrzO_f.js} +1 -1
- package/dist-renderer/assets/{c4Diagram-YG6GDRKO-CN27pqaI.js → c4Diagram-YG6GDRKO-gwPlCxDC.js} +1 -1
- package/dist-renderer/assets/channel-DpMHF50r.js +1 -0
- package/dist-renderer/assets/{chunk-4BX2VUAB-CXPCI7g_.js → chunk-4BX2VUAB-C6XLurL4.js} +1 -1
- package/dist-renderer/assets/{chunk-55IACEB6-BGAXQZRC.js → chunk-55IACEB6-Ds6quhEP.js} +1 -1
- package/dist-renderer/assets/{chunk-B4BG7PRW-TPDaA_KQ.js → chunk-B4BG7PRW-5UlA1_e9.js} +1 -1
- package/dist-renderer/assets/{chunk-DI55MBZ5-D1ADe_tq.js → chunk-DI55MBZ5-ywFrqIsY.js} +1 -1
- package/dist-renderer/assets/{chunk-FMBD7UC4-Beimtg3a.js → chunk-FMBD7UC4-C7ifUA17.js} +1 -1
- package/dist-renderer/assets/{chunk-QN33PNHL-OjNBu854.js → chunk-QN33PNHL-BxGCo80U.js} +1 -1
- package/dist-renderer/assets/{chunk-QZHKN3VN-DinqvbH8.js → chunk-QZHKN3VN-B2CuaZs6.js} +1 -1
- package/dist-renderer/assets/{chunk-TZMSLE5B-BfFtlPSZ.js → chunk-TZMSLE5B-Ds1hInvp.js} +1 -1
- package/dist-renderer/assets/classDiagram-2ON5EDUG-CBYCBVRl.js +1 -0
- package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-CBYCBVRl.js +1 -0
- package/dist-renderer/assets/clone-DcMF6Psb.js +1 -0
- package/dist-renderer/assets/{cose-bilkent-S5V4N54A-D9z9Dgt7.js → cose-bilkent-S5V4N54A-Cz1GVtLp.js} +1 -1
- package/dist-renderer/assets/{dagre-6UL2VRFP-n1g-DhEE.js → dagre-6UL2VRFP-BrmR-P4h.js} +1 -1
- package/dist-renderer/assets/{diagram-PSM6KHXK-BvxFq-BE.js → diagram-PSM6KHXK-DbNjC5Rg.js} +1 -1
- package/dist-renderer/assets/{diagram-QEK2KX5R-wVnJuwza.js → diagram-QEK2KX5R-qkRX5_Mq.js} +1 -1
- package/dist-renderer/assets/{diagram-S2PKOQOG-B707WJQw.js → diagram-S2PKOQOG-CyL5rCv2.js} +1 -1
- package/dist-renderer/assets/{erDiagram-Q2GNP2WA-C-_1dGHs.js → erDiagram-Q2GNP2WA-Dox3-bA5.js} +1 -1
- package/dist-renderer/assets/{flowDiagram-NV44I4VS-CMTSi3H6.js → flowDiagram-NV44I4VS-BtkaxlDL.js} +1 -1
- package/dist-renderer/assets/{ganttDiagram-JELNMOA3-DZ0bNrAA.js → ganttDiagram-JELNMOA3-Dhy_d9GK.js} +1 -1
- package/dist-renderer/assets/{gitGraphDiagram-V2S2FVAM-DNVfGooQ.js → gitGraphDiagram-V2S2FVAM-B5XRhIQA.js} +1 -1
- package/dist-renderer/assets/{graph-865j_tM_.js → graph-CsoEwUhS.js} +1 -1
- package/dist-renderer/assets/{index-C_F9N5x-.js → index-BWPWmJNo.js} +1 -1
- package/dist-renderer/assets/{index-LwDIsXJN.js → index-Bu2R-Se7.js} +586 -740
- package/dist-renderer/assets/index-CnWV3BhG.css +32 -0
- package/dist-renderer/assets/{index-DuUaf8at.js → index-D-3KgskL.js} +1 -1
- package/dist-renderer/assets/{index-BTx1nc4T.js → index-DGEBzLNT.js} +1 -1
- package/dist-renderer/assets/{index-2EW-eu3q.js → index-NhHNs2Oo.js} +1 -1
- package/dist-renderer/assets/{index-4dEMStJj.js → index-h17WuEyf.js} +1 -1
- package/dist-renderer/assets/{infoDiagram-HS3SLOUP-CyqtElLq.js → infoDiagram-HS3SLOUP-hMGmNojH.js} +1 -1
- package/dist-renderer/assets/{journeyDiagram-XKPGCS4Q-BvjQ0Hm0.js → journeyDiagram-XKPGCS4Q-DXV2rBDl.js} +1 -1
- package/dist-renderer/assets/{kanban-definition-3W4ZIXB7-CJJ-k0zT.js → kanban-definition-3W4ZIXB7-Bf99WLRy.js} +1 -1
- package/dist-renderer/assets/{layout-CnV6rQAG.js → layout-C3XWrpwo.js} +1 -1
- package/dist-renderer/assets/{linear-Cw3UQgyX.js → linear-OEEcn8KN.js} +1 -1
- package/dist-renderer/assets/{mindmap-definition-VGOIOE7T-C5tDaGSK.js → mindmap-definition-VGOIOE7T-Dpi3S2x4.js} +1 -1
- package/dist-renderer/assets/{pieDiagram-ADFJNKIX-CiIpPsau.js → pieDiagram-ADFJNKIX-xTPPhtNx.js} +1 -1
- package/dist-renderer/assets/{quadrantDiagram-AYHSOK5B-C3gtowNj.js → quadrantDiagram-AYHSOK5B-euniyDlz.js} +1 -1
- package/dist-renderer/assets/{requirementDiagram-UZGBJVZJ-CXBTrAnU.js → requirementDiagram-UZGBJVZJ-D9Uiw4kF.js} +1 -1
- package/dist-renderer/assets/{sankeyDiagram-TZEHDZUN-wziX77xG.js → sankeyDiagram-TZEHDZUN-CySU4nED.js} +1 -1
- package/dist-renderer/assets/{sequenceDiagram-WL72ISMW-sYqopcrj.js → sequenceDiagram-WL72ISMW-JVGpET6V.js} +1 -1
- package/dist-renderer/assets/splashScene-D0YB9uxm.js +17 -0
- package/dist-renderer/assets/{stateDiagram-FKZM4ZOC-Bl1-0_Cp.js → stateDiagram-FKZM4ZOC-B2FY5qqi.js} +1 -1
- package/dist-renderer/assets/stateDiagram-v2-4FDKWEC3-DcoMiR8H.js +1 -0
- package/dist-renderer/assets/{timeline-definition-IT6M3QCI-CIRjJUBo.js → timeline-definition-IT6M3QCI-DmycNUUe.js} +1 -1
- package/dist-renderer/assets/{treemap-GDKQZRPO-CVPuNe1n.js → treemap-GDKQZRPO-DPq4gZuB.js} +1 -1
- package/dist-renderer/assets/{xychartDiagram-PRI3JC2R-3nT9yHwp.js → xychartDiagram-PRI3JC2R-J6VVJzRq.js} +1 -1
- package/dist-renderer/index.html +20 -53
- package/package.json +25 -18
- package/src/main/ipc/extensions.ts +30 -50
- package/src/main/server.ts +890 -247
- package/src/main/services/extensions/ExtensionFacadeService.ts +4 -56
- package/src/main/services/extensions/catalog/PluginCatalogService.ts +4 -2
- package/src/main/services/extensions/library/McpLibraryService.ts +243 -0
- package/src/main/services/session-intelligence/ConversationTelemetryService.ts +1101 -0
- package/src/main/services/session-intelligence/LocalSessionScanner.ts +512 -0
- package/src/main/services/session-intelligence/SessionUsageParser.ts +4 -4
- package/src/main/services/session-intelligence/UsageTelemetryService.ts +14 -1
- package/src/main/services/system-manager/SystemManagerConfigService.ts +122 -0
- package/src/main/services/system-manager/SystemManagerPtyService.ts +233 -0
- package/src/main/services/system-manager/WorkflowPromptService.ts +75 -0
- package/src/main/services/teams-mvp/TaskDispatchService.ts +32 -8
- package/src/main/services/teams-mvp/TeamProvisioningService.ts +39 -2
- package/src/main/services/teams-mvp/TeamWorkspaceService.ts +22 -4
- package/src/main/utils/teamProjectResolution.ts +15 -0
- package/src/renderer/App.tsx +8 -4
- package/src/renderer/api/httpClient.ts +174 -38
- package/src/renderer/api/providers.ts +23 -2
- package/src/renderer/assets/participant-avatars/01.svg +3 -0
- package/src/renderer/assets/participant-avatars/02.svg +3 -0
- package/src/renderer/assets/participant-avatars/03.svg +3 -0
- package/src/renderer/assets/participant-avatars/04.svg +3 -0
- package/src/renderer/assets/participant-avatars/05.svg +3 -0
- package/src/renderer/assets/participant-avatars/06.svg +3 -0
- package/src/renderer/assets/participant-avatars/07.svg +3 -0
- package/src/renderer/assets/participant-avatars/08.svg +3 -0
- package/src/renderer/assets/participant-avatars/09.svg +3 -0
- package/src/renderer/assets/participant-avatars/10.svg +3 -0
- package/src/renderer/assets/participant-avatars/11.svg +3 -0
- package/src/renderer/assets/participant-avatars/12.svg +3 -0
- package/src/renderer/assets/participant-avatars/13.svg +3 -0
- package/src/renderer/components/common/TerminalPane.tsx +213 -0
- package/src/renderer/components/dashboard/DashboardView.tsx +9 -36
- package/src/renderer/components/extensions/ExtensionStoreView.tsx +12 -221
- package/src/renderer/components/extensions/ExtensionsSubTabTrigger.tsx +1 -1
- package/src/renderer/components/extensions/mcp/McpLibraryEnableDialog.tsx +305 -0
- package/src/renderer/components/extensions/mcp/McpLibraryEntryDialog.tsx +418 -0
- package/src/renderer/components/extensions/mcp/McpLibraryPanel.tsx +404 -0
- package/src/renderer/components/extensions/plugins/PluginCard.tsx +10 -2
- package/src/renderer/components/extensions/plugins/PluginsPanel.tsx +40 -22
- package/src/renderer/components/extensions/skills/SkillsLibraryPanel.tsx +335 -0
- package/src/renderer/components/layout/PaneContent.tsx +8 -1
- package/src/renderer/components/layout/Sidebar.tsx +11 -54
- package/src/renderer/components/layout/SortableTab.tsx +20 -31
- package/src/renderer/components/layout/TabBar.tsx +1 -1
- package/src/renderer/components/layout/TabContextMenu.tsx +1 -1
- package/src/renderer/components/runtime/ProviderRuntimeSettingsDialog.tsx +768 -157
- package/src/renderer/components/schedules/SchedulesView.tsx +51 -462
- package/src/renderer/components/schedules/calendar/CalendarDayView.tsx +173 -0
- package/src/renderer/components/schedules/calendar/CalendarEventBlock.tsx +113 -0
- package/src/renderer/components/schedules/calendar/CalendarHeader.tsx +148 -0
- package/src/renderer/components/schedules/calendar/CalendarMonthView.tsx +142 -0
- package/src/renderer/components/schedules/calendar/CalendarWeekView.tsx +219 -0
- package/src/renderer/components/schedules/calendar/ScheduleCalendarBoard.tsx +41 -0
- package/src/renderer/components/schedules/calendar/TeamGanttView.tsx +405 -0
- package/src/renderer/components/schedules/calendar/computeOccurrences.ts +234 -0
- package/src/renderer/components/schedules/calendar/index.ts +2 -0
- package/src/renderer/components/schedules/calendar/types.ts +44 -0
- package/src/renderer/components/settings/SettingsTabs.tsx +50 -55
- package/src/renderer/components/settings/SettingsView.tsx +30 -35
- package/src/renderer/components/settings/components/SettingsSectionHeader.tsx +5 -1
- package/src/renderer/components/settings/components/SettingsSelect.tsx +5 -3
- package/src/renderer/components/settings/components/SettingsToggle.tsx +2 -2
- package/src/renderer/components/settings/sections/AdvancedSection.tsx +11 -42
- package/src/renderer/components/settings/sections/CliStatusSection.tsx +71 -112
- package/src/renderer/components/settings/sections/ConfigEditorDialog.tsx +1 -1
- package/src/renderer/components/settings/sections/GeneralSection.tsx +11 -3
- package/src/renderer/components/settings/sections/HarnessSection.tsx +18 -14
- package/src/renderer/components/settings/sections/PlatformsSection.tsx +3 -3
- package/src/renderer/components/settings/sections/TaskBusSection.tsx +33 -40
- package/src/renderer/components/settings/sections/index.ts +0 -1
- package/src/renderer/components/sidebar/SidebarSessions.tsx +182 -4
- package/src/renderer/components/sidebar/SidebarTaskItem.tsx +4 -4
- package/src/renderer/components/sidebar/WorkspaceBrowser.tsx +39 -4
- package/src/renderer/components/splash/splashScene.ts +121 -929
- package/src/renderer/components/system-manager/FolderBrowser.tsx +163 -0
- package/src/renderer/components/system-manager/SystemManagerView.tsx +351 -0
- package/src/renderer/components/tasks/TasksView.tsx +112 -134
- package/src/renderer/components/team/CcSessionsSection.tsx +431 -89
- package/src/renderer/components/team/CollapsibleTeamSection.tsx +17 -32
- package/src/renderer/components/team/TeamDetailView.tsx +325 -114
- package/src/renderer/components/team/TeamListView.tsx +108 -123
- package/src/renderer/components/team/dialogs/CreateTaskDialog.tsx +2 -2
- package/src/renderer/components/team/dialogs/CreateTeamDialog.tsx +84 -306
- package/src/renderer/components/team/dialogs/EditTeamDialog.tsx +259 -342
- package/src/renderer/components/team/dialogs/GlobalTaskDetailDialog.tsx +1 -1
- package/src/renderer/components/team/dialogs/LaunchTeamDialog.tsx +17 -15
- package/src/renderer/components/team/dialogs/PlatformBindingDialog.tsx +221 -0
- package/src/renderer/components/team/dialogs/PlatformManualForm.tsx +7 -0
- package/src/renderer/components/team/dialogs/PlatformSetupQR.tsx +1 -1
- package/src/renderer/components/team/dialogs/RuntimeConfigDialog.tsx +361 -0
- package/src/renderer/components/team/dialogs/platformMeta.ts +122 -11
- package/src/renderer/components/team/dialogs/useTeamEditForm.ts +17 -5
- package/src/renderer/components/team/kanban/KanbanBoard.tsx +9 -9
- package/src/renderer/components/team/members/MemberCard.tsx +14 -47
- package/src/renderer/components/team/members/MemberDetailDialog.tsx +3 -95
- package/src/renderer/components/team/members/MemberDetailStats.tsx +50 -65
- package/src/renderer/components/team/messages/MessageComposer.tsx +8 -110
- package/src/renderer/components/team/messages/MessagesPanel.tsx +131 -114
- package/src/renderer/components/team/schedule/ScheduleStatusBadge.tsx +2 -2
- package/src/renderer/components/team/tools/AddMcpInline.tsx +57 -0
- package/src/renderer/components/team/tools/AddSkillInline.tsx +61 -0
- package/src/renderer/components/team/tools/McpChip.tsx +45 -0
- package/src/renderer/components/team/tools/SkillChip.tsx +35 -0
- package/src/renderer/components/team/tools/ToolsSection.tsx +556 -0
- package/src/renderer/hooks/useExtensionsTabState.ts +3 -114
- package/src/renderer/index.css +39 -22
- package/src/renderer/index.html +17 -50
- package/src/renderer/store/index.ts +2 -1
- package/src/renderer/store/slices/scheduleSlice.ts +1 -1
- package/src/renderer/store/slices/teamSlice.ts +45 -168
- package/src/renderer/utils/claudeCodeOnlyProviders.ts +3 -10
- package/src/renderer/utils/memberHelpers.ts +5 -17
- package/src/renderer/utils/openCodeRuntimeDeliveryDiagnostics.ts +4 -2
- package/src/renderer/utils/providerSlashCommands.ts +0 -5
- package/src/renderer/utils/scheduleFormatters.ts +3 -1
- package/src/renderer/utils/teamMessageFiltering.ts +14 -1
- package/src/renderer/utils/teamModelAvailability.ts +18 -2
- package/src/shared/types/api.ts +121 -2
- package/src/shared/types/ccConnect.ts +2 -0
- package/src/shared/types/extensions/api.ts +9 -0
- package/src/shared/types/extensions/index.ts +4 -0
- package/src/shared/types/extensions/mcp.ts +41 -0
- package/src/shared/types/index.ts +3 -0
- package/src/shared/types/systemManager.ts +49 -0
- package/src/shared/types/team.ts +29 -0
- package/src/shared/types/terminal.ts +4 -2
- package/src/shared/utils/extensionNormalizers.ts +29 -0
- package/src/shared/utils/providerExtensionCapabilities.ts +2 -2
- package/dist-renderer/assets/ProjectEditorOverlay-Va_Vz-zz.js +0 -52
- package/dist-renderer/assets/channel-5dJIx68e.js +0 -1
- package/dist-renderer/assets/classDiagram-2ON5EDUG-BMGXWJ2d.js +0 -1
- package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-BMGXWJ2d.js +0 -1
- package/dist-renderer/assets/clone-D7FWfGY9.js +0 -1
- package/dist-renderer/assets/index-B2z_IyRH.css +0 -1
- package/dist-renderer/assets/splashScene-C8lWNnm4.js +0 -1
- package/dist-renderer/assets/stateDiagram-v2-4FDKWEC3-DOYYvDbi.js +0 -1
- package/src/main/services/extensions/catalog/GlamaMcpEnrichmentService.ts +0 -190
- package/src/main/services/extensions/catalog/McpCatalogAggregator.ts +0 -150
- package/src/main/services/extensions/catalog/OfficialMcpRegistryService.ts +0 -381
- package/src/main/services/extensions/install/McpInstallService.ts +0 -407
- package/src/main/services/extensions/state/McpInstallationStateService.ts +0 -42
- package/src/renderer/components/extensions/mcp/McpServerCard.tsx +0 -314
- package/src/renderer/components/extensions/mcp/McpServerDetailDialog.tsx +0 -765
- package/src/renderer/components/extensions/mcp/McpServersPanel.tsx +0 -593
- package/src/renderer/components/extensions/skills/SkillDetailDialog.tsx +0 -372
- package/src/renderer/components/extensions/skills/SkillImportDialog.tsx +0 -343
- package/src/renderer/components/extensions/skills/SkillsPanel.tsx +0 -659
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SkillsLibraryPanel — global user skills library management.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
6
|
+
|
|
7
|
+
import { api } from '@renderer/api';
|
|
8
|
+
import { confirm } from '@renderer/components/common/ConfirmDialog';
|
|
9
|
+
import { Badge } from '@renderer/components/ui/badge';
|
|
10
|
+
import { Button } from '@renderer/components/ui/button';
|
|
11
|
+
import { useStore } from '@renderer/store';
|
|
12
|
+
import { formatSkillRootKind, getSkillAudienceLabel } from '@shared/utils/skillRoots';
|
|
13
|
+
import { AlertCircle, Edit, FileText, Plus, RefreshCw, Trash2 } from 'lucide-react';
|
|
14
|
+
|
|
15
|
+
import { SearchInput } from '../common/SearchInput';
|
|
16
|
+
|
|
17
|
+
import { SkillEditorDialog } from './SkillEditorDialog';
|
|
18
|
+
|
|
19
|
+
import type { SkillCatalogItem, SkillDetail } from '@shared/types/extensions';
|
|
20
|
+
|
|
21
|
+
interface SkillsLibraryPanelProps {
|
|
22
|
+
projectPath: string | null;
|
|
23
|
+
projectLabel: string | null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
type EditorState =
|
|
27
|
+
| { mode: 'create'; detail: null }
|
|
28
|
+
| { mode: 'edit'; detail: SkillDetail | null; skillId: string };
|
|
29
|
+
|
|
30
|
+
function formatScope(scope: SkillCatalogItem['scope']): string {
|
|
31
|
+
return scope === 'project' ? '项目' : '个人';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function formatInvocationMode(mode: SkillCatalogItem['invocationMode']): string {
|
|
35
|
+
return mode === 'manual-only' ? '手动调用' : '自动触发';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function matchesSearch(skill: SkillCatalogItem, query: string): boolean {
|
|
39
|
+
const normalizedQuery = query.trim().toLowerCase();
|
|
40
|
+
if (!normalizedQuery) return true;
|
|
41
|
+
|
|
42
|
+
return [skill.name, skill.description, skill.folderName, skill.rootKind, skill.scope]
|
|
43
|
+
.filter(Boolean)
|
|
44
|
+
.some((value) => value.toLowerCase().includes(normalizedQuery));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface SkillLibraryCardProps {
|
|
48
|
+
skill: SkillCatalogItem;
|
|
49
|
+
isLoadingDetail: boolean;
|
|
50
|
+
isDeleting: boolean;
|
|
51
|
+
onEdit: (skill: SkillCatalogItem) => void;
|
|
52
|
+
onDelete: (skill: SkillCatalogItem) => void;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const SkillLibraryCard = ({
|
|
56
|
+
skill,
|
|
57
|
+
isLoadingDetail,
|
|
58
|
+
isDeleting,
|
|
59
|
+
onEdit,
|
|
60
|
+
onDelete,
|
|
61
|
+
}: SkillLibraryCardProps): React.JSX.Element => {
|
|
62
|
+
const statusBadge = skill.isValid ? (
|
|
63
|
+
<Badge className="border-emerald-500/30 bg-emerald-500/10 text-emerald-400" variant="outline">
|
|
64
|
+
可用
|
|
65
|
+
</Badge>
|
|
66
|
+
) : (
|
|
67
|
+
<Badge className="border-amber-500/30 bg-amber-500/10 text-amber-300" variant="outline">
|
|
68
|
+
需检查
|
|
69
|
+
</Badge>
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<div className="flex flex-col gap-3 rounded-xl border border-border bg-white/[0.025] p-4 transition-colors hover:border-border-emphasis hover:bg-white/[0.045]">
|
|
74
|
+
<div className="flex items-start justify-between gap-3">
|
|
75
|
+
<div className="min-w-0 space-y-1">
|
|
76
|
+
<div className="flex min-w-0 items-center gap-2">
|
|
77
|
+
<FileText className="size-4 shrink-0 text-text-muted" />
|
|
78
|
+
<h3 className="truncate text-sm font-semibold text-text">{skill.name}</h3>
|
|
79
|
+
</div>
|
|
80
|
+
<div className="flex flex-wrap items-center gap-1.5">
|
|
81
|
+
<Badge variant="secondary" className="text-[11px]">
|
|
82
|
+
{formatSkillRootKind(skill.rootKind)}
|
|
83
|
+
</Badge>
|
|
84
|
+
<Badge
|
|
85
|
+
variant="outline"
|
|
86
|
+
className="bg-surface-raised/60 border-border text-[11px] text-text-secondary"
|
|
87
|
+
>
|
|
88
|
+
{formatScope(skill.scope)}
|
|
89
|
+
</Badge>
|
|
90
|
+
<Badge
|
|
91
|
+
variant="outline"
|
|
92
|
+
className="bg-surface-raised/60 border-border text-[11px] text-text-secondary"
|
|
93
|
+
>
|
|
94
|
+
{getSkillAudienceLabel(skill.rootKind)}
|
|
95
|
+
</Badge>
|
|
96
|
+
<Badge
|
|
97
|
+
variant="outline"
|
|
98
|
+
className="bg-surface-raised/60 border-border text-[11px] text-text-secondary"
|
|
99
|
+
>
|
|
100
|
+
{formatInvocationMode(skill.invocationMode)}
|
|
101
|
+
</Badge>
|
|
102
|
+
{statusBadge}
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
<div className="flex shrink-0 items-center gap-1">
|
|
106
|
+
<Button
|
|
107
|
+
variant="ghost"
|
|
108
|
+
size="icon"
|
|
109
|
+
className="size-8"
|
|
110
|
+
onClick={() => onEdit(skill)}
|
|
111
|
+
disabled={isLoadingDetail || isDeleting}
|
|
112
|
+
title="编辑 Skill"
|
|
113
|
+
>
|
|
114
|
+
<Edit className="size-3.5" />
|
|
115
|
+
</Button>
|
|
116
|
+
<Button
|
|
117
|
+
variant="ghost"
|
|
118
|
+
size="icon"
|
|
119
|
+
className="size-8 text-red-300 hover:text-red-200"
|
|
120
|
+
onClick={() => onDelete(skill)}
|
|
121
|
+
disabled={isDeleting || isLoadingDetail}
|
|
122
|
+
title="删除 Skill"
|
|
123
|
+
>
|
|
124
|
+
<Trash2 className="size-3.5" />
|
|
125
|
+
</Button>
|
|
126
|
+
</div>
|
|
127
|
+
</div>
|
|
128
|
+
|
|
129
|
+
<p className="line-clamp-3 min-h-[3.75rem] text-xs leading-5 text-text-secondary">
|
|
130
|
+
{skill.description || '没有描述。'}
|
|
131
|
+
</p>
|
|
132
|
+
|
|
133
|
+
<div className="flex flex-wrap items-center gap-2 text-[11px] text-text-muted">
|
|
134
|
+
<span className="truncate">{skill.folderName}</span>
|
|
135
|
+
{skill.flags.hasScripts ? <Badge variant="outline">脚本</Badge> : null}
|
|
136
|
+
{skill.flags.hasReferences ? <Badge variant="outline">参考资料</Badge> : null}
|
|
137
|
+
{skill.flags.hasAssets ? <Badge variant="outline">资源</Badge> : null}
|
|
138
|
+
{skill.issues.length > 0 ? (
|
|
139
|
+
<span className="inline-flex items-center gap-1 text-amber-300">
|
|
140
|
+
<AlertCircle className="size-3" />
|
|
141
|
+
{skill.issues.length} 个提示
|
|
142
|
+
</span>
|
|
143
|
+
) : null}
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
);
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
export const SkillsLibraryPanel = ({
|
|
150
|
+
projectPath,
|
|
151
|
+
projectLabel,
|
|
152
|
+
}: SkillsLibraryPanelProps): React.JSX.Element => {
|
|
153
|
+
const fetchSkillDetail = useStore((s) => s.fetchSkillDetail);
|
|
154
|
+
const deleteSkill = useStore((s) => s.deleteSkill);
|
|
155
|
+
const skillDetailsById = useStore((s) => s.skillsDetailsById);
|
|
156
|
+
const skillDetailLoadingById = useStore((s) => s.skillsDetailLoadingById);
|
|
157
|
+
|
|
158
|
+
const [skills, setSkills] = useState<SkillCatalogItem[]>([]);
|
|
159
|
+
const [search, setSearch] = useState('');
|
|
160
|
+
const [loading, setLoading] = useState(false);
|
|
161
|
+
const [error, setError] = useState<string | null>(null);
|
|
162
|
+
const [editorState, setEditorState] = useState<EditorState | null>(null);
|
|
163
|
+
const [openingSkillId, setOpeningSkillId] = useState<string | null>(null);
|
|
164
|
+
const [deletingSkillId, setDeletingSkillId] = useState<string | null>(null);
|
|
165
|
+
|
|
166
|
+
const loadSkills = useCallback(async (): Promise<void> => {
|
|
167
|
+
setLoading(true);
|
|
168
|
+
setError(null);
|
|
169
|
+
try {
|
|
170
|
+
const nextSkills = (await api.skills?.list()) ?? [];
|
|
171
|
+
setSkills(nextSkills);
|
|
172
|
+
} catch (err) {
|
|
173
|
+
setError(err instanceof Error ? err.message : '加载全局 Skill 失败');
|
|
174
|
+
} finally {
|
|
175
|
+
setLoading(false);
|
|
176
|
+
}
|
|
177
|
+
}, []);
|
|
178
|
+
|
|
179
|
+
useEffect(() => {
|
|
180
|
+
void loadSkills();
|
|
181
|
+
}, [loadSkills]);
|
|
182
|
+
|
|
183
|
+
const filteredSkills = useMemo(
|
|
184
|
+
() => skills.filter((skill) => matchesSearch(skill, search)),
|
|
185
|
+
[skills, search]
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
const openCreateDialog = useCallback(() => {
|
|
189
|
+
setEditorState({ mode: 'create', detail: null });
|
|
190
|
+
}, []);
|
|
191
|
+
|
|
192
|
+
const openEditDialog = useCallback(
|
|
193
|
+
(skill: SkillCatalogItem) => {
|
|
194
|
+
const cachedDetail = skillDetailsById[skill.id];
|
|
195
|
+
if (cachedDetail) {
|
|
196
|
+
setEditorState({ mode: 'edit', skillId: skill.id, detail: cachedDetail });
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
setOpeningSkillId(skill.id);
|
|
201
|
+
setError(null);
|
|
202
|
+
void fetchSkillDetail(skill.id)
|
|
203
|
+
.then(() => {
|
|
204
|
+
setEditorState({ mode: 'edit', skillId: skill.id, detail: null });
|
|
205
|
+
})
|
|
206
|
+
.catch((err) => {
|
|
207
|
+
setError(err instanceof Error ? err.message : '加载 Skill 详情失败');
|
|
208
|
+
})
|
|
209
|
+
.finally(() => {
|
|
210
|
+
setOpeningSkillId((current) => (current === skill.id ? null : current));
|
|
211
|
+
});
|
|
212
|
+
},
|
|
213
|
+
[fetchSkillDetail, skillDetailsById]
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
const handleDelete = useCallback(
|
|
217
|
+
(skill: SkillCatalogItem) => {
|
|
218
|
+
void (async () => {
|
|
219
|
+
const confirmed = await confirm({
|
|
220
|
+
title: '删除 Skill',
|
|
221
|
+
message: `确认删除全局 Skill「${skill.name}」?此操作会删除对应的 Skill 文件。`,
|
|
222
|
+
confirmLabel: '删除',
|
|
223
|
+
cancelLabel: '取消',
|
|
224
|
+
variant: 'danger',
|
|
225
|
+
});
|
|
226
|
+
if (!confirmed) return;
|
|
227
|
+
|
|
228
|
+
setDeletingSkillId(skill.id);
|
|
229
|
+
setError(null);
|
|
230
|
+
try {
|
|
231
|
+
await deleteSkill({ skillId: skill.id });
|
|
232
|
+
await loadSkills();
|
|
233
|
+
} catch (err) {
|
|
234
|
+
setError(err instanceof Error ? err.message : '删除 Skill 失败');
|
|
235
|
+
} finally {
|
|
236
|
+
setDeletingSkillId(null);
|
|
237
|
+
}
|
|
238
|
+
})();
|
|
239
|
+
},
|
|
240
|
+
[deleteSkill, loadSkills]
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
const handleSaved = useCallback(
|
|
244
|
+
(_skillId: string | null) => {
|
|
245
|
+
setEditorState(null);
|
|
246
|
+
void loadSkills();
|
|
247
|
+
},
|
|
248
|
+
[loadSkills]
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
const editorDetail = useMemo(() => {
|
|
252
|
+
if (!editorState) return null;
|
|
253
|
+
if (editorState.mode === 'create') return null;
|
|
254
|
+
return skillDetailsById[editorState.skillId] ?? editorState.detail;
|
|
255
|
+
}, [editorState, skillDetailsById]);
|
|
256
|
+
|
|
257
|
+
return (
|
|
258
|
+
<div className="flex flex-col gap-4">
|
|
259
|
+
<div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
|
|
260
|
+
<div>
|
|
261
|
+
<h2 className="text-sm font-semibold text-text">全局 Skill 库</h2>
|
|
262
|
+
<p className="text-xs text-text-muted">
|
|
263
|
+
管理个人范围 Skill。创建和编辑会保存到全局用户范围,不会写入当前项目。
|
|
264
|
+
</p>
|
|
265
|
+
</div>
|
|
266
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
267
|
+
<Badge variant="secondary" className="font-normal">
|
|
268
|
+
{skills.length} 个 Skill
|
|
269
|
+
</Badge>
|
|
270
|
+
{projectPath ? (
|
|
271
|
+
<Badge variant="outline" className="font-normal text-text-muted">
|
|
272
|
+
当前项目:{projectLabel ?? projectPath}
|
|
273
|
+
</Badge>
|
|
274
|
+
) : null}
|
|
275
|
+
<Button variant="outline" size="sm" onClick={() => void loadSkills()} disabled={loading}>
|
|
276
|
+
<RefreshCw className={loading ? 'mr-2 size-3.5 animate-spin' : 'mr-2 size-3.5'} />
|
|
277
|
+
刷新
|
|
278
|
+
</Button>
|
|
279
|
+
<Button size="sm" onClick={openCreateDialog}>
|
|
280
|
+
<Plus className="mr-2 size-3.5" />
|
|
281
|
+
新建 Skill
|
|
282
|
+
</Button>
|
|
283
|
+
</div>
|
|
284
|
+
</div>
|
|
285
|
+
|
|
286
|
+
<SearchInput
|
|
287
|
+
value={search}
|
|
288
|
+
onChange={setSearch}
|
|
289
|
+
placeholder="搜索 Skill..."
|
|
290
|
+
debounceMs={120}
|
|
291
|
+
/>
|
|
292
|
+
|
|
293
|
+
{error ? (
|
|
294
|
+
<div className="rounded-md border border-amber-500/30 bg-amber-500/10 px-3 py-2 text-sm text-amber-300">
|
|
295
|
+
{error}
|
|
296
|
+
</div>
|
|
297
|
+
) : null}
|
|
298
|
+
|
|
299
|
+
{loading && skills.length === 0 ? (
|
|
300
|
+
<div className="rounded-xl border border-border bg-white/[0.025] px-4 py-8 text-center text-sm text-text-muted">
|
|
301
|
+
正在加载全局 Skill...
|
|
302
|
+
</div>
|
|
303
|
+
) : filteredSkills.length > 0 ? (
|
|
304
|
+
<div className="grid gap-3 md:grid-cols-2 xl:grid-cols-3">
|
|
305
|
+
{filteredSkills.map((skill) => (
|
|
306
|
+
<SkillLibraryCard
|
|
307
|
+
key={skill.id}
|
|
308
|
+
skill={skill}
|
|
309
|
+
isLoadingDetail={
|
|
310
|
+
openingSkillId === skill.id || Boolean(skillDetailLoadingById[skill.id])
|
|
311
|
+
}
|
|
312
|
+
isDeleting={deletingSkillId === skill.id}
|
|
313
|
+
onEdit={openEditDialog}
|
|
314
|
+
onDelete={handleDelete}
|
|
315
|
+
/>
|
|
316
|
+
))}
|
|
317
|
+
</div>
|
|
318
|
+
) : (
|
|
319
|
+
<div className="rounded-xl border border-border bg-white/[0.025] px-4 py-8 text-center text-sm text-text-muted">
|
|
320
|
+
{search ? '没有匹配的 Skill。' : '全局 Skill 库为空,点击“新建 Skill”创建第一个 Skill。'}
|
|
321
|
+
</div>
|
|
322
|
+
)}
|
|
323
|
+
|
|
324
|
+
<SkillEditorDialog
|
|
325
|
+
open={Boolean(editorState)}
|
|
326
|
+
mode={editorState?.mode ?? 'create'}
|
|
327
|
+
projectPath={null}
|
|
328
|
+
projectLabel={projectLabel}
|
|
329
|
+
detail={editorDetail}
|
|
330
|
+
onClose={() => setEditorState(null)}
|
|
331
|
+
onSaved={handleSaved}
|
|
332
|
+
/>
|
|
333
|
+
</div>
|
|
334
|
+
);
|
|
335
|
+
};
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import { TeamGraphTab } from '@features/agent-graph/renderer';
|
|
7
7
|
import { TabUIProvider } from '@renderer/contexts/TabUIContext';
|
|
8
|
+
import { SYSTEM_MANAGER_TEAM_NAME } from '@shared/types/team';
|
|
8
9
|
|
|
9
10
|
import { DashboardView } from '../dashboard/DashboardView';
|
|
10
11
|
import { ExtensionStoreView } from '../extensions/ExtensionStoreView';
|
|
@@ -13,6 +14,7 @@ import { SessionReportTab } from '../report/SessionReportTab';
|
|
|
13
14
|
import { SchedulesView } from '../schedules/SchedulesView';
|
|
14
15
|
import { SettingsView } from '../settings/SettingsView';
|
|
15
16
|
import { TasksView } from '../tasks/TasksView';
|
|
17
|
+
import { SystemManagerView } from '../system-manager/SystemManagerView';
|
|
16
18
|
import { TeamDetailView } from '../team/TeamDetailView';
|
|
17
19
|
import { TeamListView } from '../team/TeamListView';
|
|
18
20
|
|
|
@@ -51,7 +53,12 @@ export const PaneContent = ({ pane, isPaneFocused }: PaneContentProps): React.JS
|
|
|
51
53
|
{tab.type === 'notifications' && <NotificationsView />}
|
|
52
54
|
{tab.type === 'settings' && <SettingsView />}
|
|
53
55
|
{tab.type === 'teams' && <TeamListView />}
|
|
54
|
-
{tab.type === 'team' && (
|
|
56
|
+
{tab.type === 'team' && tab.teamName === SYSTEM_MANAGER_TEAM_NAME && (
|
|
57
|
+
<TabUIProvider tabId={tab.id}>
|
|
58
|
+
<SystemManagerView isPaneFocused={isPaneFocused} />
|
|
59
|
+
</TabUIProvider>
|
|
60
|
+
)}
|
|
61
|
+
{tab.type === 'team' && tab.teamName !== SYSTEM_MANAGER_TEAM_NAME && (
|
|
55
62
|
<TabUIProvider tabId={tab.id}>
|
|
56
63
|
<TeamDetailView teamName={tab.teamName ?? ''} isPaneFocused={isPaneFocused} />
|
|
57
64
|
</TabUIProvider>
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Sidebar - Navigation with task list and session list.
|
|
3
3
|
*
|
|
4
4
|
* Structure:
|
|
5
|
-
* - Tab bar: Collapse button +
|
|
6
|
-
* - Scrollable Body:
|
|
5
|
+
* - Tab bar: Collapse button + Workspace
|
|
6
|
+
* - Scrollable Body: workspace browser
|
|
7
7
|
* - Resizable: Drag right edge to resize
|
|
8
8
|
* - Collapsible: Cmd+B to toggle (Notion-style)
|
|
9
9
|
*/
|
|
@@ -15,11 +15,9 @@ import { formatShortcut } from '@renderer/utils/stringUtils';
|
|
|
15
15
|
import { PanelLeft } from 'lucide-react';
|
|
16
16
|
import { useShallow } from 'zustand/react/shallow';
|
|
17
17
|
|
|
18
|
-
import { DateGroupedSessions } from '../sidebar/DateGroupedSessions';
|
|
19
|
-
import { SidebarSessions } from '../sidebar/SidebarSessions';
|
|
20
18
|
import { WorkspaceBrowser } from '../sidebar/WorkspaceBrowser';
|
|
21
19
|
|
|
22
|
-
type SidebarTab = 'workspace'
|
|
20
|
+
type SidebarTab = 'workspace';
|
|
23
21
|
|
|
24
22
|
const MIN_WIDTH = 200;
|
|
25
23
|
const MAX_WIDTH = 500;
|
|
@@ -34,7 +32,7 @@ export const Sidebar = (): React.JSX.Element => {
|
|
|
34
32
|
);
|
|
35
33
|
const [width, setWidth] = useState(DEFAULT_WIDTH);
|
|
36
34
|
const [isResizing, setIsResizing] = useState(false);
|
|
37
|
-
const [sidebarTab
|
|
35
|
+
const [sidebarTab] = useState<SidebarTab>('workspace');
|
|
38
36
|
const [isCollapseHovered, setIsCollapseHovered] = useState(false);
|
|
39
37
|
const sidebarRef = useRef<HTMLDivElement>(null);
|
|
40
38
|
|
|
@@ -123,54 +121,22 @@ export const Sidebar = (): React.JSX.Element => {
|
|
|
123
121
|
<button
|
|
124
122
|
type="button"
|
|
125
123
|
role="tab"
|
|
126
|
-
aria-selected
|
|
124
|
+
aria-selected
|
|
127
125
|
aria-controls="sidebar-workspace-panel"
|
|
128
126
|
id="sidebar-tab-workspace"
|
|
129
|
-
className=
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
style={
|
|
135
|
-
sidebarTab === 'workspace'
|
|
136
|
-
? {
|
|
137
|
-
borderBottom: '2px solid var(--color-text)',
|
|
138
|
-
marginBottom: '-1px',
|
|
139
|
-
}
|
|
140
|
-
: undefined
|
|
141
|
-
}
|
|
142
|
-
onClick={() => setSidebarTab('workspace')}
|
|
127
|
+
className="relative px-3 py-1.5 text-[11px] font-medium text-text transition-colors"
|
|
128
|
+
style={{
|
|
129
|
+
borderBottom: '2px solid var(--color-text)',
|
|
130
|
+
marginBottom: '-1px',
|
|
131
|
+
}}
|
|
143
132
|
>
|
|
144
133
|
工作空间
|
|
145
134
|
</button>
|
|
146
|
-
<button
|
|
147
|
-
type="button"
|
|
148
|
-
role="tab"
|
|
149
|
-
aria-selected={sidebarTab === 'sessions'}
|
|
150
|
-
aria-controls="sidebar-sessions-panel"
|
|
151
|
-
id="sidebar-tab-sessions"
|
|
152
|
-
className={`relative px-3 py-1.5 text-[11px] font-medium transition-colors ${
|
|
153
|
-
sidebarTab === 'sessions'
|
|
154
|
-
? 'text-text'
|
|
155
|
-
: 'text-text-muted hover:text-text-secondary'
|
|
156
|
-
}`}
|
|
157
|
-
style={
|
|
158
|
-
sidebarTab === 'sessions'
|
|
159
|
-
? {
|
|
160
|
-
borderBottom: '2px solid var(--color-text)',
|
|
161
|
-
marginBottom: '-1px',
|
|
162
|
-
}
|
|
163
|
-
: undefined
|
|
164
|
-
}
|
|
165
|
-
onClick={() => setSidebarTab('sessions')}
|
|
166
|
-
>
|
|
167
|
-
会话
|
|
168
|
-
</button>
|
|
169
135
|
</div>
|
|
170
136
|
<div className="flex-1" />
|
|
171
137
|
</div>
|
|
172
138
|
|
|
173
|
-
{/* Content: Workspace
|
|
139
|
+
{/* Content: Workspace browser */}
|
|
174
140
|
<div
|
|
175
141
|
id="sidebar-workspace-panel"
|
|
176
142
|
role="tabpanel"
|
|
@@ -180,15 +146,6 @@ export const Sidebar = (): React.JSX.Element => {
|
|
|
180
146
|
>
|
|
181
147
|
<WorkspaceBrowser />
|
|
182
148
|
</div>
|
|
183
|
-
<div
|
|
184
|
-
id="sidebar-sessions-panel"
|
|
185
|
-
role="tabpanel"
|
|
186
|
-
aria-labelledby="sidebar-tab-sessions"
|
|
187
|
-
hidden={sidebarTab !== 'sessions'}
|
|
188
|
-
className="min-w-0 flex-1 overflow-hidden"
|
|
189
|
-
>
|
|
190
|
-
<SidebarSessions />
|
|
191
|
-
</div>
|
|
192
149
|
</div>
|
|
193
150
|
|
|
194
151
|
{/* Resize handle - only interactive when expanded */}
|
|
@@ -8,12 +8,7 @@ import { useCallback, useState } from 'react';
|
|
|
8
8
|
import { useSortable } from '@dnd-kit/sortable';
|
|
9
9
|
import { CSS } from '@dnd-kit/utilities';
|
|
10
10
|
import { Tooltip, TooltipContent, TooltipTrigger } from '@renderer/components/ui/tooltip';
|
|
11
|
-
import {
|
|
12
|
-
getTeamColorSet,
|
|
13
|
-
getThemedBadge,
|
|
14
|
-
getThemedBorder,
|
|
15
|
-
getThemedText,
|
|
16
|
-
} from '@renderer/constants/teamColors';
|
|
11
|
+
import { getTeamColorSet } from '@renderer/constants/teamColors';
|
|
17
12
|
import { useTheme } from '@renderer/hooks/useTheme';
|
|
18
13
|
import { useStore } from '@renderer/store';
|
|
19
14
|
import { nameColorSet } from '@renderer/utils/projectColor';
|
|
@@ -91,15 +86,11 @@ export const SortableTab = ({
|
|
|
91
86
|
team?.color ??
|
|
92
87
|
(s.selectedTeamName === tab.teamName ? s.selectedTeamData?.config.color : undefined);
|
|
93
88
|
if (explicitColor) return getTeamColorSet(explicitColor);
|
|
94
|
-
// Fallback: deterministic color derived from display name
|
|
95
89
|
const displayName = team?.displayName ?? tab.label;
|
|
96
90
|
return nameColorSet(displayName, isLight);
|
|
97
91
|
})
|
|
98
92
|
);
|
|
99
|
-
const
|
|
100
|
-
? getThemedBorder(teamColorSet, isLight)
|
|
101
|
-
: 'var(--color-accent, #6366f1)';
|
|
102
|
-
const inactiveTeamTextColor = teamColorSet ? getThemedText(teamColorSet, isLight) : null;
|
|
93
|
+
const accentColor = teamColorSet?.text ?? null;
|
|
103
94
|
|
|
104
95
|
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
|
|
105
96
|
id: tab.id,
|
|
@@ -116,33 +107,25 @@ export const SortableTab = ({
|
|
|
116
107
|
transition: isDragging ? 'none' : transition,
|
|
117
108
|
opacity: isDragging ? 0.3 : 1,
|
|
118
109
|
backgroundColor: isActive
|
|
119
|
-
?
|
|
120
|
-
? getThemedBadge(teamColorSet, isLight)
|
|
121
|
-
: 'var(--color-surface-raised)'
|
|
110
|
+
? 'var(--color-surface-raised)'
|
|
122
111
|
: isHovered
|
|
123
|
-
?
|
|
124
|
-
|
|
125
|
-
: 'var(--color-surface-overlay)'
|
|
126
|
-
: teamColorSet
|
|
127
|
-
? getThemedBadge(teamColorSet, isLight)
|
|
128
|
-
: 'transparent',
|
|
112
|
+
? 'var(--color-surface-overlay)'
|
|
113
|
+
: 'transparent',
|
|
129
114
|
color: isActive
|
|
130
115
|
? 'var(--color-text)'
|
|
131
|
-
:
|
|
132
|
-
?
|
|
133
|
-
:
|
|
134
|
-
? 'var(--color-text)'
|
|
135
|
-
: 'var(--color-text-muted)',
|
|
116
|
+
: isHovered
|
|
117
|
+
? 'var(--color-text)'
|
|
118
|
+
: 'var(--color-text-muted)',
|
|
136
119
|
outline: isSelected ? '1px solid var(--color-border-emphasis)' : 'none',
|
|
137
120
|
outlineOffset: '-1px',
|
|
138
|
-
borderTop: isActive ?
|
|
139
|
-
borderLeft: '1px solid
|
|
121
|
+
borderTop: isActive ? '1px solid var(--color-border)' : '1px solid transparent',
|
|
122
|
+
borderLeft: '1px solid var(--color-border-subtle)',
|
|
140
123
|
borderRight: '1px solid transparent',
|
|
141
124
|
borderBottom: isActive ? '1px solid var(--color-surface-raised)' : '1px solid transparent',
|
|
142
|
-
borderTopLeftRadius: '
|
|
143
|
-
borderTopRightRadius: '
|
|
144
|
-
borderBottomLeftRadius:
|
|
145
|
-
borderBottomRightRadius:
|
|
125
|
+
borderTopLeftRadius: '0',
|
|
126
|
+
borderTopRightRadius: '0',
|
|
127
|
+
borderBottomLeftRadius: '0',
|
|
128
|
+
borderBottomRightRadius: '0',
|
|
146
129
|
marginBottom: isActive ? '-1px' : 0,
|
|
147
130
|
position: 'relative' as const,
|
|
148
131
|
zIndex: isActive ? 1 : 0,
|
|
@@ -184,6 +167,12 @@ export const SortableTab = ({
|
|
|
184
167
|
}
|
|
185
168
|
}}
|
|
186
169
|
>
|
|
170
|
+
{isActive && accentColor && (
|
|
171
|
+
<div
|
|
172
|
+
className="absolute bottom-0 left-2 right-2 h-[2px] rounded-full"
|
|
173
|
+
style={{ backgroundColor: accentColor, opacity: 0.6 }}
|
|
174
|
+
/>
|
|
175
|
+
)}
|
|
187
176
|
<Icon className="size-4 shrink-0" />
|
|
188
177
|
{tab.fromSearch && (
|
|
189
178
|
<span title="从搜索打开">
|
|
@@ -264,7 +264,7 @@ export const TabBar = ({ paneId }: TabBarProps): React.JSX.Element => {
|
|
|
264
264
|
scrollContainerRef.current = el;
|
|
265
265
|
setDroppableRef(el);
|
|
266
266
|
}}
|
|
267
|
-
className="scrollbar-none flex min-w-0 flex-1 items-center
|
|
267
|
+
className="scrollbar-none flex min-w-0 flex-1 items-center"
|
|
268
268
|
style={{
|
|
269
269
|
outline: isDroppableOver ? '1px dashed var(--color-accent, #6366f1)' : 'none',
|
|
270
270
|
outlineOffset: '-1px',
|
|
@@ -87,7 +87,7 @@ export const TabContextMenu = ({
|
|
|
87
87
|
return (
|
|
88
88
|
<div
|
|
89
89
|
ref={menuRef}
|
|
90
|
-
className="fixed z-50 min-w-[220px] overflow-hidden
|
|
90
|
+
className="fixed z-50 min-w-[220px] overflow-hidden border py-1 shadow-lg"
|
|
91
91
|
style={{
|
|
92
92
|
left: clampedX,
|
|
93
93
|
top: clampedY,
|