@plannotator/ui 0.22.0
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/README.md +60 -0
- package/assets/diff-options.png +0 -0
- package/assets/icon-codex.png +0 -0
- package/assets/look-flat.png +0 -0
- package/assets/look-grid.png +0 -0
- package/assets/review-sections.png +0 -0
- package/assets/review-tree.png +0 -0
- package/assets/workspaces.webp +0 -0
- package/components/AISettingsTab.tsx +145 -0
- package/components/ActionMenu.tsx +101 -0
- package/components/AgentControls.tsx +216 -0
- package/components/AgentsTab.tsx +1294 -0
- package/components/AnnotationPanel.tsx +731 -0
- package/components/AnnotationSidebar.tsx +86 -0
- package/components/AnnotationToolbar.tsx +323 -0
- package/components/AnnotationToolstrip.tsx +355 -0
- package/components/ApproveDropdown.tsx +170 -0
- package/components/AttachmentsButton.tsx +410 -0
- package/components/BlockRenderer.tsx +163 -0
- package/components/BorderTrail.tsx +38 -0
- package/components/CodeFilePicker.tsx +64 -0
- package/components/CodeFilePopout.tsx +602 -0
- package/components/CodePathValidationContext.tsx +14 -0
- package/components/CommentPopover.tsx +512 -0
- package/components/CompletionOverlay.tsx +99 -0
- package/components/ConfirmDialog.tsx +128 -0
- package/components/DocBadges.tsx +231 -0
- package/components/EditorAnnotationCard.tsx +65 -0
- package/components/ExportModal.tsx +565 -0
- package/components/FloatingQuickLabelPicker.tsx +144 -0
- package/components/GitHubIcon.tsx +16 -0
- package/components/GitLabIcon.tsx +30 -0
- package/components/GraphvizBlock.tsx +511 -0
- package/components/ImageAnnotator/Canvas.tsx +118 -0
- package/components/ImageAnnotator/Toolbar.tsx +218 -0
- package/components/ImageAnnotator/index.tsx +272 -0
- package/components/ImageAnnotator/types.ts +39 -0
- package/components/ImageAnnotator/utils.ts +147 -0
- package/components/ImageThumbnail.tsx +126 -0
- package/components/ImportModal.tsx +146 -0
- package/components/InlineMarkdown.tsx +1094 -0
- package/components/KeyboardShortcuts.tsx +208 -0
- package/components/Landing.tsx +496 -0
- package/components/ListItemBody.tsx +62 -0
- package/components/ListMarker.tsx +73 -0
- package/components/LookAndFeelAnnouncementDialog.tsx +230 -0
- package/components/MarkdownEditor.tsx +44 -0
- package/components/MenuVersionSection.tsx +91 -0
- package/components/MermaidBlock.tsx +579 -0
- package/components/ModeToggle.tsx +68 -0
- package/components/OpenInAppButton.tsx +299 -0
- package/components/OverlayScrollArea.tsx +82 -0
- package/components/PermissionModeSetup.tsx +92 -0
- package/components/PinpointOverlay.tsx +99 -0
- package/components/PlanAIAnnouncementDialog.tsx +187 -0
- package/components/PlanHeaderMenu.tsx +299 -0
- package/components/PopoutDialog.tsx +91 -0
- package/components/Popover.tsx +27 -0
- package/components/ProviderIcons.tsx +51 -0
- package/components/PullRequestIcon.tsx +12 -0
- package/components/QuickLabelDropdown.tsx +63 -0
- package/components/RenderedMarkdown.tsx +54 -0
- package/components/RepoIcon.tsx +12 -0
- package/components/ResizeHandle.tsx +86 -0
- package/components/ReviewAgentsIcon.tsx +18 -0
- package/components/SearchableSelect.tsx +157 -0
- package/components/Settings.tsx +2220 -0
- package/components/SparklesIcon.tsx +45 -0
- package/components/StickyHeaderLane.tsx +260 -0
- package/components/TableOfContents.tsx +157 -0
- package/components/TaterSpritePullup.tsx +34 -0
- package/components/TaterSpriteRunning.tsx +54 -0
- package/components/TaterSpriteSitting.tsx +37 -0
- package/components/TextShimmer.tsx +57 -0
- package/components/ThemeProvider.tsx +162 -0
- package/components/ThemeTab.tsx +139 -0
- package/components/ToolbarButtons.tsx +116 -0
- package/components/Tooltip.tsx +45 -0
- package/components/Viewer.tsx +977 -0
- package/components/ai/AIProviderBar.tsx +95 -0
- package/components/ai/DocumentAIChatPanel.tsx +313 -0
- package/components/blocks/AlertBlock.tsx +58 -0
- package/components/blocks/Callout.tsx +60 -0
- package/components/blocks/CodeBlock.tsx +75 -0
- package/components/blocks/HtmlBlock.tsx +122 -0
- package/components/blocks/MathBlock.tsx +36 -0
- package/components/blocks/TableBlock.tsx +146 -0
- package/components/blocks/TablePopout.tsx +279 -0
- package/components/blocks/TableToolbar.tsx +153 -0
- package/components/blocks/proseBody.tsx +102 -0
- package/components/core/button.tsx +44 -0
- package/components/core/textarea.tsx +26 -0
- package/components/diagramLanguages.ts +14 -0
- package/components/goal-setup/GoalSetupSurface.tsx +1354 -0
- package/components/html-viewer/HtmlViewer.tsx +386 -0
- package/components/html-viewer/bridge-script.ts +505 -0
- package/components/html-viewer/index.ts +1 -0
- package/components/html-viewer/useHtmlAnnotation.ts +400 -0
- package/components/icons/AgentIcons.tsx +66 -0
- package/components/icons/AppIcon.tsx +56 -0
- package/components/icons/MessagesIcon.tsx +11 -0
- package/components/icons/ObsidianIcons.tsx +208 -0
- package/components/icons/app/android-studio.svg +369 -0
- package/components/icons/app/antigravity.svg +97 -0
- package/components/icons/app/cursor.svg +16 -0
- package/components/icons/app/file-explorer.svg +20 -0
- package/components/icons/app/finder.png +0 -0
- package/components/icons/app/ghostty.svg +13 -0
- package/components/icons/app/iterm2.svg +13 -0
- package/components/icons/app/powershell.svg +14 -0
- package/components/icons/app/sublime-text.svg +17 -0
- package/components/icons/app/terminal.png +0 -0
- package/components/icons/app/textmate.png +0 -0
- package/components/icons/app/vscode.svg +39 -0
- package/components/icons/app/warp.png +0 -0
- package/components/icons/app/xcode.png +0 -0
- package/components/icons/app/zed-dark.svg +15 -0
- package/components/icons/app/zed.svg +15 -0
- package/components/icons/themeIcons.tsx +47 -0
- package/components/mermaidSvg.ts +33 -0
- package/components/plan-diff/PlanCleanDiffView.tsx +884 -0
- package/components/plan-diff/PlanDiffBadge.tsx +48 -0
- package/components/plan-diff/PlanDiffModeSwitcher.tsx +103 -0
- package/components/plan-diff/PlanDiffViewer.tsx +214 -0
- package/components/plan-diff/PlanRawDiffView.tsx +102 -0
- package/components/plan-diff/VSCodeIcon.tsx +132 -0
- package/components/settings/HooksTab.tsx +208 -0
- package/components/sidebar/ArchiveBrowser.tsx +98 -0
- package/components/sidebar/CountBadge.tsx +12 -0
- package/components/sidebar/FileBrowser.tsx +498 -0
- package/components/sidebar/MessagesBrowser.tsx +109 -0
- package/components/sidebar/SidebarContainer.tsx +353 -0
- package/components/sidebar/SidebarTabs.tsx +155 -0
- package/components/sidebar/VersionBrowser.tsx +141 -0
- package/components/types.d.ts +7 -0
- package/components/ui/badge.tsx +44 -0
- package/components/ui/button.tsx +83 -0
- package/components/ui/card.tsx +58 -0
- package/components/ui/dialog.tsx +106 -0
- package/components/ui/dropdown-menu.tsx +240 -0
- package/components/ui/state-pill.tsx +45 -0
- package/components/ui/tabs.tsx +46 -0
- package/components/ui/textarea.tsx +25 -0
- package/config/configStore.ts +214 -0
- package/config/index.ts +4 -0
- package/config/reviewView.ts +42 -0
- package/config/settings.ts +310 -0
- package/config/useConfig.ts +20 -0
- package/configure.ts +69 -0
- package/globals.d.ts +14 -0
- package/hooks/pfm/useCodeFilePopout.ts +111 -0
- package/hooks/useAIChat.ts +532 -0
- package/hooks/useAIProviderConfig.ts +115 -0
- package/hooks/useActiveSection.ts +78 -0
- package/hooks/useAgentJobs.ts +306 -0
- package/hooks/useAgentSettings.ts +579 -0
- package/hooks/useAgents.ts +90 -0
- package/hooks/useAnnotationDraft.ts +523 -0
- package/hooks/useAnnotationHighlighter.ts +1170 -0
- package/hooks/useArchive.ts +171 -0
- package/hooks/useAutoClose.ts +104 -0
- package/hooks/useCodeAnnotationDraft.ts +194 -0
- package/hooks/useCodeFilePopout.ts +1 -0
- package/hooks/useDismissOnOutsideAndEscape.ts +50 -0
- package/hooks/useDraggable.ts +108 -0
- package/hooks/useEditorAnnotations.ts +64 -0
- package/hooks/useExternalAnnotationHighlights.ts +105 -0
- package/hooks/useExternalAnnotations.ts +268 -0
- package/hooks/useFileBrowser.ts +402 -0
- package/hooks/useInputMethodSwitch.ts +89 -0
- package/hooks/useIsMobile.ts +17 -0
- package/hooks/useLinkedDoc.ts +494 -0
- package/hooks/useOverlayViewport.ts +36 -0
- package/hooks/usePinpoint.ts +182 -0
- package/hooks/usePlanDiff.ts +176 -0
- package/hooks/usePrintMode.ts +27 -0
- package/hooks/useResizablePanel.ts +173 -0
- package/hooks/useScrollViewport.ts +38 -0
- package/hooks/useSharing.ts +441 -0
- package/hooks/useSidebar.ts +55 -0
- package/hooks/useUpdateCheck.ts +132 -0
- package/hooks/useValidatedCodePaths.ts +94 -0
- package/icons/GitUser.tsx +17 -0
- package/lib/utils.ts +11 -0
- package/package.json +117 -0
- package/plannotator.webp +0 -0
- package/print.css +427 -0
- package/shortcuts/code-review/ai.shortcuts.ts +25 -0
- package/shortcuts/code-review/allFilesDiff.shortcuts.ts +46 -0
- package/shortcuts/code-review/annotationToolbar.shortcuts.ts +30 -0
- package/shortcuts/code-review/fileTree.shortcuts.ts +35 -0
- package/shortcuts/code-review/prComments.shortcuts.ts +18 -0
- package/shortcuts/code-review/suggestionModal.shortcuts.ts +25 -0
- package/shortcuts/code-review/tourDialog.shortcuts.ts +18 -0
- package/shortcuts/core.ts +399 -0
- package/shortcuts/index.ts +21 -0
- package/shortcuts/plan-review/annotationPanel.shortcuts.ts +25 -0
- package/shortcuts/plan-review/annotationToolbar.shortcuts.ts +39 -0
- package/shortcuts/plan-review/commentPopover.shortcuts.ts +21 -0
- package/shortcuts/plan-review/goalSetup.shortcuts.ts +10 -0
- package/shortcuts/plan-review/imageAnnotator.shortcuts.ts +42 -0
- package/shortcuts/plan-review/inputMethod.shortcuts.ts +30 -0
- package/shortcuts/plan-review/sidebar.shortcuts.ts +34 -0
- package/shortcuts/plan-review/viewer.shortcuts.ts +24 -0
- package/shortcuts/runtime.ts +259 -0
- package/sprite_package_additional/index.html +34 -0
- package/sprite_package_additional/sprite.png +0 -0
- package/sprite_package_new/index.html +34 -0
- package/sprite_package_new/sprite.png +0 -0
- package/sprite_package_pulluphang/index.html +34 -0
- package/sprite_package_pulluphang/sprite.png +0 -0
- package/styles.css +1 -0
- package/theme.css +893 -0
- package/themes/adwaita.css +62 -0
- package/themes/andromeeda.css +66 -0
- package/themes/aurora-x.css +66 -0
- package/themes/ayu-dark.css +66 -0
- package/themes/caffeine.css +113 -0
- package/themes/catppuccin.css +62 -0
- package/themes/claude-plus.css +60 -0
- package/themes/cursor-hc.css +34 -0
- package/themes/cursor-midnight.css +34 -0
- package/themes/cursor.css +62 -0
- package/themes/dark-plus.css +66 -0
- package/themes/doom-64.css +109 -0
- package/themes/dracula.css +33 -0
- package/themes/everforest-hard.css +62 -0
- package/themes/everforest-soft.css +62 -0
- package/themes/everforest.css +62 -0
- package/themes/github.css +66 -0
- package/themes/gruvbox.css +62 -0
- package/themes/houston.css +66 -0
- package/themes/kanagawa-dragon.css +34 -0
- package/themes/kanagawa-lotus.css +34 -0
- package/themes/kanagawa-wave.css +34 -0
- package/themes/laserwave.css +66 -0
- package/themes/material.css +62 -0
- package/themes/min.css +66 -0
- package/themes/monokai-pro.css +34 -0
- package/themes/neutral.css +59 -0
- package/themes/night-owl.css +66 -0
- package/themes/nord.css +66 -0
- package/themes/one-dark-pro.css +66 -0
- package/themes/one-light.css +66 -0
- package/themes/paulmillr.css +34 -0
- package/themes/plannotator.css +60 -0
- package/themes/plastic.css +66 -0
- package/themes/poimandres.css +66 -0
- package/themes/quantum-rose.css +109 -0
- package/themes/red.css +66 -0
- package/themes/rose-pine.css +62 -0
- package/themes/simple.css +124 -0
- package/themes/slack.css +66 -0
- package/themes/snazzy-light.css +66 -0
- package/themes/soft-pop.css +60 -0
- package/themes/solar-dusk.css +109 -0
- package/themes/solarized.css +66 -0
- package/themes/synthwave-84.css +34 -0
- package/themes/terminal.css +62 -0
- package/themes/tinacious.css +57 -0
- package/themes/tokyo-night.css +62 -0
- package/themes/vesper.css +62 -0
- package/themes/vitesse-black.css +66 -0
- package/themes/vitesse.css +62 -0
- package/types.ts +264 -0
- package/utils/agentSwitch.ts +71 -0
- package/utils/aiChatFormat.ts +33 -0
- package/utils/aiPrompt.ts +29 -0
- package/utils/aiProvider.ts +217 -0
- package/utils/anchors.ts +11 -0
- package/utils/annotateAgentTerminal.ts +29 -0
- package/utils/annotationHelpers.ts +101 -0
- package/utils/bear.ts +59 -0
- package/utils/blockTargeting.ts +240 -0
- package/utils/callback.ts +99 -0
- package/utils/commentContent.ts +8 -0
- package/utils/defaultNotesApp.ts +20 -0
- package/utils/diffFonts.ts +33 -0
- package/utils/editorMode.ts +31 -0
- package/utils/fileBrowser.ts +40 -0
- package/utils/generateId.ts +7 -0
- package/utils/generateIdentity.ts +29 -0
- package/utils/identity.ts +112 -0
- package/utils/inlineTransforms.ts +41 -0
- package/utils/inputMethod.ts +17 -0
- package/utils/lookAndFeelAnnouncement.ts +18 -0
- package/utils/obsidian.ts +201 -0
- package/utils/octarine.ts +53 -0
- package/utils/parser.ts +991 -0
- package/utils/permissionMode.ts +77 -0
- package/utils/planAIAnnouncement.ts +17 -0
- package/utils/planAgentInstructions.ts +137 -0
- package/utils/planDiffEngine.ts +590 -0
- package/utils/planSave.ts +49 -0
- package/utils/platform.ts +11 -0
- package/utils/quickLabels.ts +77 -0
- package/utils/reviewAgentInstructions.ts +182 -0
- package/utils/sanitizeHtml.ts +45 -0
- package/utils/sharing.ts +350 -0
- package/utils/slugify.ts +37 -0
- package/utils/storage.ts +141 -0
- package/utils/themeRegistry.ts +567 -0
- package/utils/uiPreferences.ts +34 -0
- package/utils/upload.ts +56 -0
- package/utils/wideMode.ts +48 -0
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SidebarContainer — Shared sidebar shell
|
|
3
|
+
*
|
|
4
|
+
* Houses the Table of Contents, Version Browser, File Browser, and Archive Browser views.
|
|
5
|
+
* Tab bar at top switches between them.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React from "react";
|
|
9
|
+
import type { SidebarTab } from "../../hooks/useSidebar";
|
|
10
|
+
import type { Block, Annotation } from "../../types";
|
|
11
|
+
import type { VersionInfo, VersionEntry } from "../../hooks/usePlanDiff";
|
|
12
|
+
import type { UseFileBrowserReturn } from "../../hooks/useFileBrowser";
|
|
13
|
+
import { TableOfContents } from "../TableOfContents";
|
|
14
|
+
import { VersionBrowser } from "./VersionBrowser";
|
|
15
|
+
import { FileBrowser, type FileEditStatus } from "./FileBrowser";
|
|
16
|
+
import { ArchiveBrowser, type ArchivedPlan } from "./ArchiveBrowser";
|
|
17
|
+
import { MessagesBrowser, type PickerMessage } from "./MessagesBrowser";
|
|
18
|
+
import { MessagesIcon } from "../icons/MessagesIcon";
|
|
19
|
+
import { OverlayScrollArea } from "../OverlayScrollArea";
|
|
20
|
+
import { ReviewAgentsIcon } from "../ReviewAgentsIcon";
|
|
21
|
+
|
|
22
|
+
interface SidebarContainerProps {
|
|
23
|
+
activeTab: SidebarTab;
|
|
24
|
+
onTabChange: (tab: SidebarTab) => void;
|
|
25
|
+
onClose: () => void;
|
|
26
|
+
width: number | string;
|
|
27
|
+
showAgentTerminalButton?: boolean;
|
|
28
|
+
isAgentTerminalOpen?: boolean;
|
|
29
|
+
isAgentTerminalRunning?: boolean;
|
|
30
|
+
onToggleAgentTerminal?: () => void;
|
|
31
|
+
// TOC props
|
|
32
|
+
blocks: Block[];
|
|
33
|
+
annotations: Annotation[];
|
|
34
|
+
activeSection: string | null;
|
|
35
|
+
onTocNavigate: (blockId: string) => void;
|
|
36
|
+
linkedDocFilepath?: string | null;
|
|
37
|
+
onLinkedDocBack?: () => void;
|
|
38
|
+
backLabel?: string;
|
|
39
|
+
// File Browser props
|
|
40
|
+
showFilesTab?: boolean;
|
|
41
|
+
fileAnnotationCounts?: Map<string, number>;
|
|
42
|
+
highlightedFiles?: Set<string>;
|
|
43
|
+
fileEditStatuses?: Map<string, FileEditStatus>;
|
|
44
|
+
fileBrowser?: UseFileBrowserReturn;
|
|
45
|
+
onFilesSelectFile?: (absolutePath: string, dirPath: string) => void;
|
|
46
|
+
onFilesFetchAll?: () => void;
|
|
47
|
+
onFilesRetryVaultDir?: (vaultPath: string) => void;
|
|
48
|
+
// Version Browser props
|
|
49
|
+
showVersionsTab?: boolean;
|
|
50
|
+
versionInfo: VersionInfo | null;
|
|
51
|
+
versions: VersionEntry[];
|
|
52
|
+
selectedBaseVersion: number | null;
|
|
53
|
+
onSelectBaseVersion: (version: number) => void;
|
|
54
|
+
isPlanDiffActive: boolean;
|
|
55
|
+
hasPreviousVersion: boolean;
|
|
56
|
+
onActivatePlanDiff: () => void;
|
|
57
|
+
isLoadingVersions: boolean;
|
|
58
|
+
isSelectingVersion: boolean;
|
|
59
|
+
fetchingVersion: number | null;
|
|
60
|
+
onFetchVersions: () => void;
|
|
61
|
+
// Annotation indicators
|
|
62
|
+
hasFileAnnotations?: boolean;
|
|
63
|
+
// Archive Browser props
|
|
64
|
+
showArchiveTab?: boolean;
|
|
65
|
+
archivePlans: ArchivedPlan[];
|
|
66
|
+
selectedArchiveFile: string | null;
|
|
67
|
+
onArchiveSelect: (filename: string) => void;
|
|
68
|
+
isLoadingArchive: boolean;
|
|
69
|
+
showMessagesTab?: boolean;
|
|
70
|
+
messages?: PickerMessage[];
|
|
71
|
+
selectedMessageId?: string | null;
|
|
72
|
+
onSelectMessage?: (messageId: string) => void;
|
|
73
|
+
messageAnnotationCounts?: Map<string, number>;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export const SidebarContainer: React.FC<SidebarContainerProps> = ({
|
|
77
|
+
activeTab,
|
|
78
|
+
onTabChange,
|
|
79
|
+
onClose,
|
|
80
|
+
width,
|
|
81
|
+
showAgentTerminalButton,
|
|
82
|
+
isAgentTerminalOpen,
|
|
83
|
+
isAgentTerminalRunning,
|
|
84
|
+
onToggleAgentTerminal,
|
|
85
|
+
blocks,
|
|
86
|
+
annotations,
|
|
87
|
+
activeSection,
|
|
88
|
+
onTocNavigate,
|
|
89
|
+
linkedDocFilepath,
|
|
90
|
+
onLinkedDocBack,
|
|
91
|
+
backLabel,
|
|
92
|
+
showFilesTab,
|
|
93
|
+
fileAnnotationCounts,
|
|
94
|
+
highlightedFiles,
|
|
95
|
+
fileEditStatuses,
|
|
96
|
+
fileBrowser,
|
|
97
|
+
onFilesSelectFile,
|
|
98
|
+
onFilesFetchAll,
|
|
99
|
+
onFilesRetryVaultDir,
|
|
100
|
+
showVersionsTab,
|
|
101
|
+
versionInfo,
|
|
102
|
+
versions,
|
|
103
|
+
selectedBaseVersion,
|
|
104
|
+
onSelectBaseVersion,
|
|
105
|
+
isPlanDiffActive,
|
|
106
|
+
hasPreviousVersion,
|
|
107
|
+
onActivatePlanDiff,
|
|
108
|
+
isLoadingVersions,
|
|
109
|
+
isSelectingVersion,
|
|
110
|
+
fetchingVersion,
|
|
111
|
+
onFetchVersions,
|
|
112
|
+
hasFileAnnotations,
|
|
113
|
+
showArchiveTab,
|
|
114
|
+
archivePlans,
|
|
115
|
+
selectedArchiveFile,
|
|
116
|
+
onArchiveSelect,
|
|
117
|
+
isLoadingArchive,
|
|
118
|
+
showMessagesTab,
|
|
119
|
+
messages,
|
|
120
|
+
selectedMessageId,
|
|
121
|
+
onSelectMessage,
|
|
122
|
+
messageAnnotationCounts,
|
|
123
|
+
}) => {
|
|
124
|
+
return (
|
|
125
|
+
<aside
|
|
126
|
+
className="hidden lg:flex flex-col sticky top-12 h-[calc(100vh-3rem)] flex-shrink-0 bg-card border-r border-border"
|
|
127
|
+
style={{ width }}
|
|
128
|
+
>
|
|
129
|
+
{/* Tab bar */}
|
|
130
|
+
<div className="flex h-10 items-center border-b border-border/50 px-2 gap-0.5 flex-shrink-0 overflow-hidden min-w-0">
|
|
131
|
+
{showAgentTerminalButton && onToggleAgentTerminal && (
|
|
132
|
+
<ActionButton
|
|
133
|
+
active={!!isAgentTerminalOpen}
|
|
134
|
+
running={!!isAgentTerminalRunning}
|
|
135
|
+
onClick={onToggleAgentTerminal}
|
|
136
|
+
icon={<ReviewAgentsIcon className="w-3 h-3" />}
|
|
137
|
+
label="Agent"
|
|
138
|
+
/>
|
|
139
|
+
)}
|
|
140
|
+
<TabButton
|
|
141
|
+
active={activeTab === "toc"}
|
|
142
|
+
onClick={() => onTabChange("toc")}
|
|
143
|
+
icon={
|
|
144
|
+
<svg
|
|
145
|
+
className="w-3 h-3"
|
|
146
|
+
fill="none"
|
|
147
|
+
viewBox="0 0 24 24"
|
|
148
|
+
stroke="currentColor"
|
|
149
|
+
strokeWidth={2}
|
|
150
|
+
>
|
|
151
|
+
<path
|
|
152
|
+
strokeLinecap="round"
|
|
153
|
+
strokeLinejoin="round"
|
|
154
|
+
d="M4 6h16M4 10h16M4 14h10M4 18h10"
|
|
155
|
+
/>
|
|
156
|
+
</svg>
|
|
157
|
+
}
|
|
158
|
+
label="Contents"
|
|
159
|
+
/>
|
|
160
|
+
{showVersionsTab && (
|
|
161
|
+
<TabButton
|
|
162
|
+
active={activeTab === "versions"}
|
|
163
|
+
onClick={() => onTabChange("versions")}
|
|
164
|
+
icon={
|
|
165
|
+
<svg
|
|
166
|
+
className="w-3 h-3"
|
|
167
|
+
fill="none"
|
|
168
|
+
viewBox="0 0 24 24"
|
|
169
|
+
stroke="currentColor"
|
|
170
|
+
strokeWidth={2}
|
|
171
|
+
>
|
|
172
|
+
<path
|
|
173
|
+
strokeLinecap="round"
|
|
174
|
+
strokeLinejoin="round"
|
|
175
|
+
d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"
|
|
176
|
+
/>
|
|
177
|
+
</svg>
|
|
178
|
+
}
|
|
179
|
+
label="Versions"
|
|
180
|
+
/>
|
|
181
|
+
)}
|
|
182
|
+
{showMessagesTab && (
|
|
183
|
+
<TabButton
|
|
184
|
+
active={activeTab === "messages"}
|
|
185
|
+
onClick={() => onTabChange("messages")}
|
|
186
|
+
icon={<MessagesIcon className="w-3 h-3" />}
|
|
187
|
+
label="Messages"
|
|
188
|
+
badge={messageAnnotationCounts !== undefined && messageAnnotationCounts.size > 0}
|
|
189
|
+
/>
|
|
190
|
+
)}
|
|
191
|
+
{showFilesTab && (
|
|
192
|
+
<TabButton
|
|
193
|
+
active={activeTab === "files"}
|
|
194
|
+
onClick={() => onTabChange("files")}
|
|
195
|
+
icon={
|
|
196
|
+
<svg
|
|
197
|
+
className="w-3 h-3"
|
|
198
|
+
fill="none"
|
|
199
|
+
viewBox="0 0 24 24"
|
|
200
|
+
stroke="currentColor"
|
|
201
|
+
strokeWidth={2}
|
|
202
|
+
>
|
|
203
|
+
<path
|
|
204
|
+
strokeLinecap="round"
|
|
205
|
+
strokeLinejoin="round"
|
|
206
|
+
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
|
207
|
+
/>
|
|
208
|
+
</svg>
|
|
209
|
+
}
|
|
210
|
+
label="Files"
|
|
211
|
+
badge={hasFileAnnotations}
|
|
212
|
+
/>
|
|
213
|
+
)}
|
|
214
|
+
{showArchiveTab && (
|
|
215
|
+
<TabButton
|
|
216
|
+
active={activeTab === "archive"}
|
|
217
|
+
onClick={() => onTabChange("archive")}
|
|
218
|
+
icon={
|
|
219
|
+
<svg
|
|
220
|
+
className="w-3 h-3"
|
|
221
|
+
fill="none"
|
|
222
|
+
viewBox="0 0 24 24"
|
|
223
|
+
stroke="currentColor"
|
|
224
|
+
strokeWidth={2}
|
|
225
|
+
>
|
|
226
|
+
<path
|
|
227
|
+
strokeLinecap="round"
|
|
228
|
+
strokeLinejoin="round"
|
|
229
|
+
d="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4"
|
|
230
|
+
/>
|
|
231
|
+
</svg>
|
|
232
|
+
}
|
|
233
|
+
label="Archive"
|
|
234
|
+
/>
|
|
235
|
+
)}
|
|
236
|
+
{/* No header close button — the sidebar collapses via the resize-handle
|
|
237
|
+
hover button (see ResizeHandle onCollapse). */}
|
|
238
|
+
</div>
|
|
239
|
+
|
|
240
|
+
{/* Content area */}
|
|
241
|
+
<OverlayScrollArea className="flex-1 min-h-0">
|
|
242
|
+
{activeTab === "toc" && (
|
|
243
|
+
<TableOfContents
|
|
244
|
+
blocks={blocks}
|
|
245
|
+
annotations={annotations}
|
|
246
|
+
activeId={activeSection}
|
|
247
|
+
onNavigate={onTocNavigate}
|
|
248
|
+
className=""
|
|
249
|
+
linkedDocFilepath={linkedDocFilepath}
|
|
250
|
+
onLinkedDocBack={onLinkedDocBack}
|
|
251
|
+
backLabel={backLabel}
|
|
252
|
+
/>
|
|
253
|
+
)}
|
|
254
|
+
{activeTab === "versions" && (
|
|
255
|
+
<VersionBrowser
|
|
256
|
+
versionInfo={versionInfo}
|
|
257
|
+
versions={versions}
|
|
258
|
+
selectedBaseVersion={selectedBaseVersion}
|
|
259
|
+
onSelectBaseVersion={onSelectBaseVersion}
|
|
260
|
+
isPlanDiffActive={isPlanDiffActive}
|
|
261
|
+
hasPreviousVersion={hasPreviousVersion}
|
|
262
|
+
onActivatePlanDiff={onActivatePlanDiff}
|
|
263
|
+
isLoading={isLoadingVersions}
|
|
264
|
+
isSelectingVersion={isSelectingVersion}
|
|
265
|
+
fetchingVersion={fetchingVersion}
|
|
266
|
+
onFetchVersions={onFetchVersions}
|
|
267
|
+
/>
|
|
268
|
+
)}
|
|
269
|
+
{activeTab === "files" && showFilesTab && fileBrowser && (
|
|
270
|
+
<FileBrowser
|
|
271
|
+
dirs={fileBrowser.dirs}
|
|
272
|
+
expandedFolders={fileBrowser.expandedFolders}
|
|
273
|
+
onToggleFolder={fileBrowser.toggleFolder}
|
|
274
|
+
collapsedDirs={fileBrowser.collapsedDirs}
|
|
275
|
+
onToggleCollapse={fileBrowser.toggleCollapse}
|
|
276
|
+
onSelectFile={onFilesSelectFile ?? (() => {})}
|
|
277
|
+
activeFile={fileBrowser.activeFile}
|
|
278
|
+
onFetchAll={onFilesFetchAll ?? (() => {})}
|
|
279
|
+
onRetryVaultDir={onFilesRetryVaultDir}
|
|
280
|
+
annotationCounts={fileAnnotationCounts}
|
|
281
|
+
highlightedFiles={highlightedFiles}
|
|
282
|
+
editStatuses={fileEditStatuses}
|
|
283
|
+
/>
|
|
284
|
+
)}
|
|
285
|
+
{activeTab === "archive" && showArchiveTab && (
|
|
286
|
+
<ArchiveBrowser
|
|
287
|
+
plans={archivePlans}
|
|
288
|
+
selectedFile={selectedArchiveFile}
|
|
289
|
+
onSelect={onArchiveSelect}
|
|
290
|
+
isLoading={isLoadingArchive}
|
|
291
|
+
/>
|
|
292
|
+
)}
|
|
293
|
+
{activeTab === "messages" && showMessagesTab && messages && onSelectMessage && (
|
|
294
|
+
<MessagesBrowser
|
|
295
|
+
messages={messages}
|
|
296
|
+
selectedMessageId={selectedMessageId ?? null}
|
|
297
|
+
onSelect={onSelectMessage}
|
|
298
|
+
annotationCounts={messageAnnotationCounts}
|
|
299
|
+
/>
|
|
300
|
+
)}
|
|
301
|
+
</OverlayScrollArea>
|
|
302
|
+
</aside>
|
|
303
|
+
);
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
const TabButton: React.FC<{
|
|
307
|
+
active: boolean;
|
|
308
|
+
onClick: () => void;
|
|
309
|
+
icon: React.ReactNode;
|
|
310
|
+
label: string;
|
|
311
|
+
badge?: boolean;
|
|
312
|
+
}> = ({ active, onClick, icon, label, badge }) => (
|
|
313
|
+
<button
|
|
314
|
+
onClick={onClick}
|
|
315
|
+
className={`relative flex items-center gap-1 px-2 py-1 rounded text-xs font-medium transition-colors min-w-0 shrink-0 ${
|
|
316
|
+
active
|
|
317
|
+
? "bg-primary/10 text-primary"
|
|
318
|
+
: "text-muted-foreground hover:text-foreground hover:bg-muted/50"
|
|
319
|
+
}`}
|
|
320
|
+
>
|
|
321
|
+
{icon}
|
|
322
|
+
{label}
|
|
323
|
+
{badge && (
|
|
324
|
+
<span className="absolute -top-0.5 -right-0.5 w-1.5 h-1.5 rounded-full bg-primary" />
|
|
325
|
+
)}
|
|
326
|
+
</button>
|
|
327
|
+
);
|
|
328
|
+
|
|
329
|
+
const ActionButton: React.FC<{
|
|
330
|
+
active: boolean;
|
|
331
|
+
running?: boolean;
|
|
332
|
+
onClick: () => void;
|
|
333
|
+
icon: React.ReactNode;
|
|
334
|
+
label: string;
|
|
335
|
+
}> = ({ active, running, onClick, icon, label }) => (
|
|
336
|
+
<button
|
|
337
|
+
type="button"
|
|
338
|
+
onClick={onClick}
|
|
339
|
+
aria-pressed={active}
|
|
340
|
+
title={running ? "Agent running" : label}
|
|
341
|
+
className={`relative flex items-center gap-1 px-2 py-1 rounded text-xs font-medium transition-colors min-w-0 shrink-0 ${
|
|
342
|
+
active || running
|
|
343
|
+
? "bg-primary/10 text-primary"
|
|
344
|
+
: "text-muted-foreground hover:text-foreground hover:bg-muted/50"
|
|
345
|
+
}`}
|
|
346
|
+
>
|
|
347
|
+
{icon}
|
|
348
|
+
{label}
|
|
349
|
+
{running && (
|
|
350
|
+
<span className="absolute -top-0.5 -right-0.5 h-1.5 w-1.5 rounded-full bg-primary" />
|
|
351
|
+
)}
|
|
352
|
+
</button>
|
|
353
|
+
);
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SidebarTabs — Collapsed tab flags
|
|
3
|
+
*
|
|
4
|
+
* When the sidebar is closed, small vertical tabs protrude from the left edge.
|
|
5
|
+
* Clicking a tab opens the sidebar in that mode.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React from "react";
|
|
9
|
+
import type { SidebarTab } from "../../hooks/useSidebar";
|
|
10
|
+
import { MessagesIcon } from "../icons/MessagesIcon";
|
|
11
|
+
import { ReviewAgentsIcon } from "../ReviewAgentsIcon";
|
|
12
|
+
|
|
13
|
+
interface SidebarTabsProps {
|
|
14
|
+
activeTab: SidebarTab;
|
|
15
|
+
onToggleTab: (tab: SidebarTab) => void;
|
|
16
|
+
hasDiff: boolean;
|
|
17
|
+
showVersionsTab?: boolean;
|
|
18
|
+
showFilesTab?: boolean;
|
|
19
|
+
showMessagesTab?: boolean;
|
|
20
|
+
showAgentTerminalTab?: boolean;
|
|
21
|
+
isAgentTerminalOpen?: boolean;
|
|
22
|
+
isAgentTerminalRunning?: boolean;
|
|
23
|
+
onToggleAgentTerminal?: () => void;
|
|
24
|
+
hasFileAnnotations?: boolean;
|
|
25
|
+
hasMessageAnnotations?: boolean;
|
|
26
|
+
className?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const SidebarTabs: React.FC<SidebarTabsProps> = ({
|
|
30
|
+
activeTab,
|
|
31
|
+
onToggleTab,
|
|
32
|
+
hasDiff,
|
|
33
|
+
showVersionsTab,
|
|
34
|
+
showFilesTab,
|
|
35
|
+
showMessagesTab,
|
|
36
|
+
showAgentTerminalTab,
|
|
37
|
+
isAgentTerminalOpen,
|
|
38
|
+
isAgentTerminalRunning,
|
|
39
|
+
onToggleAgentTerminal,
|
|
40
|
+
hasFileAnnotations,
|
|
41
|
+
hasMessageAnnotations,
|
|
42
|
+
className,
|
|
43
|
+
}) => {
|
|
44
|
+
return (
|
|
45
|
+
<div
|
|
46
|
+
data-sidebar-tabs="true"
|
|
47
|
+
className={`flex flex-col gap-1 pt-3 pl-0.5 flex-shrink-0 ${className ?? ""}`}
|
|
48
|
+
>
|
|
49
|
+
{showAgentTerminalTab && onToggleAgentTerminal && (
|
|
50
|
+
<button
|
|
51
|
+
onClick={onToggleAgentTerminal}
|
|
52
|
+
className={`sidebar-tab-flag group relative flex items-center justify-center w-7 h-9 rounded-r-md border border-l-0 border-border/50 bg-card/80 backdrop-blur-sm transition-colors ${
|
|
53
|
+
isAgentTerminalOpen || isAgentTerminalRunning
|
|
54
|
+
? "text-primary"
|
|
55
|
+
: "text-muted-foreground hover:text-foreground hover:bg-card"
|
|
56
|
+
}`}
|
|
57
|
+
title={isAgentTerminalRunning ? "Agent running" : "Agent"}
|
|
58
|
+
aria-pressed={isAgentTerminalOpen}
|
|
59
|
+
>
|
|
60
|
+
<ReviewAgentsIcon className="w-3.5 h-3.5" />
|
|
61
|
+
{isAgentTerminalRunning && (
|
|
62
|
+
<span className="absolute top-1 right-1 h-1.5 w-1.5 rounded-full bg-primary" />
|
|
63
|
+
)}
|
|
64
|
+
</button>
|
|
65
|
+
)}
|
|
66
|
+
|
|
67
|
+
{/* TOC tab */}
|
|
68
|
+
<button
|
|
69
|
+
onClick={() => onToggleTab("toc")}
|
|
70
|
+
className="sidebar-tab-flag group flex items-center justify-center w-7 h-9 rounded-r-md border border-l-0 border-border/50 bg-card/80 backdrop-blur-sm text-muted-foreground hover:text-foreground hover:bg-card transition-colors"
|
|
71
|
+
title="Table of Contents"
|
|
72
|
+
>
|
|
73
|
+
<svg
|
|
74
|
+
className="w-3.5 h-3.5"
|
|
75
|
+
fill="none"
|
|
76
|
+
viewBox="0 0 24 24"
|
|
77
|
+
stroke="currentColor"
|
|
78
|
+
strokeWidth={2}
|
|
79
|
+
>
|
|
80
|
+
<path
|
|
81
|
+
strokeLinecap="round"
|
|
82
|
+
strokeLinejoin="round"
|
|
83
|
+
d="M4 6h16M4 10h16M4 14h10M4 18h10"
|
|
84
|
+
/>
|
|
85
|
+
</svg>
|
|
86
|
+
</button>
|
|
87
|
+
|
|
88
|
+
{/* Versions tab — only shown when multiple versions exist */}
|
|
89
|
+
{showVersionsTab && (
|
|
90
|
+
<button
|
|
91
|
+
onClick={() => onToggleTab("versions")}
|
|
92
|
+
className="sidebar-tab-flag group relative flex items-center justify-center w-7 h-9 rounded-r-md border border-l-0 border-border/50 bg-card/80 backdrop-blur-sm text-muted-foreground hover:text-foreground hover:bg-card transition-colors"
|
|
93
|
+
title="Plan Versions"
|
|
94
|
+
>
|
|
95
|
+
<svg
|
|
96
|
+
className="w-3.5 h-3.5"
|
|
97
|
+
fill="none"
|
|
98
|
+
viewBox="0 0 24 24"
|
|
99
|
+
stroke="currentColor"
|
|
100
|
+
strokeWidth={2}
|
|
101
|
+
>
|
|
102
|
+
<path
|
|
103
|
+
strokeLinecap="round"
|
|
104
|
+
strokeLinejoin="round"
|
|
105
|
+
d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"
|
|
106
|
+
/>
|
|
107
|
+
</svg>
|
|
108
|
+
{/* Availability indicator dot */}
|
|
109
|
+
{hasDiff && (
|
|
110
|
+
<span className="absolute top-1 right-1 w-1.5 h-1.5 rounded-full bg-primary" />
|
|
111
|
+
)}
|
|
112
|
+
</button>
|
|
113
|
+
)}
|
|
114
|
+
|
|
115
|
+
{showMessagesTab && (
|
|
116
|
+
<button
|
|
117
|
+
onClick={() => onToggleTab("messages")}
|
|
118
|
+
className="sidebar-tab-flag group relative flex items-center justify-center w-7 h-9 rounded-r-md border border-l-0 border-border/50 bg-card/80 backdrop-blur-sm text-muted-foreground hover:text-foreground hover:bg-card transition-colors"
|
|
119
|
+
title="Pick a different message"
|
|
120
|
+
>
|
|
121
|
+
<MessagesIcon />
|
|
122
|
+
{hasMessageAnnotations && (
|
|
123
|
+
<span className="absolute top-1 right-1 w-1.5 h-1.5 rounded-full bg-primary" />
|
|
124
|
+
)}
|
|
125
|
+
</button>
|
|
126
|
+
)}
|
|
127
|
+
|
|
128
|
+
{/* Files tab */}
|
|
129
|
+
{showFilesTab && (
|
|
130
|
+
<button
|
|
131
|
+
onClick={() => onToggleTab("files")}
|
|
132
|
+
className="sidebar-tab-flag group relative flex items-center justify-center w-7 h-9 rounded-r-md border border-l-0 border-border/50 bg-card/80 backdrop-blur-sm text-muted-foreground hover:text-foreground hover:bg-card transition-colors"
|
|
133
|
+
title="File Browser"
|
|
134
|
+
>
|
|
135
|
+
<svg
|
|
136
|
+
className="w-3.5 h-3.5"
|
|
137
|
+
fill="none"
|
|
138
|
+
viewBox="0 0 24 24"
|
|
139
|
+
stroke="currentColor"
|
|
140
|
+
strokeWidth={2}
|
|
141
|
+
>
|
|
142
|
+
<path
|
|
143
|
+
strokeLinecap="round"
|
|
144
|
+
strokeLinejoin="round"
|
|
145
|
+
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
|
146
|
+
/>
|
|
147
|
+
</svg>
|
|
148
|
+
{hasFileAnnotations && (
|
|
149
|
+
<span className="absolute top-1 right-1 w-1.5 h-1.5 rounded-full bg-primary" />
|
|
150
|
+
)}
|
|
151
|
+
</button>
|
|
152
|
+
)}
|
|
153
|
+
</div>
|
|
154
|
+
);
|
|
155
|
+
};
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VersionBrowser — Version list for plan diff
|
|
3
|
+
*
|
|
4
|
+
* Shows all versions of the current plan and allows selecting
|
|
5
|
+
* which version to diff against.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import React, { useEffect } from "react";
|
|
9
|
+
import type { VersionInfo, VersionEntry } from "../../hooks/usePlanDiff";
|
|
10
|
+
|
|
11
|
+
interface VersionBrowserProps {
|
|
12
|
+
versionInfo: VersionInfo | null;
|
|
13
|
+
versions: VersionEntry[];
|
|
14
|
+
selectedBaseVersion: number | null;
|
|
15
|
+
onSelectBaseVersion: (version: number) => void;
|
|
16
|
+
isPlanDiffActive: boolean;
|
|
17
|
+
hasPreviousVersion: boolean;
|
|
18
|
+
onActivatePlanDiff: () => void;
|
|
19
|
+
isLoading: boolean;
|
|
20
|
+
isSelectingVersion: boolean;
|
|
21
|
+
fetchingVersion: number | null;
|
|
22
|
+
onFetchVersions: () => void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function relativeTime(timestamp: string): string {
|
|
26
|
+
if (!timestamp) return "";
|
|
27
|
+
const now = Date.now();
|
|
28
|
+
const then = new Date(timestamp).getTime();
|
|
29
|
+
const diff = now - then;
|
|
30
|
+
|
|
31
|
+
if (diff < 60_000) return "just now";
|
|
32
|
+
if (diff < 3_600_000) return `${Math.floor(diff / 60_000)}m ago`;
|
|
33
|
+
if (diff < 86_400_000) return `${Math.floor(diff / 3_600_000)}h ago`;
|
|
34
|
+
if (diff < 604_800_000) return `${Math.floor(diff / 86_400_000)}d ago`;
|
|
35
|
+
return new Date(timestamp).toLocaleDateString();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const VersionBrowser: React.FC<VersionBrowserProps> = ({
|
|
39
|
+
versionInfo,
|
|
40
|
+
versions,
|
|
41
|
+
selectedBaseVersion,
|
|
42
|
+
onSelectBaseVersion,
|
|
43
|
+
isPlanDiffActive,
|
|
44
|
+
hasPreviousVersion,
|
|
45
|
+
onActivatePlanDiff,
|
|
46
|
+
isLoading,
|
|
47
|
+
isSelectingVersion,
|
|
48
|
+
fetchingVersion,
|
|
49
|
+
onFetchVersions,
|
|
50
|
+
}) => {
|
|
51
|
+
// Fetch version list once versionInfo is available
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
if (versionInfo && versions.length === 0) {
|
|
54
|
+
onFetchVersions();
|
|
55
|
+
}
|
|
56
|
+
}, [versionInfo, versions.length, onFetchVersions]);
|
|
57
|
+
|
|
58
|
+
if (!versionInfo) {
|
|
59
|
+
return (
|
|
60
|
+
<div className="p-4 text-xs text-muted-foreground text-center">
|
|
61
|
+
No version history available.
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const currentVersion = versionInfo.version;
|
|
67
|
+
const totalVersions = versionInfo.totalVersions;
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
<div className="p-3">
|
|
71
|
+
{/* Current version info */}
|
|
72
|
+
<div className="mb-3">
|
|
73
|
+
<div className="text-[10px] font-medium text-muted-foreground uppercase tracking-wider mb-1">
|
|
74
|
+
Current Plan
|
|
75
|
+
</div>
|
|
76
|
+
<div className="text-xs text-foreground">
|
|
77
|
+
Version {currentVersion} of {totalVersions}
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
{/* Show Diff button if not active */}
|
|
82
|
+
{hasPreviousVersion && !isPlanDiffActive && (
|
|
83
|
+
<button
|
|
84
|
+
onClick={onActivatePlanDiff}
|
|
85
|
+
className="w-full mb-3 px-3 py-1.5 text-xs font-medium rounded-md bg-primary/10 text-primary hover:bg-primary/20 transition-colors border border-primary/20"
|
|
86
|
+
>
|
|
87
|
+
Show Changes
|
|
88
|
+
</button>
|
|
89
|
+
)}
|
|
90
|
+
|
|
91
|
+
{/* Version list */}
|
|
92
|
+
{totalVersions > 1 && (
|
|
93
|
+
<div className="mb-3">
|
|
94
|
+
<div className="text-[10px] font-medium text-muted-foreground uppercase tracking-wider mb-2">
|
|
95
|
+
Compare Against
|
|
96
|
+
</div>
|
|
97
|
+
|
|
98
|
+
{isLoading ? (
|
|
99
|
+
<div className="text-xs text-muted-foreground py-2 text-center">
|
|
100
|
+
Loading...
|
|
101
|
+
</div>
|
|
102
|
+
) : (
|
|
103
|
+
<div className="space-y-0.5">
|
|
104
|
+
{versions
|
|
105
|
+
.filter((v) => v.version !== currentVersion)
|
|
106
|
+
.reverse()
|
|
107
|
+
.map((v) => {
|
|
108
|
+
const isSelected = selectedBaseVersion === v.version;
|
|
109
|
+
return (
|
|
110
|
+
<button
|
|
111
|
+
key={v.version}
|
|
112
|
+
onClick={() => onSelectBaseVersion(v.version)}
|
|
113
|
+
className={`w-full text-left px-2 py-1.5 rounded text-xs transition-colors ${
|
|
114
|
+
isSelected
|
|
115
|
+
? "bg-primary/10 text-primary border border-primary/30"
|
|
116
|
+
: "text-foreground hover:bg-muted/50 border border-transparent"
|
|
117
|
+
}`}
|
|
118
|
+
>
|
|
119
|
+
<div className="flex items-center justify-between">
|
|
120
|
+
<span className="font-medium">
|
|
121
|
+
v{v.version}
|
|
122
|
+
{v.version === currentVersion - 1 && (
|
|
123
|
+
<span className="ml-1 text-muted-foreground font-normal">
|
|
124
|
+
(previous)
|
|
125
|
+
</span>
|
|
126
|
+
)}
|
|
127
|
+
</span>
|
|
128
|
+
<span className="text-[10px] text-muted-foreground">
|
|
129
|
+
{fetchingVersion === v.version ? "Loading..." : relativeTime(v.timestamp)}
|
|
130
|
+
</span>
|
|
131
|
+
</div>
|
|
132
|
+
</button>
|
|
133
|
+
);
|
|
134
|
+
})}
|
|
135
|
+
</div>
|
|
136
|
+
)}
|
|
137
|
+
</div>
|
|
138
|
+
)}
|
|
139
|
+
</div>
|
|
140
|
+
);
|
|
141
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Vite globals injected at build time
|
|
2
|
+
declare const __APP_VERSION__: string;
|
|
3
|
+
|
|
4
|
+
// Image asset module declarations live in ../globals.d.ts (the package's
|
|
5
|
+
// ambient-declaration home, /// <reference>'d by each asset-importing
|
|
6
|
+
// component so consumer compilers load them too). Declaring them here as
|
|
7
|
+
// well would be a duplicate-identifier error under skipLibCheck: false.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
2
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
3
|
+
import type * as React from "react";
|
|
4
|
+
|
|
5
|
+
import { cn } from "../../lib/utils";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Badge — small labelled token (status, category, count). Token-driven variants.
|
|
9
|
+
* Pass `asChild` to render as a link/button. Override padding/size via className
|
|
10
|
+
* for tighter inline badges (e.g. `px-1.5 py-px text-[10px]`).
|
|
11
|
+
*/
|
|
12
|
+
const badgeVariants = cva(
|
|
13
|
+
"inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-auto whitespace-nowrap rounded-md border px-3 py-1 text-xs font-medium transition-[color,box-shadow] [&>svg]:size-3 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
|
|
14
|
+
{
|
|
15
|
+
variants: {
|
|
16
|
+
variant: {
|
|
17
|
+
default: "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
|
|
18
|
+
secondary:
|
|
19
|
+
"border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
|
|
20
|
+
destructive:
|
|
21
|
+
"border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40",
|
|
22
|
+
outline: "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
defaultVariants: {
|
|
26
|
+
variant: "default",
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
function Badge({
|
|
32
|
+
className,
|
|
33
|
+
variant,
|
|
34
|
+
asChild = false,
|
|
35
|
+
...props
|
|
36
|
+
}: React.ComponentProps<"span"> & VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
|
|
37
|
+
const Comp = asChild ? Slot : "span";
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<Comp data-slot="badge" className={cn(badgeVariants({ variant }), className)} {...props} />
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export { Badge, badgeVariants };
|