larkup 0.1.14
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/.env +2 -0
- package/app/actions/vercel.ts +417 -0
- package/app/api/chat/route.ts +192 -0
- package/app/api/chat/status/route.ts +55 -0
- package/app/api/chat/suggestions/route.ts +115 -0
- package/app/api/config/route.ts +73 -0
- package/app/api/config/test/route.ts +67 -0
- package/app/api/config/test-embedding/route.ts +40 -0
- package/app/api/config/test-llm/route.ts +47 -0
- package/app/api/config/test-provider/route.ts +36 -0
- package/app/api/demo/route.ts +176 -0
- package/app/api/deploy/ssh/route.ts +340 -0
- package/app/api/documents/route.ts +90 -0
- package/app/api/firecrawl/local/route.ts +46 -0
- package/app/api/index/route.ts +113 -0
- package/app/api/jobs/[id]/route.ts +44 -0
- package/app/api/jobs/route.ts +116 -0
- package/app/api/parse-file/route.ts +39 -0
- package/app/api/search/google/route.ts +162 -0
- package/app/api/search/route.ts +29 -0
- package/app/api/server/download/route.ts +112 -0
- package/app/api/server/generate/route.ts +46 -0
- package/app/api/server/local/route.ts +42 -0
- package/app/api/servers/route.ts +137 -0
- package/app/api/vector-stores/install/route.ts +65 -0
- package/app/api/vector-stores/status/route.ts +26 -0
- package/app/chat/page.tsx +15 -0
- package/app/configure/page.tsx +53 -0
- package/app/data/page.tsx +15 -0
- package/app/demo/page.tsx +15 -0
- package/app/favicon.ico +0 -0
- package/app/globals.css +190 -0
- package/app/index-data/page.tsx +15 -0
- package/app/layout.tsx +51 -0
- package/app/page.tsx +34 -0
- package/app/server/page.tsx +22 -0
- package/app/simple/chat/page.tsx +17 -0
- package/app/simple/docs/page.tsx +21 -0
- package/app/simple/layout.tsx +9 -0
- package/app/simple/settings/page.tsx +627 -0
- package/app/template.tsx +16 -0
- package/app/themes.css +733 -0
- package/components/alerts/generic-alert.tsx +74 -0
- package/components/app-sidebar.tsx +187 -0
- package/components/app-topnav.tsx +195 -0
- package/components/chat/chat-settings-modal.tsx +209 -0
- package/components/chat/chat-workspace.tsx +348 -0
- package/components/chat/knowledge-base-result.tsx +97 -0
- package/components/chat/message-item.tsx +103 -0
- package/components/client-layout-wrapper.tsx +182 -0
- package/components/configure/configure-form.tsx +1683 -0
- package/components/configure/store-fields.tsx +152 -0
- package/components/data/corpus-panel.tsx +499 -0
- package/components/data/data-workspace.tsx +272 -0
- package/components/data/firecrawl-notice.tsx +236 -0
- package/components/data/jobs-panel.tsx +485 -0
- package/components/data/paste-panel.tsx +79 -0
- package/components/data/scrape-panel.tsx +964 -0
- package/components/data/upload-panel.tsx +714 -0
- package/components/demo/demo-workspace.tsx +419 -0
- package/components/global-settings.tsx +286 -0
- package/components/index/index-workspace.tsx +482 -0
- package/components/onboarding/simple-setup.tsx +702 -0
- package/components/onboarding/tech-setup.tsx +121 -0
- package/components/onboarding/welcome-screen.tsx +183 -0
- package/components/page-header.tsx +44 -0
- package/components/server/code-viewer.tsx +87 -0
- package/components/server/deploy-button.tsx +1390 -0
- package/components/server/server-workspace.tsx +392 -0
- package/components/simple/sdk-connect-dialog.tsx +201 -0
- package/components/simple/simple-index-button.tsx +83 -0
- package/components/simple/simple-sidebar.tsx +161 -0
- package/components/theme-customizer-provider.tsx +171 -0
- package/components/theme-switcher.tsx +445 -0
- package/components/ui/alert-dialog.tsx +187 -0
- package/components/ui/alert.tsx +76 -0
- package/components/ui/badge.tsx +52 -0
- package/components/ui/button.tsx +59 -0
- package/components/ui/card.tsx +103 -0
- package/components/ui/checkbox.tsx +28 -0
- package/components/ui/collapsible.tsx +21 -0
- package/components/ui/dialog.tsx +159 -0
- package/components/ui/dropdown-menu.tsx +281 -0
- package/components/ui/input.tsx +22 -0
- package/components/ui/label.tsx +20 -0
- package/components/ui/popover.tsx +90 -0
- package/components/ui/progress.tsx +83 -0
- package/components/ui/provider-icon.tsx +94 -0
- package/components/ui/scroll-area.tsx +55 -0
- package/components/ui/select.tsx +248 -0
- package/components/ui/separator.tsx +25 -0
- package/components/ui/sheet.tsx +138 -0
- package/components/ui/skeleton.tsx +13 -0
- package/components/ui/sonner.tsx +63 -0
- package/components/ui/switch.tsx +32 -0
- package/components/ui/table.tsx +116 -0
- package/components/ui/tabs.tsx +84 -0
- package/components/ui/textarea.tsx +18 -0
- package/components/ui/tooltip.tsx +66 -0
- package/components/workspace/delete-server-dialog.tsx +71 -0
- package/components/workspace/server-form-dialog.tsx +103 -0
- package/components/workspace/server-switcher.tsx +163 -0
- package/components/workspace/workspace-provider.tsx +177 -0
- package/components/workspace/workspace-top-bar.tsx +23 -0
- package/components.json +21 -0
- package/lib/error-formatter.ts +15 -0
- package/lib/utils.ts +6 -0
- package/next-env.d.ts +6 -0
- package/next.config.mjs +18 -0
- package/package.json +65 -0
- package/postcss.config.mjs +8 -0
- package/public/docker.png +0 -0
- package/public/favicon.ico +0 -0
- package/public/github.svg +3 -0
- package/public/hetzner.svg +1 -0
- package/public/icons/aws.svg +38 -0
- package/public/icons/azure.svg +1 -0
- package/public/icons/chroma.png +0 -0
- package/public/icons/cohere.svg +30 -0
- package/public/icons/digital-ocean.webp +0 -0
- package/public/icons/firecrawl2.png +0 -0
- package/public/icons/gcp.svg +1 -0
- package/public/icons/gemini.svg +1 -0
- package/public/icons/jina.svg +1 -0
- package/public/icons/lancedb2.png +0 -0
- package/public/icons/mistral.svg +469 -0
- package/public/icons/nomic.png +0 -0
- package/public/icons/openai.svg +1 -0
- package/public/icons/pgvector2.png +0 -0
- package/public/icons/pinecone.png +0 -0
- package/public/icons/qdrant.svg +35 -0
- package/public/icons/supabase.png +0 -0
- package/public/icons/vercel copy.svg +1 -0
- package/public/icons/vercel.svg +1 -0
- package/public/icons/voyage-light.png +0 -0
- package/public/icons/weaviate.webp +0 -0
- package/public/logo-light.png +0 -0
- package/public/logo.png +0 -0
- package/public/logo9.png +0 -0
- package/public/vercel.svg +1 -0
- package/tsconfig.json +33 -0
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState, useEffect, Suspense } from "react";
|
|
4
|
+
import { useSearchParams } from "next/navigation";
|
|
5
|
+
import { GlobalSettings } from "./global-settings";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
useThemeCustomizer,
|
|
9
|
+
ThemeVariant,
|
|
10
|
+
BackgroundVariant,
|
|
11
|
+
PanelBgVariant,
|
|
12
|
+
LayoutVariant,
|
|
13
|
+
RadiusVariant,
|
|
14
|
+
PageStyleVariant,
|
|
15
|
+
} from "./theme-customizer-provider";
|
|
16
|
+
import { useWorkspace } from "@/components/workspace/workspace-provider";
|
|
17
|
+
import {
|
|
18
|
+
SlidersHorizontal,
|
|
19
|
+
LayoutTemplate,
|
|
20
|
+
Palette,
|
|
21
|
+
Monitor,
|
|
22
|
+
SquareDashed,
|
|
23
|
+
PanelTop,
|
|
24
|
+
User,
|
|
25
|
+
Check,
|
|
26
|
+
Settings,
|
|
27
|
+
} from "lucide-react";
|
|
28
|
+
import { Button } from "@/components/ui/button";
|
|
29
|
+
import {
|
|
30
|
+
Popover,
|
|
31
|
+
PopoverContent,
|
|
32
|
+
PopoverTrigger,
|
|
33
|
+
} from "@/components/ui/popover";
|
|
34
|
+
import {
|
|
35
|
+
Tooltip,
|
|
36
|
+
TooltipContent,
|
|
37
|
+
TooltipProvider,
|
|
38
|
+
TooltipTrigger,
|
|
39
|
+
} from "@/components/ui/tooltip";
|
|
40
|
+
import { Input } from "./ui/input";
|
|
41
|
+
|
|
42
|
+
const THEMES: { id: ThemeVariant; name: string; color: string }[] = [
|
|
43
|
+
{ id: "default", name: "Caffee", color: "#f2efe4" },
|
|
44
|
+
{ id: "theme-gaia", name: "Emerald Green", color: "#2b935f" },
|
|
45
|
+
{ id: "theme-docker", name: "Ocean Blue", color: "#1d63ed" },
|
|
46
|
+
{ id: "theme-pinecone", name: "Deep Indigo", color: "#6e56cf" },
|
|
47
|
+
{ id: "theme-vercel", name: "Minimal Black", color: "#000000" },
|
|
48
|
+
{ id: "theme-elevenlabs", name: "Soft Cream", color: "#f8f7f5" },
|
|
49
|
+
{ id: "theme-espresso", name: "Espresso", color: "#6B3F2A" },
|
|
50
|
+
{ id: "theme-sienna", name: "Warm Sienna", color: "#A0522D" },
|
|
51
|
+
{ id: "theme-caramel", name: "Caramel", color: "#C47C3E" },
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
const BACKGROUNDS: { id: BackgroundVariant; name: string; color: string }[] = [
|
|
55
|
+
{ id: "bg-default", name: "White", color: "#FFFFFF" },
|
|
56
|
+
{ id: "bg-pure", name: "Pure White", color: "#FFFFFF" },
|
|
57
|
+
{ id: "bg-silver", name: "Silver", color: "#F8F8F8" },
|
|
58
|
+
{ id: "bg-soft", name: "Soft", color: "#FBFAF8" },
|
|
59
|
+
{ id: "bg-stone", name: "Stone", color: "#F5F5F2" },
|
|
60
|
+
{ id: "bg-sage", name: "Sage", color: "#EDEDE8" },
|
|
61
|
+
{ id: "bg-warm", name: "Warm Cream", color: "#F7F1EA" },
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
const PANEL_BACKGROUNDS: {
|
|
65
|
+
id: PanelBgVariant;
|
|
66
|
+
name: string;
|
|
67
|
+
color: string;
|
|
68
|
+
}[] = [
|
|
69
|
+
{ id: "panel-default", name: "Theme Default", color: "#FAFAFA" },
|
|
70
|
+
{ id: "panel-white", name: "White", color: "#FFFFFF" },
|
|
71
|
+
{ id: "panel-fafafa", name: "Near White", color: "#F4F4F4" },
|
|
72
|
+
{ id: "panel-silver", name: "Silver", color: "#F8F8F8" },
|
|
73
|
+
{ id: "panel-soft", name: "Soft", color: "#FBFAF8" },
|
|
74
|
+
{ id: "panel-stone", name: "Stone", color: "#F5F5F2" },
|
|
75
|
+
{ id: "panel-warm", name: "Warm Cream", color: "#F7F1EA" },
|
|
76
|
+
];
|
|
77
|
+
|
|
78
|
+
const LAYOUTS: { id: LayoutVariant; name: string }[] = [
|
|
79
|
+
{ id: "sidebar", name: "Sidebar (Left)" },
|
|
80
|
+
{ id: "topnav", name: "Top Navigation" },
|
|
81
|
+
];
|
|
82
|
+
|
|
83
|
+
const RADIUSES: { id: RadiusVariant; name: string; value: string }[] = [
|
|
84
|
+
{ id: "radius-0", name: "Sharp (0)", value: "0" },
|
|
85
|
+
{ id: "radius-sm", name: "Small", value: "0.3rem" },
|
|
86
|
+
{ id: "radius-default", name: "Default", value: "0.625rem" },
|
|
87
|
+
{ id: "radius-lg", name: "Large", value: "1rem" },
|
|
88
|
+
];
|
|
89
|
+
|
|
90
|
+
const PAGE_STYLES: { id: PageStyleVariant; name: string }[] = [
|
|
91
|
+
{ id: "card", name: "Card (Rounded/Shadow)" },
|
|
92
|
+
{ id: "fused", name: "Fused (Flat)" },
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
export function ThemeSwitcher({ floating = true }: { floating?: boolean }) {
|
|
96
|
+
return (
|
|
97
|
+
<Suspense fallback={<div className={floating ? "fixed bottom-6 right-6 z-50 h-12 w-12" : "size-9"} />}>
|
|
98
|
+
<ThemeSwitcherContent floating={floating} />
|
|
99
|
+
</Suspense>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function ThemeSwitcherContent({ floating = true }: { floating?: boolean }) {
|
|
104
|
+
const {
|
|
105
|
+
theme,
|
|
106
|
+
setTheme,
|
|
107
|
+
background,
|
|
108
|
+
setBackground,
|
|
109
|
+
panelBg,
|
|
110
|
+
setPanelBg,
|
|
111
|
+
navBg,
|
|
112
|
+
setNavBg,
|
|
113
|
+
layout,
|
|
114
|
+
setLayout,
|
|
115
|
+
radius,
|
|
116
|
+
setRadius,
|
|
117
|
+
pageStyle,
|
|
118
|
+
setPageStyle,
|
|
119
|
+
isMounted,
|
|
120
|
+
} = useThemeCustomizer();
|
|
121
|
+
|
|
122
|
+
const { username, setUsername } = useWorkspace();
|
|
123
|
+
|
|
124
|
+
const [localName, setLocalName] = useState(username || "");
|
|
125
|
+
|
|
126
|
+
// Sync local input when context username changes (e.g. on mount)
|
|
127
|
+
const syncedRef = useState({ synced: false })[0];
|
|
128
|
+
if (isMounted && !syncedRef.synced && username && localName !== username) {
|
|
129
|
+
setLocalName(username);
|
|
130
|
+
syncedRef.synced = true;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const searchParams = useSearchParams();
|
|
134
|
+
const [view, setView] = useState<"main" | "settings">("main");
|
|
135
|
+
const [open, setOpen] = useState(false);
|
|
136
|
+
|
|
137
|
+
useEffect(() => {
|
|
138
|
+
if (searchParams?.get("settings")) {
|
|
139
|
+
setOpen(true);
|
|
140
|
+
setView("settings");
|
|
141
|
+
}
|
|
142
|
+
}, [searchParams]);
|
|
143
|
+
|
|
144
|
+
const handleSaveUsername = () => {
|
|
145
|
+
setUsername(localName.trim());
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
if (!isMounted) return null;
|
|
149
|
+
|
|
150
|
+
const wrapperClass = floating
|
|
151
|
+
? "fixed bottom-6 right-6 z-50"
|
|
152
|
+
: "flex items-center";
|
|
153
|
+
const buttonClass = floating
|
|
154
|
+
? "h-12 w-12 rounded-full shadow-xl"
|
|
155
|
+
: "size-9 rounded-lg border border-border bg-card text-primary shadow-sm hover:bg-accent hover:text-accent-foreground";
|
|
156
|
+
|
|
157
|
+
return (
|
|
158
|
+
<div className={wrapperClass}>
|
|
159
|
+
<Popover open={open} onOpenChange={setOpen}>
|
|
160
|
+
<PopoverTrigger
|
|
161
|
+
render={
|
|
162
|
+
<Button
|
|
163
|
+
variant={floating ? "default" : "ghost"}
|
|
164
|
+
size="icon"
|
|
165
|
+
className={buttonClass}
|
|
166
|
+
>
|
|
167
|
+
<SlidersHorizontal className={floating ? "h-5 w-5" : "h-4 w-4"} />
|
|
168
|
+
</Button>
|
|
169
|
+
}
|
|
170
|
+
/>
|
|
171
|
+
<PopoverContent
|
|
172
|
+
align="end"
|
|
173
|
+
className="w-80 p-0 shadow-2xl flex flex-col max-h-[85vh] overflow-hidden"
|
|
174
|
+
>
|
|
175
|
+
{view === "settings" ? (
|
|
176
|
+
<div className="flex flex-col min-h-0 flex-1 h-full animate-in slide-in-from-right-4 duration-300">
|
|
177
|
+
<GlobalSettings onBack={() => setView("main")} />
|
|
178
|
+
</div>
|
|
179
|
+
) : (
|
|
180
|
+
<div className="flex flex-col min-h-0 flex-1 h-full animate-in slide-in-from-left-4 duration-300">
|
|
181
|
+
<div className="border-b px-4 py-3 font-semibold flex items-center justify-between shrink-0">
|
|
182
|
+
<div className="flex items-center gap-2">
|
|
183
|
+
<Palette className="h-4 w-4" /> Preferences
|
|
184
|
+
</div>
|
|
185
|
+
<Button variant="ghost" size="icon" className="h-6 w-6" onClick={() => setView("settings")}>
|
|
186
|
+
<Settings className="h-4 w-4 text-muted-foreground" />
|
|
187
|
+
</Button>
|
|
188
|
+
</div>
|
|
189
|
+
<div className="flex-1 min-h-0 p-4 space-y-6 overflow-y-auto">
|
|
190
|
+
{/* Username */}
|
|
191
|
+
<div className="space-y-3">
|
|
192
|
+
<label className="text-sm font-medium flex items-center gap-2">
|
|
193
|
+
<User className="h-4 w-4 text-muted-foreground" /> Username
|
|
194
|
+
</label>
|
|
195
|
+
<div className="flex gap-2">
|
|
196
|
+
<Input
|
|
197
|
+
value={localName}
|
|
198
|
+
onChange={(e) => setLocalName(e.target.value)}
|
|
199
|
+
onKeyDown={(e) => e.key === "Enter" && handleSaveUsername()}
|
|
200
|
+
placeholder="Enter your name"
|
|
201
|
+
className="flex-1 rounded-md border border-input bg-background px-3 h-7 text-sm outline-none "
|
|
202
|
+
/>
|
|
203
|
+
<Button
|
|
204
|
+
size="sm"
|
|
205
|
+
variant="default"
|
|
206
|
+
className="shrink-0 h-7 px-3.5"
|
|
207
|
+
onClick={handleSaveUsername}
|
|
208
|
+
>
|
|
209
|
+
save
|
|
210
|
+
{/* <Check className="h-3.5 w-3.5 " /> */}
|
|
211
|
+
</Button>
|
|
212
|
+
</div>
|
|
213
|
+
</div>
|
|
214
|
+
|
|
215
|
+
{/* Color Theme */}
|
|
216
|
+
<div className="space-y-3">
|
|
217
|
+
<label className="text-sm font-medium flex items-center gap-2">
|
|
218
|
+
<Palette className="h-4 w-4 text-muted-foreground" /> Color
|
|
219
|
+
Palette
|
|
220
|
+
</label>
|
|
221
|
+
<div className="grid grid-cols-3 gap-2">
|
|
222
|
+
{THEMES.map((t) => (
|
|
223
|
+
<button
|
|
224
|
+
key={t.id}
|
|
225
|
+
onClick={() => setTheme(t.id)}
|
|
226
|
+
className={`flex flex-col items-center justify-center gap-2 rounded-md border-2 p-2 text-xs transition-all hover:bg-muted ${
|
|
227
|
+
theme === t.id
|
|
228
|
+
? "border-primary bg-primary/5"
|
|
229
|
+
: "border-transparent"
|
|
230
|
+
}`}
|
|
231
|
+
>
|
|
232
|
+
<div
|
|
233
|
+
className="h-6 w-6 rounded-full border shadow-sm"
|
|
234
|
+
style={{ background: t.color }}
|
|
235
|
+
/>
|
|
236
|
+
<span className="truncate w-full text-center">
|
|
237
|
+
{t.name}
|
|
238
|
+
</span>
|
|
239
|
+
</button>
|
|
240
|
+
))}
|
|
241
|
+
</div>
|
|
242
|
+
</div>
|
|
243
|
+
|
|
244
|
+
{/* Page Background */}
|
|
245
|
+
<TooltipProvider delay={200}>
|
|
246
|
+
<div className="space-y-3">
|
|
247
|
+
<label className="text-sm font-medium flex items-center gap-2">
|
|
248
|
+
<SquareDashed className="h-4 w-4 text-muted-foreground" />{" "}
|
|
249
|
+
Page Background
|
|
250
|
+
</label>
|
|
251
|
+
<p className="text-[11px] text-muted-foreground -mt-1">
|
|
252
|
+
Full page background behind everything
|
|
253
|
+
</p>
|
|
254
|
+
<div className="flex flex-wrap gap-2">
|
|
255
|
+
{BACKGROUNDS.map((bg) => (
|
|
256
|
+
<Tooltip key={bg.id}>
|
|
257
|
+
<TooltipTrigger
|
|
258
|
+
render={
|
|
259
|
+
<button
|
|
260
|
+
onClick={() => setBackground(bg.id)}
|
|
261
|
+
className={`flex items-center justify-center rounded-full border-2 p-0.5 transition-all hover:scale-110 ${
|
|
262
|
+
background === bg.id
|
|
263
|
+
? "border-primary"
|
|
264
|
+
: "border-transparent"
|
|
265
|
+
}`}
|
|
266
|
+
/>
|
|
267
|
+
}
|
|
268
|
+
>
|
|
269
|
+
<div
|
|
270
|
+
className={`h-6 w-6 rounded-full border shrink-0 ${bg.id === "bg-default" ? "border-dashed" : "shadow-sm"}`}
|
|
271
|
+
style={{ background: bg.color }}
|
|
272
|
+
/>
|
|
273
|
+
</TooltipTrigger>
|
|
274
|
+
<TooltipContent side="top" sideOffset={6}>
|
|
275
|
+
<span className="text-xs font-medium">{bg.name}</span>
|
|
276
|
+
<span className="text-[10px] text-muted-foreground ml-1.5">
|
|
277
|
+
{bg.color}
|
|
278
|
+
</span>
|
|
279
|
+
</TooltipContent>
|
|
280
|
+
</Tooltip>
|
|
281
|
+
))}
|
|
282
|
+
</div>
|
|
283
|
+
</div>
|
|
284
|
+
</TooltipProvider>
|
|
285
|
+
|
|
286
|
+
{/* Panel / Content Background */}
|
|
287
|
+
<TooltipProvider delay={200}>
|
|
288
|
+
<div className="space-y-3">
|
|
289
|
+
<label className="text-sm font-medium flex items-center gap-2">
|
|
290
|
+
<PanelTop className="h-4 w-4 text-muted-foreground" /> Content
|
|
291
|
+
Panel Background
|
|
292
|
+
</label>
|
|
293
|
+
<p className="text-[11px] text-muted-foreground -mt-1">
|
|
294
|
+
Inner content area (card / main panel)
|
|
295
|
+
</p>
|
|
296
|
+
<div className="flex flex-wrap gap-2">
|
|
297
|
+
{PANEL_BACKGROUNDS.map((pb) => (
|
|
298
|
+
<Tooltip key={pb.id}>
|
|
299
|
+
<TooltipTrigger
|
|
300
|
+
render={
|
|
301
|
+
<button
|
|
302
|
+
onClick={() => setPanelBg(pb.id)}
|
|
303
|
+
className={`flex items-center justify-center rounded-full border-2 p-0.5 transition-all hover:scale-110 ${
|
|
304
|
+
panelBg === pb.id
|
|
305
|
+
? "border-primary"
|
|
306
|
+
: "border-transparent"
|
|
307
|
+
}`}
|
|
308
|
+
/>
|
|
309
|
+
}
|
|
310
|
+
>
|
|
311
|
+
<div
|
|
312
|
+
className={`h-6 w-6 rounded-full border shrink-0 ${pb.id === "panel-default" ? "border-dashed" : "shadow-sm"}`}
|
|
313
|
+
style={{ background: pb.color }}
|
|
314
|
+
/>
|
|
315
|
+
</TooltipTrigger>
|
|
316
|
+
<TooltipContent side="top" sideOffset={6}>
|
|
317
|
+
<span className="text-xs font-medium">{pb.name}</span>
|
|
318
|
+
<span className="text-[10px] text-muted-foreground ml-1.5">
|
|
319
|
+
{pb.color}
|
|
320
|
+
</span>
|
|
321
|
+
</TooltipContent>
|
|
322
|
+
</Tooltip>
|
|
323
|
+
))}
|
|
324
|
+
</div>
|
|
325
|
+
</div>
|
|
326
|
+
</TooltipProvider>
|
|
327
|
+
|
|
328
|
+
{/* Nav/Sidebar Background */}
|
|
329
|
+
<TooltipProvider delay={200}>
|
|
330
|
+
<div className="space-y-3">
|
|
331
|
+
<label className="text-sm font-medium flex items-center gap-2">
|
|
332
|
+
<LayoutTemplate className="h-4 w-4 text-muted-foreground" /> Sidebar / Topnav Background
|
|
333
|
+
</label>
|
|
334
|
+
<p className="text-[11px] text-muted-foreground -mt-1">
|
|
335
|
+
Background color for the side or top navigation
|
|
336
|
+
</p>
|
|
337
|
+
<div className="flex flex-wrap gap-2">
|
|
338
|
+
{PANEL_BACKGROUNDS.map((pb) => (
|
|
339
|
+
<Tooltip key={`nav-${pb.id}`}>
|
|
340
|
+
<TooltipTrigger
|
|
341
|
+
render={
|
|
342
|
+
<button
|
|
343
|
+
onClick={() => setNavBg(pb.id)}
|
|
344
|
+
className={`flex items-center justify-center rounded-full border-2 p-0.5 transition-all hover:scale-110 ${
|
|
345
|
+
navBg === pb.id
|
|
346
|
+
? "border-primary"
|
|
347
|
+
: "border-transparent"
|
|
348
|
+
}`}
|
|
349
|
+
/>
|
|
350
|
+
}
|
|
351
|
+
>
|
|
352
|
+
<div
|
|
353
|
+
className={`h-6 w-6 rounded-full border shrink-0 ${pb.id === "panel-default" ? "border-dashed" : "shadow-sm"}`}
|
|
354
|
+
style={{ background: pb.color }}
|
|
355
|
+
/>
|
|
356
|
+
</TooltipTrigger>
|
|
357
|
+
<TooltipContent side="top" sideOffset={6}>
|
|
358
|
+
<span className="text-xs font-medium">{pb.name}</span>
|
|
359
|
+
<span className="text-[10px] text-muted-foreground ml-1.5">
|
|
360
|
+
{pb.color}
|
|
361
|
+
</span>
|
|
362
|
+
</TooltipContent>
|
|
363
|
+
</Tooltip>
|
|
364
|
+
))}
|
|
365
|
+
</div>
|
|
366
|
+
</div>
|
|
367
|
+
</TooltipProvider>
|
|
368
|
+
|
|
369
|
+
{/* Layout */}
|
|
370
|
+
<div className="space-y-3">
|
|
371
|
+
<label className="text-sm font-medium flex items-center gap-2">
|
|
372
|
+
<LayoutTemplate className="h-4 w-4 text-muted-foreground" />{" "}
|
|
373
|
+
Layout Style
|
|
374
|
+
</label>
|
|
375
|
+
<div className="grid grid-cols-2 gap-2">
|
|
376
|
+
{LAYOUTS.map((l) => (
|
|
377
|
+
<button
|
|
378
|
+
key={l.id}
|
|
379
|
+
onClick={() => setLayout(l.id)}
|
|
380
|
+
className={`rounded-md border-2 p-2 text-sm transition-all hover:bg-muted ${
|
|
381
|
+
layout === l.id
|
|
382
|
+
? "border-primary bg-primary/5"
|
|
383
|
+
: "border-border"
|
|
384
|
+
}`}
|
|
385
|
+
>
|
|
386
|
+
{l.name}
|
|
387
|
+
</button>
|
|
388
|
+
))}
|
|
389
|
+
</div>
|
|
390
|
+
</div>
|
|
391
|
+
|
|
392
|
+
{/* Page Style */}
|
|
393
|
+
<div className="space-y-3">
|
|
394
|
+
<label className="text-sm font-medium flex items-center gap-2">
|
|
395
|
+
<SquareDashed className="h-4 w-4 text-muted-foreground" /> Page
|
|
396
|
+
Style
|
|
397
|
+
</label>
|
|
398
|
+
<div className="grid grid-cols-2 gap-2">
|
|
399
|
+
{PAGE_STYLES.map((ps) => (
|
|
400
|
+
<button
|
|
401
|
+
key={ps.id}
|
|
402
|
+
onClick={() => setPageStyle(ps.id)}
|
|
403
|
+
className={`rounded-md border-2 p-2 text-xs transition-all hover:bg-muted ${
|
|
404
|
+
pageStyle === ps.id
|
|
405
|
+
? "border-primary bg-primary/5"
|
|
406
|
+
: "border-border"
|
|
407
|
+
}`}
|
|
408
|
+
>
|
|
409
|
+
{ps.name}
|
|
410
|
+
</button>
|
|
411
|
+
))}
|
|
412
|
+
</div>
|
|
413
|
+
</div>
|
|
414
|
+
|
|
415
|
+
{/* Border Radius */}
|
|
416
|
+
<div className="space-y-3">
|
|
417
|
+
<label className="text-sm font-medium flex items-center gap-2">
|
|
418
|
+
<Monitor className="h-4 w-4 text-muted-foreground" /> Border
|
|
419
|
+
Radius
|
|
420
|
+
</label>
|
|
421
|
+
<div className="flex flex-wrap gap-2">
|
|
422
|
+
{RADIUSES.map((r) => (
|
|
423
|
+
<button
|
|
424
|
+
key={r.id}
|
|
425
|
+
onClick={() => setRadius(r.id)}
|
|
426
|
+
className={`rounded-md border-2 px-3 py-1 text-xs transition-all hover:bg-muted ${
|
|
427
|
+
radius === r.id
|
|
428
|
+
? "border-primary bg-primary/5"
|
|
429
|
+
: "border-border"
|
|
430
|
+
}`}
|
|
431
|
+
style={{ borderRadius: r.value }}
|
|
432
|
+
>
|
|
433
|
+
{r.name}
|
|
434
|
+
</button>
|
|
435
|
+
))}
|
|
436
|
+
</div>
|
|
437
|
+
</div>
|
|
438
|
+
</div>
|
|
439
|
+
</div>
|
|
440
|
+
)}
|
|
441
|
+
</PopoverContent>
|
|
442
|
+
</Popover>
|
|
443
|
+
</div>
|
|
444
|
+
);
|
|
445
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { AlertDialog as AlertDialogPrimitive } from "@base-ui/react/alert-dialog"
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils"
|
|
7
|
+
import { Button } from "@/components/ui/button"
|
|
8
|
+
|
|
9
|
+
function AlertDialog({ ...props }: AlertDialogPrimitive.Root.Props) {
|
|
10
|
+
return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function AlertDialogTrigger({ ...props }: AlertDialogPrimitive.Trigger.Props) {
|
|
14
|
+
return (
|
|
15
|
+
<AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function AlertDialogPortal({ ...props }: AlertDialogPrimitive.Portal.Props) {
|
|
20
|
+
return (
|
|
21
|
+
<AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function AlertDialogOverlay({
|
|
26
|
+
className,
|
|
27
|
+
...props
|
|
28
|
+
}: AlertDialogPrimitive.Backdrop.Props) {
|
|
29
|
+
return (
|
|
30
|
+
<AlertDialogPrimitive.Backdrop
|
|
31
|
+
data-slot="alert-dialog-overlay"
|
|
32
|
+
className={cn(
|
|
33
|
+
"fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0",
|
|
34
|
+
className
|
|
35
|
+
)}
|
|
36
|
+
{...props}
|
|
37
|
+
/>
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function AlertDialogContent({
|
|
42
|
+
className,
|
|
43
|
+
size = "default",
|
|
44
|
+
...props
|
|
45
|
+
}: AlertDialogPrimitive.Popup.Props & {
|
|
46
|
+
size?: "default" | "sm"
|
|
47
|
+
}) {
|
|
48
|
+
return (
|
|
49
|
+
<AlertDialogPortal>
|
|
50
|
+
<AlertDialogOverlay />
|
|
51
|
+
<AlertDialogPrimitive.Popup
|
|
52
|
+
data-slot="alert-dialog-content"
|
|
53
|
+
data-size={size}
|
|
54
|
+
className={cn(
|
|
55
|
+
"group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-popover p-4 text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
|
|
56
|
+
className
|
|
57
|
+
)}
|
|
58
|
+
{...props}
|
|
59
|
+
/>
|
|
60
|
+
</AlertDialogPortal>
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function AlertDialogHeader({
|
|
65
|
+
className,
|
|
66
|
+
...props
|
|
67
|
+
}: React.ComponentProps<"div">) {
|
|
68
|
+
return (
|
|
69
|
+
<div
|
|
70
|
+
data-slot="alert-dialog-header"
|
|
71
|
+
className={cn(
|
|
72
|
+
"grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-4 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]",
|
|
73
|
+
className
|
|
74
|
+
)}
|
|
75
|
+
{...props}
|
|
76
|
+
/>
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function AlertDialogFooter({
|
|
81
|
+
className,
|
|
82
|
+
...props
|
|
83
|
+
}: React.ComponentProps<"div">) {
|
|
84
|
+
return (
|
|
85
|
+
<div
|
|
86
|
+
data-slot="alert-dialog-footer"
|
|
87
|
+
className={cn(
|
|
88
|
+
"-mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-xl border-t bg-muted/50 p-4 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end",
|
|
89
|
+
className
|
|
90
|
+
)}
|
|
91
|
+
{...props}
|
|
92
|
+
/>
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function AlertDialogMedia({
|
|
97
|
+
className,
|
|
98
|
+
...props
|
|
99
|
+
}: React.ComponentProps<"div">) {
|
|
100
|
+
return (
|
|
101
|
+
<div
|
|
102
|
+
data-slot="alert-dialog-media"
|
|
103
|
+
className={cn(
|
|
104
|
+
"mb-2 inline-flex size-10 items-center justify-center rounded-md bg-muted sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-6",
|
|
105
|
+
className
|
|
106
|
+
)}
|
|
107
|
+
{...props}
|
|
108
|
+
/>
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function AlertDialogTitle({
|
|
113
|
+
className,
|
|
114
|
+
...props
|
|
115
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {
|
|
116
|
+
return (
|
|
117
|
+
<AlertDialogPrimitive.Title
|
|
118
|
+
data-slot="alert-dialog-title"
|
|
119
|
+
className={cn(
|
|
120
|
+
"font-heading text-base font-medium sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2",
|
|
121
|
+
className
|
|
122
|
+
)}
|
|
123
|
+
{...props}
|
|
124
|
+
/>
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function AlertDialogDescription({
|
|
129
|
+
className,
|
|
130
|
+
...props
|
|
131
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {
|
|
132
|
+
return (
|
|
133
|
+
<AlertDialogPrimitive.Description
|
|
134
|
+
data-slot="alert-dialog-description"
|
|
135
|
+
className={cn(
|
|
136
|
+
"text-sm text-balance text-muted-foreground md:text-pretty *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",
|
|
137
|
+
className
|
|
138
|
+
)}
|
|
139
|
+
{...props}
|
|
140
|
+
/>
|
|
141
|
+
)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function AlertDialogAction({
|
|
145
|
+
className,
|
|
146
|
+
...props
|
|
147
|
+
}: React.ComponentProps<typeof Button>) {
|
|
148
|
+
return (
|
|
149
|
+
<Button
|
|
150
|
+
data-slot="alert-dialog-action"
|
|
151
|
+
className={cn(className)}
|
|
152
|
+
{...props}
|
|
153
|
+
/>
|
|
154
|
+
)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function AlertDialogCancel({
|
|
158
|
+
className,
|
|
159
|
+
variant = "outline",
|
|
160
|
+
size = "default",
|
|
161
|
+
...props
|
|
162
|
+
}: AlertDialogPrimitive.Close.Props &
|
|
163
|
+
Pick<React.ComponentProps<typeof Button>, "variant" | "size">) {
|
|
164
|
+
return (
|
|
165
|
+
<AlertDialogPrimitive.Close
|
|
166
|
+
data-slot="alert-dialog-cancel"
|
|
167
|
+
className={cn(className)}
|
|
168
|
+
render={<Button variant={variant} size={size} />}
|
|
169
|
+
{...props}
|
|
170
|
+
/>
|
|
171
|
+
)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export {
|
|
175
|
+
AlertDialog,
|
|
176
|
+
AlertDialogAction,
|
|
177
|
+
AlertDialogCancel,
|
|
178
|
+
AlertDialogContent,
|
|
179
|
+
AlertDialogDescription,
|
|
180
|
+
AlertDialogFooter,
|
|
181
|
+
AlertDialogHeader,
|
|
182
|
+
AlertDialogMedia,
|
|
183
|
+
AlertDialogOverlay,
|
|
184
|
+
AlertDialogPortal,
|
|
185
|
+
AlertDialogTitle,
|
|
186
|
+
AlertDialogTrigger,
|
|
187
|
+
}
|