@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,83 @@
|
|
|
1
|
+
import { Slot, Slottable } 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
|
+
* Button — the canonical action primitive (shared by the frontend shell and the
|
|
9
|
+
* embedded plan/review apps). cva variants + sizes, optional `iconLeft`/`iconRight`
|
|
10
|
+
* slots, and `asChild` for polymorphism.
|
|
11
|
+
*
|
|
12
|
+
* `success` (solid, token-driven green) covers the plan app's Approve action; the
|
|
13
|
+
* Feedback action uses `outline`. (No `accent` variant — `text-accent` on `bg-accent`
|
|
14
|
+
* has no contrast in neutral-accent themes.)
|
|
15
|
+
*/
|
|
16
|
+
const buttonVariants = cva(
|
|
17
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-[13px] font-medium transition-[color,background-color,box-shadow] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
|
18
|
+
{
|
|
19
|
+
variants: {
|
|
20
|
+
variant: {
|
|
21
|
+
default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
|
|
22
|
+
destructive:
|
|
23
|
+
"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40",
|
|
24
|
+
success: "bg-success text-success-foreground shadow-xs hover:bg-success/90",
|
|
25
|
+
outline:
|
|
26
|
+
"border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground",
|
|
27
|
+
secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
|
|
28
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
29
|
+
link: "text-primary underline-offset-4 hover:underline",
|
|
30
|
+
},
|
|
31
|
+
size: {
|
|
32
|
+
default: "h-9 px-4 py-2",
|
|
33
|
+
xxs: "h-6 rounded-md gap-1.5 px-2.5",
|
|
34
|
+
xs: "h-7 rounded-md gap-1.5 px-2.5",
|
|
35
|
+
sm: "h-8 rounded-md gap-1.5 px-3",
|
|
36
|
+
lg: "h-10 rounded-md px-6",
|
|
37
|
+
icon: "size-9",
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
defaultVariants: {
|
|
41
|
+
variant: "default",
|
|
42
|
+
size: "default",
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
type ButtonIcon = React.ReactNode;
|
|
48
|
+
|
|
49
|
+
function Button({
|
|
50
|
+
children,
|
|
51
|
+
className,
|
|
52
|
+
variant,
|
|
53
|
+
size,
|
|
54
|
+
asChild = false,
|
|
55
|
+
iconLeft,
|
|
56
|
+
iconRight,
|
|
57
|
+
...props
|
|
58
|
+
}: React.ComponentProps<"button"> &
|
|
59
|
+
VariantProps<typeof buttonVariants> & {
|
|
60
|
+
asChild?: boolean;
|
|
61
|
+
iconLeft?: ButtonIcon;
|
|
62
|
+
iconRight?: ButtonIcon;
|
|
63
|
+
}) {
|
|
64
|
+
const Comp = asChild ? Slot : "button";
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<Comp data-slot="button" className={cn(buttonVariants({ variant, size, className }))} {...props}>
|
|
68
|
+
{iconLeft ? (
|
|
69
|
+
<span data-slot="button-icon" data-side="left" aria-hidden="true" className="shrink-0">
|
|
70
|
+
{iconLeft}
|
|
71
|
+
</span>
|
|
72
|
+
) : null}
|
|
73
|
+
<Slottable>{children}</Slottable>
|
|
74
|
+
{iconRight ? (
|
|
75
|
+
<span data-slot="button-icon" data-side="right" aria-hidden="true" className="shrink-0">
|
|
76
|
+
{iconRight}
|
|
77
|
+
</span>
|
|
78
|
+
) : null}
|
|
79
|
+
</Comp>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export { Button, buttonVariants };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type * as React from "react";
|
|
2
|
+
|
|
3
|
+
import { cn } from "../../lib/utils";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Card — surface container primitive (shadcn-style).
|
|
7
|
+
*
|
|
8
|
+
* Composition: Card > CardHeader (CardTitle + CardDescription) / CardContent / CardFooter.
|
|
9
|
+
* Uses the shared token surface (`bg-card`/`text-card-foreground`) so it adapts to every
|
|
10
|
+
* theme. Pair with `shadow-[var(--card-shadow)]` (instead of `shadow-sm`) when you want
|
|
11
|
+
* the themed elevation used across the app shell.
|
|
12
|
+
*/
|
|
13
|
+
function Card({ className, ...props }: React.ComponentProps<"div">) {
|
|
14
|
+
return (
|
|
15
|
+
<div
|
|
16
|
+
data-slot="card"
|
|
17
|
+
className={cn(
|
|
18
|
+
"flex flex-col gap-6 rounded-xl border bg-card py-6 text-card-foreground shadow-sm",
|
|
19
|
+
className,
|
|
20
|
+
)}
|
|
21
|
+
{...props}
|
|
22
|
+
/>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|
27
|
+
return (
|
|
28
|
+
<div data-slot="card-header" className={cn("flex flex-col gap-1.5 px-6", className)} {...props} />
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
|
|
33
|
+
return (
|
|
34
|
+
<div data-slot="card-title" className={cn("font-semibold leading-none", className)} {...props} />
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
|
|
39
|
+
return (
|
|
40
|
+
<div
|
|
41
|
+
data-slot="card-description"
|
|
42
|
+
className={cn("text-sm text-muted-foreground", className)}
|
|
43
|
+
{...props}
|
|
44
|
+
/>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
|
|
49
|
+
return <div data-slot="card-content" className={cn("px-6", className)} {...props} />;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
|
|
53
|
+
return (
|
|
54
|
+
<div data-slot="card-footer" className={cn("flex items-center px-6", className)} {...props} />
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
3
|
+
import { X } from "lucide-react";
|
|
4
|
+
import { cn } from "../../lib/utils";
|
|
5
|
+
|
|
6
|
+
const Dialog = DialogPrimitive.Root;
|
|
7
|
+
const DialogTrigger = DialogPrimitive.Trigger;
|
|
8
|
+
const DialogPortal = DialogPrimitive.Portal;
|
|
9
|
+
const DialogClose = DialogPrimitive.Close;
|
|
10
|
+
|
|
11
|
+
const DialogOverlay = React.forwardRef<
|
|
12
|
+
React.ComponentRef<typeof DialogPrimitive.Overlay>,
|
|
13
|
+
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
|
|
14
|
+
>(({ className, ...props }, ref) => (
|
|
15
|
+
<DialogPrimitive.Overlay
|
|
16
|
+
ref={ref}
|
|
17
|
+
className={cn(
|
|
18
|
+
"fixed inset-0 z-[110] bg-black/55 backdrop-blur-[2px]",
|
|
19
|
+
"data-[state=open]:animate-in data-[state=open]:fade-in-0",
|
|
20
|
+
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0",
|
|
21
|
+
className,
|
|
22
|
+
)}
|
|
23
|
+
{...props}
|
|
24
|
+
/>
|
|
25
|
+
));
|
|
26
|
+
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
|
27
|
+
|
|
28
|
+
const DialogContent = React.forwardRef<
|
|
29
|
+
React.ComponentRef<typeof DialogPrimitive.Content>,
|
|
30
|
+
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {
|
|
31
|
+
hideClose?: boolean;
|
|
32
|
+
}
|
|
33
|
+
>(({ className, children, hideClose, ...props }, ref) => (
|
|
34
|
+
<DialogPortal>
|
|
35
|
+
<DialogOverlay />
|
|
36
|
+
<DialogPrimitive.Content
|
|
37
|
+
ref={ref}
|
|
38
|
+
className={cn(
|
|
39
|
+
"fixed top-[50%] left-[50%] z-[110] w-full translate-x-[-50%] translate-y-[-50%]",
|
|
40
|
+
"max-w-4xl max-h-[min(640px,85vh)]",
|
|
41
|
+
"flex flex-col overflow-hidden",
|
|
42
|
+
"rounded-2xl border border-border bg-popover text-popover-foreground",
|
|
43
|
+
"shadow-[0_24px_80px_-36px_rgba(15,23,42,0.5)]",
|
|
44
|
+
"data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
|
|
45
|
+
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
|
|
46
|
+
"duration-200",
|
|
47
|
+
className,
|
|
48
|
+
)}
|
|
49
|
+
{...props}
|
|
50
|
+
>
|
|
51
|
+
{children}
|
|
52
|
+
{!hideClose && (
|
|
53
|
+
<DialogPrimitive.Close className="absolute top-3.5 right-3.5 rounded-md p-1.5 text-muted-foreground hover:text-foreground focus:outline-none focus:ring-2 focus:ring-ring/50">
|
|
54
|
+
<X className="size-4" />
|
|
55
|
+
<span className="sr-only">Close</span>
|
|
56
|
+
</DialogPrimitive.Close>
|
|
57
|
+
)}
|
|
58
|
+
</DialogPrimitive.Content>
|
|
59
|
+
</DialogPortal>
|
|
60
|
+
));
|
|
61
|
+
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
|
62
|
+
|
|
63
|
+
function DialogHeader({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
|
|
64
|
+
return (
|
|
65
|
+
<div
|
|
66
|
+
className={cn("flex flex-col gap-1.5 border-b border-border px-5 py-4", className)}
|
|
67
|
+
{...props}
|
|
68
|
+
/>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const DialogTitle = React.forwardRef<
|
|
73
|
+
React.ComponentRef<typeof DialogPrimitive.Title>,
|
|
74
|
+
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
|
|
75
|
+
>(({ className, ...props }, ref) => (
|
|
76
|
+
<DialogPrimitive.Title
|
|
77
|
+
ref={ref}
|
|
78
|
+
className={cn("text-base font-semibold tracking-tight", className)}
|
|
79
|
+
{...props}
|
|
80
|
+
/>
|
|
81
|
+
));
|
|
82
|
+
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
|
83
|
+
|
|
84
|
+
const DialogDescription = React.forwardRef<
|
|
85
|
+
React.ComponentRef<typeof DialogPrimitive.Description>,
|
|
86
|
+
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
|
|
87
|
+
>(({ className, ...props }, ref) => (
|
|
88
|
+
<DialogPrimitive.Description
|
|
89
|
+
ref={ref}
|
|
90
|
+
className={cn("text-sm text-muted-foreground", className)}
|
|
91
|
+
{...props}
|
|
92
|
+
/>
|
|
93
|
+
));
|
|
94
|
+
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
|
95
|
+
|
|
96
|
+
export {
|
|
97
|
+
Dialog,
|
|
98
|
+
DialogPortal,
|
|
99
|
+
DialogOverlay,
|
|
100
|
+
DialogClose,
|
|
101
|
+
DialogTrigger,
|
|
102
|
+
DialogContent,
|
|
103
|
+
DialogHeader,
|
|
104
|
+
DialogTitle,
|
|
105
|
+
DialogDescription,
|
|
106
|
+
};
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
|
2
|
+
import { Check, ChevronRight, Circle } from "lucide-react";
|
|
3
|
+
import type * as React from "react";
|
|
4
|
+
|
|
5
|
+
import { cn } from "../../lib/utils";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* DropdownMenu — Radix-backed menu primitive (shadcn-style). Replaces the plan app's
|
|
9
|
+
* hand-rolled Approve dropdown / label picker / header menus. Icons via lucide-react.
|
|
10
|
+
*/
|
|
11
|
+
function DropdownMenu({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
|
|
12
|
+
return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function DropdownMenuPortal({
|
|
16
|
+
...props
|
|
17
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
|
|
18
|
+
return <DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function DropdownMenuTrigger({
|
|
22
|
+
...props
|
|
23
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
|
|
24
|
+
return <DropdownMenuPrimitive.Trigger data-slot="dropdown-menu-trigger" {...props} />;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function DropdownMenuContent({
|
|
28
|
+
className,
|
|
29
|
+
sideOffset = 4,
|
|
30
|
+
...props
|
|
31
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
|
|
32
|
+
return (
|
|
33
|
+
<DropdownMenuPrimitive.Portal>
|
|
34
|
+
<DropdownMenuPrimitive.Content
|
|
35
|
+
data-slot="dropdown-menu-content"
|
|
36
|
+
sideOffset={sideOffset}
|
|
37
|
+
className={cn(
|
|
38
|
+
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
|
39
|
+
className,
|
|
40
|
+
)}
|
|
41
|
+
{...props}
|
|
42
|
+
/>
|
|
43
|
+
</DropdownMenuPrimitive.Portal>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function DropdownMenuGroup({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
|
|
48
|
+
return <DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function DropdownMenuItem({
|
|
52
|
+
className,
|
|
53
|
+
inset,
|
|
54
|
+
variant = "default",
|
|
55
|
+
...props
|
|
56
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
|
|
57
|
+
inset?: boolean;
|
|
58
|
+
variant?: "default" | "destructive";
|
|
59
|
+
}) {
|
|
60
|
+
return (
|
|
61
|
+
<DropdownMenuPrimitive.Item
|
|
62
|
+
data-slot="dropdown-menu-item"
|
|
63
|
+
data-inset={inset}
|
|
64
|
+
data-variant={variant}
|
|
65
|
+
className={cn(
|
|
66
|
+
"relative flex cursor-default select-none items-center gap-2 rounded-md px-2 py-1.5 font-medium outline-hidden focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground",
|
|
67
|
+
className,
|
|
68
|
+
)}
|
|
69
|
+
{...props}
|
|
70
|
+
/>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function DropdownMenuCheckboxItem({
|
|
75
|
+
className,
|
|
76
|
+
children,
|
|
77
|
+
checked,
|
|
78
|
+
...props
|
|
79
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {
|
|
80
|
+
return (
|
|
81
|
+
<DropdownMenuPrimitive.CheckboxItem
|
|
82
|
+
data-slot="dropdown-menu-checkbox-item"
|
|
83
|
+
className={cn(
|
|
84
|
+
"relative flex cursor-default select-none items-center gap-2 rounded-md py-1.5 pl-8 pr-2 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
85
|
+
className,
|
|
86
|
+
)}
|
|
87
|
+
checked={checked}
|
|
88
|
+
{...props}
|
|
89
|
+
>
|
|
90
|
+
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
|
91
|
+
<DropdownMenuPrimitive.ItemIndicator>
|
|
92
|
+
<Check className="size-4" />
|
|
93
|
+
</DropdownMenuPrimitive.ItemIndicator>
|
|
94
|
+
</span>
|
|
95
|
+
{children}
|
|
96
|
+
</DropdownMenuPrimitive.CheckboxItem>
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function DropdownMenuRadioGroup({
|
|
101
|
+
...props
|
|
102
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
|
|
103
|
+
return <DropdownMenuPrimitive.RadioGroup data-slot="dropdown-menu-radio-group" {...props} />;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function DropdownMenuRadioItem({
|
|
107
|
+
className,
|
|
108
|
+
children,
|
|
109
|
+
...props
|
|
110
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {
|
|
111
|
+
return (
|
|
112
|
+
<DropdownMenuPrimitive.RadioItem
|
|
113
|
+
data-slot="dropdown-menu-radio-item"
|
|
114
|
+
className={cn(
|
|
115
|
+
"relative flex cursor-default select-none items-center gap-2 rounded-md py-1.5 pl-8 pr-2 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
116
|
+
className,
|
|
117
|
+
)}
|
|
118
|
+
{...props}
|
|
119
|
+
>
|
|
120
|
+
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
|
|
121
|
+
<DropdownMenuPrimitive.ItemIndicator>
|
|
122
|
+
<Circle className="size-2 fill-current" />
|
|
123
|
+
</DropdownMenuPrimitive.ItemIndicator>
|
|
124
|
+
</span>
|
|
125
|
+
{children}
|
|
126
|
+
</DropdownMenuPrimitive.RadioItem>
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function DropdownMenuLabel({
|
|
131
|
+
className,
|
|
132
|
+
inset,
|
|
133
|
+
...props
|
|
134
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & { inset?: boolean }) {
|
|
135
|
+
return (
|
|
136
|
+
<DropdownMenuPrimitive.Label
|
|
137
|
+
data-slot="dropdown-menu-label"
|
|
138
|
+
data-inset={inset}
|
|
139
|
+
className={cn("px-2 py-1.5 font-medium data-[inset]:pl-8", className)}
|
|
140
|
+
{...props}
|
|
141
|
+
/>
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function DropdownMenuSeparator({
|
|
146
|
+
className,
|
|
147
|
+
...props
|
|
148
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
|
|
149
|
+
return (
|
|
150
|
+
<DropdownMenuPrimitive.Separator
|
|
151
|
+
data-slot="dropdown-menu-separator"
|
|
152
|
+
className={cn("-mx-1 my-1 h-px bg-border", className)}
|
|
153
|
+
{...props}
|
|
154
|
+
/>
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function DropdownMenuShortcut({
|
|
159
|
+
className,
|
|
160
|
+
keys,
|
|
161
|
+
children,
|
|
162
|
+
...props
|
|
163
|
+
}: React.ComponentProps<"span"> & { keys?: string[] }) {
|
|
164
|
+
return (
|
|
165
|
+
<span
|
|
166
|
+
data-slot="dropdown-menu-shortcut"
|
|
167
|
+
className={cn("ml-auto flex items-center gap-1 text-[11px] text-muted-foreground", className)}
|
|
168
|
+
{...props}
|
|
169
|
+
>
|
|
170
|
+
{keys
|
|
171
|
+
? keys.map((key, i) => (
|
|
172
|
+
<span key={key} className="flex items-center gap-1">
|
|
173
|
+
{i > 0 && <span>then</span>}
|
|
174
|
+
<kbd className="font-sans">{key}</kbd>
|
|
175
|
+
</span>
|
|
176
|
+
))
|
|
177
|
+
: children}
|
|
178
|
+
</span>
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function DropdownMenuSub({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
|
|
183
|
+
return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function DropdownMenuSubTrigger({
|
|
187
|
+
className,
|
|
188
|
+
inset,
|
|
189
|
+
children,
|
|
190
|
+
...props
|
|
191
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & { inset?: boolean }) {
|
|
192
|
+
return (
|
|
193
|
+
<DropdownMenuPrimitive.SubTrigger
|
|
194
|
+
data-slot="dropdown-menu-sub-trigger"
|
|
195
|
+
data-inset={inset}
|
|
196
|
+
className={cn(
|
|
197
|
+
"flex cursor-default select-none items-center rounded-md px-2 py-1.5 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-[inset]:pl-8 data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
|
|
198
|
+
className,
|
|
199
|
+
)}
|
|
200
|
+
{...props}
|
|
201
|
+
>
|
|
202
|
+
{children}
|
|
203
|
+
<ChevronRight className="ml-auto size-4" />
|
|
204
|
+
</DropdownMenuPrimitive.SubTrigger>
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function DropdownMenuSubContent({
|
|
209
|
+
className,
|
|
210
|
+
...props
|
|
211
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
|
|
212
|
+
return (
|
|
213
|
+
<DropdownMenuPrimitive.SubContent
|
|
214
|
+
data-slot="dropdown-menu-sub-content"
|
|
215
|
+
className={cn(
|
|
216
|
+
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
|
217
|
+
className,
|
|
218
|
+
)}
|
|
219
|
+
{...props}
|
|
220
|
+
/>
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export {
|
|
225
|
+
DropdownMenu,
|
|
226
|
+
DropdownMenuPortal,
|
|
227
|
+
DropdownMenuTrigger,
|
|
228
|
+
DropdownMenuContent,
|
|
229
|
+
DropdownMenuGroup,
|
|
230
|
+
DropdownMenuLabel,
|
|
231
|
+
DropdownMenuItem,
|
|
232
|
+
DropdownMenuCheckboxItem,
|
|
233
|
+
DropdownMenuRadioGroup,
|
|
234
|
+
DropdownMenuRadioItem,
|
|
235
|
+
DropdownMenuSeparator,
|
|
236
|
+
DropdownMenuShortcut,
|
|
237
|
+
DropdownMenuSub,
|
|
238
|
+
DropdownMenuSubTrigger,
|
|
239
|
+
DropdownMenuSubContent,
|
|
240
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
2
|
+
import type * as React from "react";
|
|
3
|
+
|
|
4
|
+
import { cn } from "../../lib/utils";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* StatePill — semantic status indicator (PR/issue/session state). Rounded-full pill
|
|
8
|
+
* with tone-based color. Uses standard color ramps (green/red/purple) for instantly
|
|
9
|
+
* legible state rather than theme accent tokens.
|
|
10
|
+
*/
|
|
11
|
+
const statePillVariants = cva(
|
|
12
|
+
"inline-flex shrink-0 items-center gap-1 whitespace-nowrap rounded-full px-2 py-0.5 text-xs font-medium",
|
|
13
|
+
{
|
|
14
|
+
variants: {
|
|
15
|
+
tone: {
|
|
16
|
+
open: "bg-green-500/10 text-green-500",
|
|
17
|
+
closed: "bg-red-500/10 text-red-500",
|
|
18
|
+
merged: "bg-purple-500/10 text-purple-500",
|
|
19
|
+
muted: "bg-muted text-muted-foreground",
|
|
20
|
+
secondary: "bg-secondary text-secondary-foreground",
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
defaultVariants: {
|
|
24
|
+
tone: "muted",
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
export type StatePillTone = NonNullable<VariantProps<typeof statePillVariants>["tone"]>;
|
|
30
|
+
|
|
31
|
+
function StatePill({
|
|
32
|
+
className,
|
|
33
|
+
tone,
|
|
34
|
+
...props
|
|
35
|
+
}: React.ComponentProps<"span"> & VariantProps<typeof statePillVariants>) {
|
|
36
|
+
return (
|
|
37
|
+
<span
|
|
38
|
+
data-slot="state-pill"
|
|
39
|
+
className={cn(statePillVariants({ tone }), className)}
|
|
40
|
+
{...props}
|
|
41
|
+
/>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export { StatePill, statePillVariants };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as TabsPrimitive from "@radix-ui/react-tabs";
|
|
3
|
+
import { cn } from "../../lib/utils";
|
|
4
|
+
|
|
5
|
+
const Tabs = TabsPrimitive.Root;
|
|
6
|
+
|
|
7
|
+
const TabsList = React.forwardRef<
|
|
8
|
+
React.ComponentRef<typeof TabsPrimitive.List>,
|
|
9
|
+
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
|
|
10
|
+
>(({ className, ...props }, ref) => (
|
|
11
|
+
<TabsPrimitive.List
|
|
12
|
+
ref={ref}
|
|
13
|
+
className={cn("flex data-[orientation=vertical]:flex-col", className)}
|
|
14
|
+
{...props}
|
|
15
|
+
/>
|
|
16
|
+
));
|
|
17
|
+
TabsList.displayName = TabsPrimitive.List.displayName;
|
|
18
|
+
|
|
19
|
+
const TabsTrigger = React.forwardRef<
|
|
20
|
+
React.ComponentRef<typeof TabsPrimitive.Trigger>,
|
|
21
|
+
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
|
|
22
|
+
>(({ className, ...props }, ref) => (
|
|
23
|
+
<TabsPrimitive.Trigger
|
|
24
|
+
ref={ref}
|
|
25
|
+
className={cn(
|
|
26
|
+
"inline-flex items-center gap-2 rounded-md px-3 py-1.5 text-[13px] font-medium text-foreground",
|
|
27
|
+
"hover:bg-surface-1",
|
|
28
|
+
"data-[state=active]:bg-primary/10 data-[state=active]:text-foreground",
|
|
29
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50",
|
|
30
|
+
"disabled:pointer-events-none disabled:opacity-50",
|
|
31
|
+
className,
|
|
32
|
+
)}
|
|
33
|
+
{...props}
|
|
34
|
+
/>
|
|
35
|
+
));
|
|
36
|
+
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
|
|
37
|
+
|
|
38
|
+
const TabsContent = React.forwardRef<
|
|
39
|
+
React.ComponentRef<typeof TabsPrimitive.Content>,
|
|
40
|
+
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
|
|
41
|
+
>(({ className, ...props }, ref) => (
|
|
42
|
+
<TabsPrimitive.Content ref={ref} className={cn("flex-1 outline-none", className)} {...props} />
|
|
43
|
+
));
|
|
44
|
+
TabsContent.displayName = TabsPrimitive.Content.displayName;
|
|
45
|
+
|
|
46
|
+
export { Tabs, TabsList, TabsTrigger, TabsContent };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type * as React from "react";
|
|
2
|
+
|
|
3
|
+
import { cn } from "../../lib/utils";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Textarea — multi-line text input primitive. `field-sizing-content` auto-grows to
|
|
7
|
+
* fit content. Defaults to `bg-background`; pass `bg-card` via className when used
|
|
8
|
+
* inside an elevated surface (e.g. annotation/comment editors).
|
|
9
|
+
*/
|
|
10
|
+
function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
|
|
11
|
+
return (
|
|
12
|
+
<textarea
|
|
13
|
+
data-slot="textarea"
|
|
14
|
+
className={cn(
|
|
15
|
+
"flex field-sizing-content min-h-16 w-full rounded-md border border-input bg-background px-3 py-2 text-base shadow-xs outline-none transition-[color,box-shadow] placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
|
16
|
+
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
|
|
17
|
+
"aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
|
|
18
|
+
className,
|
|
19
|
+
)}
|
|
20
|
+
{...props}
|
|
21
|
+
/>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export { Textarea };
|