diffhub 0.1.1 → 0.1.2
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/.next/standalone/apps/web/.next/BUILD_ID +1 -1
- package/.next/standalone/apps/web/.next/build-manifest.json +3 -3
- package/.next/standalone/apps/web/.next/prerender-manifest.json +3 -3
- package/.next/standalone/apps/web/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/apps/web/.next/server/app/_global-error.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/_not-found/page.js +1 -1
- package/.next/standalone/apps/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/apps/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/apps/web/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/apps/web/.next/server/app/_not-found.rsc +16 -15
- package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_full.segment.rsc +16 -15
- package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
- package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_index.segment.rsc +5 -4
- package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/api/comments/route.js +1 -1
- package/.next/standalone/apps/web/.next/server/app/api/comments/route.js.nft.json +1 -1
- package/.next/standalone/apps/web/.next/server/app/api/diff/route.js +2 -2
- package/.next/standalone/apps/web/.next/server/app/api/diff/route.js.nft.json +1 -1
- package/.next/standalone/apps/web/.next/server/app/api/discard/route.js +2 -2
- package/.next/standalone/apps/web/.next/server/app/api/discard/route.js.nft.json +1 -1
- package/.next/standalone/apps/web/.next/server/app/api/file/route.js +2 -2
- package/.next/standalone/apps/web/.next/server/app/api/file/route.js.nft.json +1 -1
- package/.next/standalone/apps/web/.next/server/app/api/files/route.js +2 -2
- package/.next/standalone/apps/web/.next/server/app/api/files/route.js.nft.json +1 -1
- package/.next/standalone/apps/web/.next/server/app/index.html +1 -1
- package/.next/standalone/apps/web/.next/server/app/index.rsc +15 -14
- package/.next/standalone/apps/web/.next/server/app/index.segments/__PAGE__.segment.rsc +3 -3
- package/.next/standalone/apps/web/.next/server/app/index.segments/_full.segment.rsc +15 -14
- package/.next/standalone/apps/web/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/standalone/apps/web/.next/server/app/index.segments/_index.segment.rsc +5 -4
- package/.next/standalone/apps/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/page/react-loadable-manifest.json +2 -2
- package/.next/standalone/apps/web/.next/server/app/page.js +2 -2
- package/.next/standalone/apps/web/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/apps/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/apps/web/.next/server/chunks/[root-of-the-server]__05ejtyr._.js +3 -0
- package/.next/standalone/apps/web/.next/server/chunks/[root-of-the-server]__0e2dp4h._.js +3 -0
- package/.next/standalone/apps/web/.next/server/chunks/[root-of-the-server]__0egk6ui._.js +3 -0
- package/.next/standalone/apps/web/.next/server/chunks/[root-of-the-server]__0i6i-~n._.js +3 -0
- package/.next/standalone/apps/web/.next/server/chunks/[root-of-the-server]__0sv4hr9._.js +3 -0
- package/.next/standalone/apps/web/.next/server/chunks/[root-of-the-server]__0t.tl18._.js +3 -0
- package/.next/standalone/apps/web/.next/server/chunks/ssr/{[root-of-the-server]__06b81~v._.js → [root-of-the-server]__0giwc4b._.js} +2 -2
- package/.next/standalone/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0jit913._.js +3 -0
- package/.next/standalone/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0v19a7g._.js +3 -0
- package/.next/standalone/apps/web/.next/server/chunks/ssr/_0f40lcw._.js +3 -0
- package/.next/standalone/apps/web/.next/server/chunks/ssr/_0oc3qg_._.js +3 -3
- package/.next/standalone/apps/web/.next/server/chunks/ssr/{apps_web_0b_ykcu._.js → _0qo42r0._.js} +2 -2
- package/.next/standalone/apps/web/.next/server/chunks/ssr/{apps_web_08kf15u._.js → apps_web_0758ax4._.js} +2 -2
- package/.next/standalone/apps/web/.next/server/chunks/ssr/node_modules_0v8w2j~._.js +70 -0
- package/.next/standalone/apps/web/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/apps/web/.next/server/pages/404.html +1 -1
- package/.next/standalone/apps/web/.next/server/pages/500.html +1 -1
- package/.next/standalone/apps/web/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/apps/web/.next/server/server-reference-manifest.json +1 -1
- package/.next/standalone/apps/web/.next/static/chunks/{0-ci0c9di0qo8.js → 00zp83w4g1v1r.js} +3 -3
- package/.next/standalone/apps/web/.next/static/chunks/042ip11u2i2z6.js +138 -0
- package/.next/standalone/apps/web/.next/static/chunks/085s9eg867ha-.js +1 -0
- package/.next/standalone/apps/web/.next/static/chunks/0_vmme_k_ff_u.js +67 -0
- package/.next/standalone/apps/web/.next/static/chunks/0ap~_hc7r17_6.js +1 -0
- package/.next/standalone/apps/web/.next/static/chunks/0nt5-rwas5thn.js +67 -0
- package/.next/standalone/apps/web/.next/static/chunks/0p~3-4_.v0cft.js +1 -0
- package/.next/standalone/apps/web/.next/static/chunks/0wx-2dr44ql-g.js +1 -0
- package/.next/standalone/apps/web/.next/static/chunks/{0syypqto3~pe_.js → 0y0o261rjun_2.js} +8 -8
- package/.next/standalone/apps/web/.next/static/chunks/0y5z3t-z1c8ks.js.map +5 -0
- package/.next/standalone/apps/web/.next/static/chunks/17b.xoi.b6rcl.js +1 -0
- package/.next/standalone/apps/web/.next/static/chunks/turbopack-0_n_4n~_4no2a.js +1 -0
- package/.next/standalone/apps/web/.next/static/chunks/turbopack-worker-0sjn--fhq~1cg.js +1 -0
- package/.next/standalone/apps/web/.next/static/media/diffs.worker.09unk0quktc_5.ts +1 -0
- package/.next/standalone/apps/web/package.json +4 -4
- package/README.md +10 -3
- package/package.json +4 -4
- package/.next/standalone/apps/web/.next/server/chunks/[root-of-the-server]__05vwx85._.js +0 -3
- package/.next/standalone/apps/web/.next/server/chunks/[root-of-the-server]__09vmjc2._.js +0 -3
- package/.next/standalone/apps/web/.next/server/chunks/[root-of-the-server]__0etmu4u._.js +0 -3
- package/.next/standalone/apps/web/.next/server/chunks/[root-of-the-server]__0g-_a7n._.js +0 -3
- package/.next/standalone/apps/web/.next/server/chunks/[root-of-the-server]__0mshgfw._.js +0 -3
- package/.next/standalone/apps/web/.next/server/chunks/[root-of-the-server]__0qixima._.js +0 -3
- package/.next/standalone/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0f~hmsk._.js +0 -3
- package/.next/standalone/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0khyzju._.js +0 -3
- package/.next/standalone/apps/web/.next/server/chunks/ssr/[root-of-the-server]__0l2mjim._.js +0 -70
- package/.next/standalone/apps/web/.next/server/chunks/ssr/_0kwaklj._.js +0 -3
- package/.next/standalone/apps/web/.next/static/chunks/0.ae0sud8tm7k.js +0 -204
- package/.next/standalone/apps/web/.next/static/chunks/0di~ntk7iivm4.js +0 -1
- package/.next/standalone/apps/web/.next/static/chunks/0pklg0nmdvay8.js +0 -1
- package/.next/standalone/apps/web/.next/static/chunks/0up9_7hiwl_dt.js +0 -1
- package/.next/standalone/apps/web/.next/static/chunks/0~984a88e4rp9.js +0 -204
- package/.next/standalone/apps/web/.next/static/chunks/13y8355z8m13w.js +0 -1
- package/.next/standalone/apps/web/AGENTS.md +0 -60
- package/.next/standalone/apps/web/CHANGELOG.md +0 -7
- package/.next/standalone/apps/web/CLAUDE.md +0 -1
- package/.next/standalone/apps/web/README.md +0 -78
- package/.next/standalone/apps/web/app/api/comments/route.ts +0 -20
- package/.next/standalone/apps/web/app/api/diff/route.ts +0 -15
- package/.next/standalone/apps/web/app/api/discard/route.ts +0 -15
- package/.next/standalone/apps/web/app/api/file/route.ts +0 -17
- package/.next/standalone/apps/web/app/api/files/route.ts +0 -14
- package/.next/standalone/apps/web/app/api/open/route.ts +0 -64
- package/.next/standalone/apps/web/app/favicon.ico +0 -0
- package/.next/standalone/apps/web/app/globals.css +0 -214
- package/.next/standalone/apps/web/app/layout.tsx +0 -52
- package/.next/standalone/apps/web/app/page.tsx +0 -6
- package/.next/standalone/apps/web/bin/diffhub.mjs +0 -147
- package/.next/standalone/apps/web/components/ContextMenu.tsx +0 -161
- package/.next/standalone/apps/web/components/DiffApp.tsx +0 -419
- package/.next/standalone/apps/web/components/DiffViewer.tsx +0 -565
- package/.next/standalone/apps/web/components/FileDiffHeader.tsx +0 -119
- package/.next/standalone/apps/web/components/FileList.tsx +0 -455
- package/.next/standalone/apps/web/components/KeyboardShortcutsDialog.tsx +0 -79
- package/.next/standalone/apps/web/components/SidebarHelpMenu.tsx +0 -86
- package/.next/standalone/apps/web/components/StatusBar.tsx +0 -212
- package/.next/standalone/apps/web/components/icons/file-status-icons.tsx +0 -48
- package/.next/standalone/apps/web/components/theme-provider.tsx +0 -12
- package/.next/standalone/apps/web/components/ui/button.tsx +0 -90
- package/.next/standalone/apps/web/components/ui/empty.tsx +0 -82
- package/.next/standalone/apps/web/components/ui/input.tsx +0 -18
- package/.next/standalone/apps/web/components/ui/kbd.tsx +0 -14
- package/.next/standalone/apps/web/components/ui/separator.tsx +0 -23
- package/.next/standalone/apps/web/components/ui/sheet.tsx +0 -109
- package/.next/standalone/apps/web/components/ui/sidebar.tsx +0 -700
- package/.next/standalone/apps/web/components/ui/skeleton.tsx +0 -9
- package/.next/standalone/apps/web/components/ui/toggle.tsx +0 -35
- package/.next/standalone/apps/web/components/ui/tooltip.tsx +0 -52
- package/.next/standalone/apps/web/components.json +0 -27
- package/.next/standalone/apps/web/lib/comments.ts +0 -52
- package/.next/standalone/apps/web/lib/export-comments.ts +0 -13
- package/.next/standalone/apps/web/lib/git.ts +0 -201
- package/.next/standalone/apps/web/lib/use-mobile.ts +0 -19
- package/.next/standalone/apps/web/lib/utils.ts +0 -5
- package/.next/standalone/apps/web/next.config.ts +0 -19
- package/.next/standalone/apps/web/oxfmt.config.ts +0 -6
- package/.next/standalone/apps/web/oxlint.config.ts +0 -13
- package/.next/standalone/apps/web/postcss.config.mjs +0 -7
- package/.next/standalone/apps/web/public/file.svg +0 -1
- package/.next/standalone/apps/web/public/glide-variable-italic.woff2 +0 -0
- package/.next/standalone/apps/web/public/glide-variable.woff2 +0 -0
- package/.next/standalone/apps/web/public/globe.svg +0 -1
- package/.next/standalone/apps/web/public/next.svg +0 -1
- package/.next/standalone/apps/web/public/operator-mono-book-italic.woff2 +0 -0
- package/.next/standalone/apps/web/public/operator-mono-book.woff2 +0 -0
- package/.next/standalone/apps/web/public/operator-mono-medium-italic.woff2 +0 -0
- package/.next/standalone/apps/web/public/operator-mono-medium.woff2 +0 -0
- package/.next/standalone/apps/web/public/vercel.svg +0 -1
- package/.next/standalone/apps/web/public/window.svg +0 -1
- package/.next/standalone/apps/web/tsconfig.json +0 -34
- /package/.next/standalone/apps/web/.next/static/{ZhI_-YaFho-fQoajjgwSH → mAVCL4HCmtJwT35feBPdK}/_buildManifest.js +0 -0
- /package/.next/standalone/apps/web/.next/static/{ZhI_-YaFho-fQoajjgwSH → mAVCL4HCmtJwT35feBPdK}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/apps/web/.next/static/{ZhI_-YaFho-fQoajjgwSH → mAVCL4HCmtJwT35feBPdK}/_ssgManifest.js +0 -0
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
CopySimpleIcon,
|
|
5
|
-
CheckIcon,
|
|
6
|
-
ChevronDownIcon,
|
|
7
|
-
SunIcon,
|
|
8
|
-
MoonIcon,
|
|
9
|
-
SplitIcon,
|
|
10
|
-
ArrowRightIcon,
|
|
11
|
-
} from "blode-icons-react";
|
|
12
|
-
import { useTheme } from "next-themes";
|
|
13
|
-
import { useEffect, useRef, useState } from "react";
|
|
14
|
-
import type { Comment } from "@/lib/comments";
|
|
15
|
-
import { exportCommentsAsPrompt } from "@/lib/export-comments";
|
|
16
|
-
import { Button } from "@/components/ui/button";
|
|
17
|
-
import { cn } from "@/lib/utils";
|
|
18
|
-
|
|
19
|
-
export type DiffMode = "all" | "uncommitted";
|
|
20
|
-
|
|
21
|
-
const DIFF_MODES: { value: DiffMode; label: string }[] = [
|
|
22
|
-
{ label: "All changes", value: "all" },
|
|
23
|
-
{ label: "Uncommitted changes", value: "uncommitted" },
|
|
24
|
-
];
|
|
25
|
-
|
|
26
|
-
interface StatusBarProps {
|
|
27
|
-
branch: string;
|
|
28
|
-
baseBranch: string;
|
|
29
|
-
insertions: number;
|
|
30
|
-
deletions: number;
|
|
31
|
-
fileCount: number;
|
|
32
|
-
refreshing: boolean;
|
|
33
|
-
lastUpdated: Date | null;
|
|
34
|
-
comments: Comment[];
|
|
35
|
-
diffMode: DiffMode;
|
|
36
|
-
onDiffModeChange: (mode: DiffMode) => void;
|
|
37
|
-
layout: "split" | "stacked";
|
|
38
|
-
onLayoutChange: (l: "split" | "stacked") => void;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export const StatusBar = ({
|
|
42
|
-
branch,
|
|
43
|
-
baseBranch,
|
|
44
|
-
insertions,
|
|
45
|
-
deletions,
|
|
46
|
-
fileCount,
|
|
47
|
-
refreshing,
|
|
48
|
-
lastUpdated,
|
|
49
|
-
comments,
|
|
50
|
-
diffMode,
|
|
51
|
-
onDiffModeChange,
|
|
52
|
-
layout,
|
|
53
|
-
onLayoutChange,
|
|
54
|
-
}: StatusBarProps) => {
|
|
55
|
-
const [copied, setCopied] = useState(false);
|
|
56
|
-
const [modeMenuOpen, setModeMenuOpen] = useState(false);
|
|
57
|
-
const modeMenuRef = useRef<HTMLDivElement>(null);
|
|
58
|
-
const { resolvedTheme, setTheme } = useTheme();
|
|
59
|
-
|
|
60
|
-
const copiedTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
61
|
-
|
|
62
|
-
// oxlint-disable-next-line react-perf/jsx-no-new-function-as-prop
|
|
63
|
-
const copyCommentsAsPrompt = async () => {
|
|
64
|
-
try {
|
|
65
|
-
const text = exportCommentsAsPrompt(comments);
|
|
66
|
-
await navigator.clipboard.writeText(text);
|
|
67
|
-
if (copiedTimerRef.current) {
|
|
68
|
-
clearTimeout(copiedTimerRef.current);
|
|
69
|
-
}
|
|
70
|
-
setCopied(true);
|
|
71
|
-
copiedTimerRef.current = setTimeout(() => setCopied(false), 2000);
|
|
72
|
-
} catch {
|
|
73
|
-
// clipboard unavailable — don't flip copied state
|
|
74
|
-
}
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
useEffect(() => {
|
|
78
|
-
if (!modeMenuOpen) {
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
const handleClick = (e: MouseEvent) => {
|
|
82
|
-
if (modeMenuRef.current && !modeMenuRef.current.contains(e.target as Node)) {
|
|
83
|
-
setModeMenuOpen(false);
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
document.addEventListener("mousedown", handleClick);
|
|
87
|
-
return () => document.removeEventListener("mousedown", handleClick);
|
|
88
|
-
}, [modeMenuOpen]);
|
|
89
|
-
|
|
90
|
-
return (
|
|
91
|
-
<header className="flex items-center gap-2 border-b border-border bg-card px-4 py-2.5 text-sm">
|
|
92
|
-
{/* Branch comparison badges */}
|
|
93
|
-
<div className="flex items-center gap-1.5">
|
|
94
|
-
<span className="rounded-md border border-border bg-background px-2.5 py-1 font-mono text-xs font-medium text-foreground">
|
|
95
|
-
{branch}
|
|
96
|
-
</span>
|
|
97
|
-
<ArrowRightIcon size={12} className="text-muted-foreground/50 shrink-0" />
|
|
98
|
-
<span className="rounded-md border border-border bg-background px-2.5 py-1 font-mono text-xs text-muted-foreground">
|
|
99
|
-
{baseBranch}
|
|
100
|
-
</span>
|
|
101
|
-
</div>
|
|
102
|
-
|
|
103
|
-
{/* Stats */}
|
|
104
|
-
<div className="flex items-center gap-2">
|
|
105
|
-
<span className="text-xs font-mono text-muted-foreground">
|
|
106
|
-
{fileCount} {fileCount === 1 ? "file" : "files"}
|
|
107
|
-
</span>
|
|
108
|
-
{insertions > 0 && <span className="text-xs font-mono text-diff-green">+{insertions}</span>}
|
|
109
|
-
{deletions > 0 && <span className="text-xs font-mono text-destructive">−{deletions}</span>}
|
|
110
|
-
</div>
|
|
111
|
-
|
|
112
|
-
<div className="flex-1" />
|
|
113
|
-
|
|
114
|
-
<div className="flex items-center gap-0.5">
|
|
115
|
-
{/* Live indicator */}
|
|
116
|
-
{lastUpdated && (
|
|
117
|
-
<span
|
|
118
|
-
className={cn(
|
|
119
|
-
"size-1.5 rounded-full bg-diff-green mx-1.5",
|
|
120
|
-
refreshing && "animate-pulse",
|
|
121
|
-
)}
|
|
122
|
-
/>
|
|
123
|
-
)}
|
|
124
|
-
|
|
125
|
-
{/* Diff mode dropdown */}
|
|
126
|
-
<div className="relative" ref={modeMenuRef}>
|
|
127
|
-
<Button
|
|
128
|
-
variant="ghost"
|
|
129
|
-
size="xs"
|
|
130
|
-
// oxlint-disable-next-line react-perf/jsx-no-new-function-as-prop
|
|
131
|
-
onClick={() => setModeMenuOpen((o) => !o)}
|
|
132
|
-
className="text-muted-foreground hover:text-foreground hover:bg-secondary gap-1"
|
|
133
|
-
>
|
|
134
|
-
{diffMode === "uncommitted" ? "Uncommitted" : "All changes"}
|
|
135
|
-
<ChevronDownIcon
|
|
136
|
-
size={10}
|
|
137
|
-
className={cn("transition-transform duration-150", modeMenuOpen && "rotate-180")}
|
|
138
|
-
/>
|
|
139
|
-
</Button>
|
|
140
|
-
|
|
141
|
-
{modeMenuOpen && (
|
|
142
|
-
<div className="absolute right-0 top-full mt-1 z-50 min-w-[200px] rounded-lg border border-border bg-card shadow-lg dark:shadow-none py-1 overflow-hidden">
|
|
143
|
-
{DIFF_MODES.map(({ value, label }) => (
|
|
144
|
-
<button
|
|
145
|
-
type="button"
|
|
146
|
-
key={value}
|
|
147
|
-
className="flex w-full items-center justify-between px-3 py-2 text-sm text-left hover:bg-secondary/50 transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring/50"
|
|
148
|
-
// oxlint-disable-next-line react-perf/jsx-no-new-function-as-prop
|
|
149
|
-
onClick={() => {
|
|
150
|
-
onDiffModeChange(value);
|
|
151
|
-
setModeMenuOpen(false);
|
|
152
|
-
}}
|
|
153
|
-
>
|
|
154
|
-
<span className={cn("text-foreground", diffMode === value && "font-medium")}>
|
|
155
|
-
{label}
|
|
156
|
-
</span>
|
|
157
|
-
{diffMode === value && (
|
|
158
|
-
<CheckIcon size={14} className="text-diff-green shrink-0" />
|
|
159
|
-
)}
|
|
160
|
-
</button>
|
|
161
|
-
))}
|
|
162
|
-
</div>
|
|
163
|
-
)}
|
|
164
|
-
</div>
|
|
165
|
-
|
|
166
|
-
{/* Comments export */}
|
|
167
|
-
{comments.length > 0 && (
|
|
168
|
-
<Button
|
|
169
|
-
variant="ghost"
|
|
170
|
-
size="xs"
|
|
171
|
-
onClick={copyCommentsAsPrompt}
|
|
172
|
-
className="text-muted-foreground hover:text-foreground hover:bg-secondary"
|
|
173
|
-
title="Copy all comments as AI prompt"
|
|
174
|
-
>
|
|
175
|
-
{copied ? (
|
|
176
|
-
<CheckIcon data-icon="inline-start" />
|
|
177
|
-
) : (
|
|
178
|
-
<CopySimpleIcon data-icon="inline-start" />
|
|
179
|
-
)}
|
|
180
|
-
{copied
|
|
181
|
-
? "Copied!"
|
|
182
|
-
: `Copy ${comments.length} comment${comments.length === 1 ? "" : "s"}`}
|
|
183
|
-
</Button>
|
|
184
|
-
)}
|
|
185
|
-
|
|
186
|
-
{/* Layout toggle */}
|
|
187
|
-
<Button
|
|
188
|
-
variant="ghost"
|
|
189
|
-
size="icon-xs"
|
|
190
|
-
// oxlint-disable-next-line react-perf/jsx-no-new-function-as-prop
|
|
191
|
-
onClick={() => onLayoutChange(layout === "split" ? "stacked" : "split")}
|
|
192
|
-
className="text-muted-foreground hover:text-foreground hover:bg-secondary"
|
|
193
|
-
title={layout === "split" ? "Switch to unified view (S)" : "Switch to split view (S)"}
|
|
194
|
-
>
|
|
195
|
-
<SplitIcon size={14} />
|
|
196
|
-
</Button>
|
|
197
|
-
|
|
198
|
-
{/* Theme toggle */}
|
|
199
|
-
<Button
|
|
200
|
-
variant="ghost"
|
|
201
|
-
size="icon-xs"
|
|
202
|
-
// oxlint-disable-next-line react-perf/jsx-no-new-function-as-prop
|
|
203
|
-
onClick={() => setTheme(resolvedTheme === "dark" ? "light" : "dark")}
|
|
204
|
-
className="text-muted-foreground hover:text-foreground hover:bg-secondary"
|
|
205
|
-
title={resolvedTheme === "dark" ? "Switch to light mode" : "Switch to dark mode"}
|
|
206
|
-
>
|
|
207
|
-
{resolvedTheme === "dark" ? <SunIcon size={14} /> : <MoonIcon size={14} />}
|
|
208
|
-
</Button>
|
|
209
|
-
</div>
|
|
210
|
-
</header>
|
|
211
|
-
);
|
|
212
|
-
};
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import type { SVGProps } from "react";
|
|
2
|
-
|
|
3
|
-
type IconProps = SVGProps<SVGSVGElement> & { size?: number };
|
|
4
|
-
|
|
5
|
-
/** Modified file */
|
|
6
|
-
export const FileDiffIcon = ({ size = 16, ...props }: IconProps) => (
|
|
7
|
-
<svg
|
|
8
|
-
viewBox="0 0 16 16"
|
|
9
|
-
width={size}
|
|
10
|
-
height={size}
|
|
11
|
-
fill="currentColor"
|
|
12
|
-
aria-hidden="true"
|
|
13
|
-
focusable="false"
|
|
14
|
-
{...props}
|
|
15
|
-
>
|
|
16
|
-
<path d="M1 1.75C1 .784 1.784 0 2.75 0h7.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16H2.75A1.75 1.75 0 0 1 1 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25V4.664a.25.25 0 0 0-.073-.177l-2.914-2.914a.25.25 0 0 0-.177-.073ZM8 3.25a.75.75 0 0 1 .75.75v1.5h1.5a.75.75 0 0 1 0 1.5h-1.5v1.5a.75.75 0 0 1-1.5 0V7h-1.5a.75.75 0 0 1 0-1.5h1.5V4A.75.75 0 0 1 8 3.25Zm-3 8a.75.75 0 0 1 .75-.75h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1-.75-.75Z" />
|
|
17
|
-
</svg>
|
|
18
|
-
);
|
|
19
|
-
|
|
20
|
-
/** Added file */
|
|
21
|
-
export const FileAddedIcon = ({ size = 16, ...props }: IconProps) => (
|
|
22
|
-
<svg
|
|
23
|
-
viewBox="0 0 16 16"
|
|
24
|
-
width={size}
|
|
25
|
-
height={size}
|
|
26
|
-
fill="currentColor"
|
|
27
|
-
aria-hidden="true"
|
|
28
|
-
focusable="false"
|
|
29
|
-
{...props}
|
|
30
|
-
>
|
|
31
|
-
<path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V4.664a.25.25 0 0 0-.073-.177l-2.914-2.914a.25.25 0 0 0-.177-.073Zm4.48 3.758a.75.75 0 0 1 .755.745l.01 1.497h1.497a.75.75 0 0 1 0 1.5H9v1.507a.75.75 0 0 1-1.5 0V9.005l-1.502.01a.75.75 0 0 1-.01-1.5l1.507-.01-.01-1.492a.75.75 0 0 1 .745-.755Z" />
|
|
32
|
-
</svg>
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
/** Removed file */
|
|
36
|
-
export const FileRemovedIcon = ({ size = 16, ...props }: IconProps) => (
|
|
37
|
-
<svg
|
|
38
|
-
viewBox="0 0 16 16"
|
|
39
|
-
width={size}
|
|
40
|
-
height={size}
|
|
41
|
-
fill="currentColor"
|
|
42
|
-
aria-hidden="true"
|
|
43
|
-
focusable="false"
|
|
44
|
-
{...props}
|
|
45
|
-
>
|
|
46
|
-
<path d="M2 1.75C2 .784 2.784 0 3.75 0h6.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v9.586A1.75 1.75 0 0 1 13.25 16h-9.5A1.75 1.75 0 0 1 2 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h9.5a.25.25 0 0 0 .25-.25V4.664a.25.25 0 0 0-.073-.177l-2.914-2.914a.25.25 0 0 0-.177-.073Zm4.5 6h2.242a.75.75 0 0 1 0 1.5h-2.24l-2.254.015a.75.75 0 0 1-.01-1.5Z" />
|
|
47
|
-
</svg>
|
|
48
|
-
);
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import * as React from "react";
|
|
4
|
-
import { ThemeProvider as NextThemesProvider } from "next-themes";
|
|
5
|
-
import type { ThemeProviderProps } from "next-themes";
|
|
6
|
-
|
|
7
|
-
export const ThemeProvider = ({
|
|
8
|
-
children,
|
|
9
|
-
...props
|
|
10
|
-
}: ThemeProviderProps & { children?: React.ReactNode }) => (
|
|
11
|
-
<NextThemesProvider {...props}>{children}</NextThemesProvider>
|
|
12
|
-
);
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { mergeProps } from "@base-ui/react/merge-props";
|
|
2
|
-
import { useRender } from "@base-ui/react/use-render";
|
|
3
|
-
import { cva } from "class-variance-authority";
|
|
4
|
-
import type { VariantProps } from "class-variance-authority";
|
|
5
|
-
import type * as React from "react";
|
|
6
|
-
|
|
7
|
-
import { cn } from "@/lib/utils";
|
|
8
|
-
|
|
9
|
-
const buttonVariants = cva(
|
|
10
|
-
"group/button inline-flex shrink-0 select-none items-center justify-center whitespace-nowrap rounded-lg border border-transparent bg-clip-padding font-sans font-medium text-sm outline-none transition-[color,background-color,border-color,box-shadow,opacity,transform] duration-150 ease-out focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-45 aria-disabled:pointer-events-none aria-disabled:cursor-not-allowed aria-disabled:opacity-45 aria-invalid:border-destructive aria-invalid:ring-2 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
11
|
-
{
|
|
12
|
-
defaultVariants: {
|
|
13
|
-
size: "default",
|
|
14
|
-
variant: "default",
|
|
15
|
-
},
|
|
16
|
-
variants: {
|
|
17
|
-
size: {
|
|
18
|
-
default:
|
|
19
|
-
"h-10 gap-1.5 px-3 has-data-[icon=inline-end]:pr-2.5 has-data-[icon=inline-start]:pl-2.5",
|
|
20
|
-
icon: "size-10",
|
|
21
|
-
"icon-lg": "size-11",
|
|
22
|
-
"icon-sm":
|
|
23
|
-
"size-9 in-data-[slot=button-group]:rounded-lg rounded-[min(var(--radius-md),12px)]",
|
|
24
|
-
"icon-xs":
|
|
25
|
-
"size-8 in-data-[slot=button-group]:rounded-lg rounded-[min(var(--radius-md),10px)] [&_svg:not([class*='size-'])]:size-3",
|
|
26
|
-
input:
|
|
27
|
-
"h-[var(--field-height)] gap-2 rounded-[var(--field-radius)] px-[var(--field-padding-x)] py-[var(--field-padding-y)]",
|
|
28
|
-
"input-sm":
|
|
29
|
-
"h-[var(--field-height-sm)] gap-2 rounded-[var(--field-radius)] px-[var(--field-padding-x)] py-[var(--field-padding-y)]",
|
|
30
|
-
lg: "h-11 gap-1.5 px-4 has-data-[icon=inline-end]:pr-3.5 has-data-[icon=inline-start]:pl-3.5",
|
|
31
|
-
sm: "h-9 gap-1 in-data-[slot=button-group]:rounded-lg rounded-[min(var(--radius-md),12px)] px-3 text-[0.8rem] has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2 [&_svg:not([class*='size-'])]:size-3.5",
|
|
32
|
-
xs: "h-8 gap-1 in-data-[slot=button-group]:rounded-lg rounded-[min(var(--radius-md),10px)] px-2.5 text-xs has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2 [&_svg:not([class*='size-'])]:size-3",
|
|
33
|
-
},
|
|
34
|
-
variant: {
|
|
35
|
-
default:
|
|
36
|
-
"bg-primary text-primary-foreground hover:bg-primary/90 active:bg-primary/95 aria-pressed:bg-primary/95",
|
|
37
|
-
destructive:
|
|
38
|
-
"bg-red-600 text-white hover:bg-red-700 focus-visible:border-red-600 focus-visible:ring-red-500/30 active:bg-red-800 aria-pressed:bg-red-800 dark:bg-red-500 dark:aria-pressed:bg-red-300 dark:active:bg-red-300 dark:hover:bg-red-400",
|
|
39
|
-
destructiveSecondary:
|
|
40
|
-
"border-red-200 text-red-700 hover:bg-red-50 active:bg-red-100 aria-pressed:bg-red-100 dark:border-red-800 dark:text-red-300 dark:aria-pressed:bg-red-950 dark:active:bg-red-950 dark:hover:bg-red-950/60",
|
|
41
|
-
ghost:
|
|
42
|
-
"hover:bg-muted hover:text-foreground active:bg-muted/80 aria-expanded:bg-muted aria-pressed:bg-muted/80 dark:aria-pressed:bg-muted/60 dark:active:bg-muted/60 dark:hover:bg-muted/50",
|
|
43
|
-
input:
|
|
44
|
-
"border-input bg-card font-normal font-sans text-base text-foreground leading-snug shadow-input hover:border-input-hover focus-visible:ring-2 focus-visible:ring-ring/15 focus-visible:ring-offset-1 focus-visible:ring-offset-background active:border-input-hover/80 aria-pressed:border-input-hover aria-invalid:border-destructive-foreground data-[placeholder]:text-placeholder-foreground",
|
|
45
|
-
link: "text-primary underline-offset-4 hover:underline active:opacity-80 aria-pressed:underline aria-pressed:opacity-80",
|
|
46
|
-
outline:
|
|
47
|
-
"border-border bg-background hover:bg-muted hover:text-foreground active:bg-muted/80 aria-expanded:bg-muted aria-pressed:bg-muted/80 dark:border-input dark:bg-input/30 dark:aria-pressed:bg-input/60 dark:active:bg-input/60 dark:hover:bg-input/50",
|
|
48
|
-
secondary:
|
|
49
|
-
"bg-secondary text-secondary-foreground hover:bg-secondary/85 active:bg-secondary/75 aria-expanded:bg-secondary aria-pressed:bg-secondary/75",
|
|
50
|
-
success:
|
|
51
|
-
"bg-green-600 text-white hover:bg-green-700 focus-visible:border-green-600 focus-visible:ring-green-500/30 active:bg-green-800 aria-pressed:bg-green-800 dark:bg-green-500 dark:aria-pressed:bg-green-300 dark:active:bg-green-300 dark:hover:bg-green-400",
|
|
52
|
-
successSecondary:
|
|
53
|
-
"border-green-200 text-green-700 hover:bg-green-50 active:bg-green-100 aria-pressed:bg-green-100 dark:border-green-800 dark:text-green-300 dark:aria-pressed:bg-green-950 dark:active:bg-green-950 dark:hover:bg-green-950/60",
|
|
54
|
-
warning:
|
|
55
|
-
"bg-yellow-600 text-white hover:bg-yellow-700 focus-visible:border-yellow-600 focus-visible:ring-yellow-500/30 active:bg-yellow-800 aria-pressed:bg-yellow-800 dark:bg-yellow-500 dark:text-yellow-950 dark:aria-pressed:bg-yellow-300 dark:active:bg-yellow-300 dark:hover:bg-yellow-400",
|
|
56
|
-
warningSecondary:
|
|
57
|
-
"border-yellow-200 text-yellow-700 hover:bg-yellow-50 active:bg-yellow-100 aria-pressed:bg-yellow-100 dark:border-yellow-800 dark:text-yellow-300 dark:aria-pressed:bg-yellow-950 dark:active:bg-yellow-950 dark:hover:bg-yellow-950/60",
|
|
58
|
-
},
|
|
59
|
-
},
|
|
60
|
-
},
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
const Button = ({
|
|
64
|
-
className,
|
|
65
|
-
variant = "default",
|
|
66
|
-
size = "default",
|
|
67
|
-
asChild = false,
|
|
68
|
-
children,
|
|
69
|
-
...props
|
|
70
|
-
}: React.ComponentProps<"button"> &
|
|
71
|
-
VariantProps<typeof buttonVariants> & {
|
|
72
|
-
asChild?: boolean;
|
|
73
|
-
}) =>
|
|
74
|
-
useRender({
|
|
75
|
-
defaultTagName: "button",
|
|
76
|
-
props: mergeProps<"button">(
|
|
77
|
-
{
|
|
78
|
-
className: cn(buttonVariants({ className, size, variant })),
|
|
79
|
-
},
|
|
80
|
-
asChild ? props : { ...props, children },
|
|
81
|
-
),
|
|
82
|
-
render: asChild ? (children as React.ReactElement) : undefined,
|
|
83
|
-
state: {
|
|
84
|
-
size,
|
|
85
|
-
slot: "button",
|
|
86
|
-
variant,
|
|
87
|
-
},
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
export { Button, buttonVariants };
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { cva } from "class-variance-authority";
|
|
2
|
-
import type { VariantProps } from "class-variance-authority";
|
|
3
|
-
import type * as React from "react";
|
|
4
|
-
|
|
5
|
-
import { cn } from "@/lib/utils";
|
|
6
|
-
|
|
7
|
-
const Empty = ({ className, ...props }: React.ComponentProps<"div">) => (
|
|
8
|
-
<div
|
|
9
|
-
className={cn(
|
|
10
|
-
"flex min-w-0 flex-1 flex-col items-center justify-center gap-6 text-balance rounded-lg border-dashed p-6 text-center md:p-12",
|
|
11
|
-
className,
|
|
12
|
-
)}
|
|
13
|
-
data-slot="empty"
|
|
14
|
-
{...props}
|
|
15
|
-
/>
|
|
16
|
-
);
|
|
17
|
-
|
|
18
|
-
const EmptyHeader = ({ className, ...props }: React.ComponentProps<"div">) => (
|
|
19
|
-
<div
|
|
20
|
-
className={cn("flex max-w-sm flex-col items-center gap-2 text-center", className)}
|
|
21
|
-
data-slot="empty-header"
|
|
22
|
-
{...props}
|
|
23
|
-
/>
|
|
24
|
-
);
|
|
25
|
-
|
|
26
|
-
const emptyMediaVariants = cva(
|
|
27
|
-
"mb-2 flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
28
|
-
{
|
|
29
|
-
defaultVariants: { variant: "default" },
|
|
30
|
-
variants: {
|
|
31
|
-
variant: {
|
|
32
|
-
default: "bg-transparent",
|
|
33
|
-
icon: "flex size-10 shrink-0 items-center justify-center rounded-lg bg-muted text-foreground [&_svg:not([class*='size-'])]:size-6",
|
|
34
|
-
},
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
const EmptyMedia = ({
|
|
40
|
-
className,
|
|
41
|
-
variant = "default",
|
|
42
|
-
...props
|
|
43
|
-
}: React.ComponentProps<"div"> & VariantProps<typeof emptyMediaVariants>) => (
|
|
44
|
-
<div
|
|
45
|
-
className={cn(emptyMediaVariants({ className, variant }))}
|
|
46
|
-
data-slot="empty-icon"
|
|
47
|
-
data-variant={variant}
|
|
48
|
-
{...props}
|
|
49
|
-
/>
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
const EmptyTitle = ({ className, ...props }: React.ComponentProps<"div">) => (
|
|
53
|
-
<div
|
|
54
|
-
className={cn("font-medium text-lg tracking-tight", className)}
|
|
55
|
-
data-slot="empty-title"
|
|
56
|
-
{...props}
|
|
57
|
-
/>
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
const EmptyDescription = ({ className, ...props }: React.ComponentProps<"p">) => (
|
|
61
|
-
<div
|
|
62
|
-
className={cn(
|
|
63
|
-
"text-muted-foreground text-sm/relaxed [&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4",
|
|
64
|
-
className,
|
|
65
|
-
)}
|
|
66
|
-
data-slot="empty-description"
|
|
67
|
-
{...props}
|
|
68
|
-
/>
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
const EmptyContent = ({ className, ...props }: React.ComponentProps<"div">) => (
|
|
72
|
-
<div
|
|
73
|
-
className={cn(
|
|
74
|
-
"flex w-full min-w-0 max-w-sm flex-col items-center gap-4 text-balance text-sm",
|
|
75
|
-
className,
|
|
76
|
-
)}
|
|
77
|
-
data-slot="empty-content"
|
|
78
|
-
{...props}
|
|
79
|
-
/>
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
export { Empty, EmptyHeader, EmptyTitle, EmptyDescription, EmptyContent, EmptyMedia };
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { Input as InputPrimitive } from "@base-ui/react/input";
|
|
3
|
-
|
|
4
|
-
import { cn } from "@/lib/utils";
|
|
5
|
-
|
|
6
|
-
const Input = ({ className, type, ...props }: React.ComponentProps<"input">) => (
|
|
7
|
-
<InputPrimitive
|
|
8
|
-
type={type}
|
|
9
|
-
data-slot="input"
|
|
10
|
-
className={cn(
|
|
11
|
-
"h-8 w-full min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
|
|
12
|
-
className,
|
|
13
|
-
)}
|
|
14
|
-
{...props}
|
|
15
|
-
/>
|
|
16
|
-
);
|
|
17
|
-
|
|
18
|
-
export { Input };
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type * as React from "react";
|
|
2
|
-
import { cn } from "@/lib/utils";
|
|
3
|
-
|
|
4
|
-
export const Kbd = ({ className, children, ...props }: React.ComponentProps<"kbd">) => (
|
|
5
|
-
<kbd
|
|
6
|
-
className={cn(
|
|
7
|
-
"inline-flex h-5 items-center rounded border border-border bg-muted px-1.5 font-mono text-[10px] text-muted-foreground",
|
|
8
|
-
className,
|
|
9
|
-
)}
|
|
10
|
-
{...props}
|
|
11
|
-
>
|
|
12
|
-
{children}
|
|
13
|
-
</kbd>
|
|
14
|
-
);
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { Separator as SeparatorPrimitive } from "@base-ui/react/separator";
|
|
4
|
-
|
|
5
|
-
import { cn } from "@/lib/utils";
|
|
6
|
-
|
|
7
|
-
const Separator = ({
|
|
8
|
-
className,
|
|
9
|
-
orientation = "horizontal",
|
|
10
|
-
...props
|
|
11
|
-
}: SeparatorPrimitive.Props) => (
|
|
12
|
-
<SeparatorPrimitive
|
|
13
|
-
data-slot="separator"
|
|
14
|
-
orientation={orientation}
|
|
15
|
-
className={cn(
|
|
16
|
-
"shrink-0 bg-border data-horizontal:h-px data-horizontal:w-full data-vertical:w-px data-vertical:self-stretch",
|
|
17
|
-
className,
|
|
18
|
-
)}
|
|
19
|
-
{...props}
|
|
20
|
-
/>
|
|
21
|
-
);
|
|
22
|
-
|
|
23
|
-
export { Separator };
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import * as React from "react";
|
|
4
|
-
import { Dialog as SheetPrimitive } from "@base-ui/react/dialog";
|
|
5
|
-
|
|
6
|
-
import { cn } from "@/lib/utils";
|
|
7
|
-
import { Button } from "@/components/ui/button";
|
|
8
|
-
import { XIcon } from "lucide-react";
|
|
9
|
-
|
|
10
|
-
const Sheet = ({ ...props }: SheetPrimitive.Root.Props) => (
|
|
11
|
-
<SheetPrimitive.Root data-slot="sheet" {...props} />
|
|
12
|
-
);
|
|
13
|
-
|
|
14
|
-
const SheetTrigger = ({ ...props }: SheetPrimitive.Trigger.Props) => (
|
|
15
|
-
<SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />
|
|
16
|
-
);
|
|
17
|
-
|
|
18
|
-
const SheetClose = ({ ...props }: SheetPrimitive.Close.Props) => (
|
|
19
|
-
<SheetPrimitive.Close data-slot="sheet-close" {...props} />
|
|
20
|
-
);
|
|
21
|
-
|
|
22
|
-
const SheetPortal = ({ ...props }: SheetPrimitive.Portal.Props) => (
|
|
23
|
-
<SheetPrimitive.Portal data-slot="sheet-portal" {...props} />
|
|
24
|
-
);
|
|
25
|
-
|
|
26
|
-
const SheetOverlay = ({ className, ...props }: SheetPrimitive.Backdrop.Props) => (
|
|
27
|
-
<SheetPrimitive.Backdrop
|
|
28
|
-
data-slot="sheet-overlay"
|
|
29
|
-
className={cn(
|
|
30
|
-
"fixed inset-0 z-50 bg-black/10 transition-opacity duration-150 data-ending-style:opacity-0 data-starting-style:opacity-0 supports-backdrop-filter:backdrop-blur-xs",
|
|
31
|
-
className,
|
|
32
|
-
)}
|
|
33
|
-
{...props}
|
|
34
|
-
/>
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
const SheetContent = ({
|
|
38
|
-
className,
|
|
39
|
-
children,
|
|
40
|
-
side = "right",
|
|
41
|
-
showCloseButton = true,
|
|
42
|
-
...props
|
|
43
|
-
}: SheetPrimitive.Popup.Props & {
|
|
44
|
-
side?: "top" | "right" | "bottom" | "left";
|
|
45
|
-
showCloseButton?: boolean;
|
|
46
|
-
}) => (
|
|
47
|
-
<SheetPortal>
|
|
48
|
-
<SheetOverlay />
|
|
49
|
-
<SheetPrimitive.Popup
|
|
50
|
-
data-slot="sheet-content"
|
|
51
|
-
data-side={side}
|
|
52
|
-
className={cn(
|
|
53
|
-
"fixed z-50 flex flex-col gap-4 bg-popover bg-clip-padding text-sm text-popover-foreground shadow-lg transition duration-200 ease-in-out data-ending-style:opacity-0 data-starting-style:opacity-0 data-[side=bottom]:inset-x-0 data-[side=bottom]:bottom-0 data-[side=bottom]:h-auto data-[side=bottom]:border-t data-[side=bottom]:data-ending-style:translate-y-[2.5rem] data-[side=bottom]:data-starting-style:translate-y-[2.5rem] data-[side=left]:inset-y-0 data-[side=left]:left-0 data-[side=left]:h-full data-[side=left]:w-3/4 data-[side=left]:border-r data-[side=left]:data-ending-style:translate-x-[-2.5rem] data-[side=left]:data-starting-style:translate-x-[-2.5rem] data-[side=right]:inset-y-0 data-[side=right]:right-0 data-[side=right]:h-full data-[side=right]:w-3/4 data-[side=right]:border-l data-[side=right]:data-ending-style:translate-x-[2.5rem] data-[side=right]:data-starting-style:translate-x-[2.5rem] data-[side=top]:inset-x-0 data-[side=top]:top-0 data-[side=top]:h-auto data-[side=top]:border-b data-[side=top]:data-ending-style:translate-y-[-2.5rem] data-[side=top]:data-starting-style:translate-y-[-2.5rem] data-[side=left]:sm:max-w-sm data-[side=right]:sm:max-w-sm",
|
|
54
|
-
className,
|
|
55
|
-
)}
|
|
56
|
-
{...props}
|
|
57
|
-
>
|
|
58
|
-
{children}
|
|
59
|
-
{showCloseButton && (
|
|
60
|
-
<SheetPrimitive.Close
|
|
61
|
-
data-slot="sheet-close"
|
|
62
|
-
render={<Button variant="ghost" className="absolute top-3 right-3" size="icon-sm" />}
|
|
63
|
-
>
|
|
64
|
-
<XIcon />
|
|
65
|
-
<span className="sr-only">Close</span>
|
|
66
|
-
</SheetPrimitive.Close>
|
|
67
|
-
)}
|
|
68
|
-
</SheetPrimitive.Popup>
|
|
69
|
-
</SheetPortal>
|
|
70
|
-
);
|
|
71
|
-
|
|
72
|
-
const SheetHeader = ({ className, ...props }: React.ComponentProps<"div">) => (
|
|
73
|
-
<div data-slot="sheet-header" className={cn("flex flex-col gap-0.5 p-4", className)} {...props} />
|
|
74
|
-
);
|
|
75
|
-
|
|
76
|
-
const SheetFooter = ({ className, ...props }: React.ComponentProps<"div">) => (
|
|
77
|
-
<div
|
|
78
|
-
data-slot="sheet-footer"
|
|
79
|
-
className={cn("mt-auto flex flex-col gap-2 p-4", className)}
|
|
80
|
-
{...props}
|
|
81
|
-
/>
|
|
82
|
-
);
|
|
83
|
-
|
|
84
|
-
const SheetTitle = ({ className, ...props }: SheetPrimitive.Title.Props) => (
|
|
85
|
-
<SheetPrimitive.Title
|
|
86
|
-
data-slot="sheet-title"
|
|
87
|
-
className={cn("font-heading text-base font-medium text-foreground", className)}
|
|
88
|
-
{...props}
|
|
89
|
-
/>
|
|
90
|
-
);
|
|
91
|
-
|
|
92
|
-
const SheetDescription = ({ className, ...props }: SheetPrimitive.Description.Props) => (
|
|
93
|
-
<SheetPrimitive.Description
|
|
94
|
-
data-slot="sheet-description"
|
|
95
|
-
className={cn("text-sm text-muted-foreground", className)}
|
|
96
|
-
{...props}
|
|
97
|
-
/>
|
|
98
|
-
);
|
|
99
|
-
|
|
100
|
-
export {
|
|
101
|
-
Sheet,
|
|
102
|
-
SheetTrigger,
|
|
103
|
-
SheetClose,
|
|
104
|
-
SheetContent,
|
|
105
|
-
SheetHeader,
|
|
106
|
-
SheetFooter,
|
|
107
|
-
SheetTitle,
|
|
108
|
-
SheetDescription,
|
|
109
|
-
};
|