@khal-os/ui 1.0.0 → 1.0.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/LICENSE +94 -0
- package/README.md +25 -0
- package/dist/index.cjs +2661 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +926 -0
- package/dist/index.d.ts +926 -0
- package/dist/index.js +2510 -0
- package/dist/index.js.map +1 -0
- package/package.json +59 -40
- package/tokens.css +260 -238
- package/src/components/ContextMenu.tsx +0 -130
- package/src/components/avatar.tsx +0 -71
- package/src/components/badge.tsx +0 -39
- package/src/components/button.tsx +0 -102
- package/src/components/command.tsx +0 -165
- package/src/components/cost-counter.tsx +0 -75
- package/src/components/data-row.tsx +0 -97
- package/src/components/dropdown-menu.tsx +0 -233
- package/src/components/glass-card.tsx +0 -74
- package/src/components/input.tsx +0 -48
- package/src/components/khal-logo.tsx +0 -73
- package/src/components/live-feed.tsx +0 -109
- package/src/components/mesh-gradient.tsx +0 -57
- package/src/components/metric-display.tsx +0 -93
- package/src/components/note.tsx +0 -55
- package/src/components/number-flow.tsx +0 -25
- package/src/components/pill-badge.tsx +0 -65
- package/src/components/progress-bar.tsx +0 -70
- package/src/components/section-card.tsx +0 -76
- package/src/components/separator.tsx +0 -25
- package/src/components/spinner.tsx +0 -42
- package/src/components/status-dot.tsx +0 -90
- package/src/components/switch.tsx +0 -36
- package/src/components/theme-provider.tsx +0 -58
- package/src/components/theme-switcher.tsx +0 -59
- package/src/components/ticker-bar.tsx +0 -41
- package/src/components/tooltip.tsx +0 -62
- package/src/components/window-minimized-context.tsx +0 -29
- package/src/hooks/useReducedMotion.ts +0 -21
- package/src/index.ts +0 -58
- package/src/lib/animations.ts +0 -50
- package/src/primitives/collapsible-sidebar.tsx +0 -226
- package/src/primitives/dialog.tsx +0 -76
- package/src/primitives/empty-state.tsx +0 -43
- package/src/primitives/index.ts +0 -22
- package/src/primitives/list-view.tsx +0 -155
- package/src/primitives/property-panel.tsx +0 -108
- package/src/primitives/section-header.tsx +0 -19
- package/src/primitives/sidebar-nav.tsx +0 -110
- package/src/primitives/split-pane.tsx +0 -146
- package/src/primitives/status-badge.tsx +0 -10
- package/src/primitives/status-bar.tsx +0 -100
- package/src/primitives/toolbar.tsx +0 -152
- package/src/server.ts +0 -4
- package/src/stores/notification-store.ts +0 -271
- package/src/stores/theme-store.ts +0 -33
- package/src/tokens/lp-tokens.ts +0 -36
- package/src/utils.ts +0 -6
- package/tsconfig.json +0 -17
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2661 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
ACCENT_BLUE: () => ACCENT_BLUE,
|
|
34
|
+
Avatar: () => Avatar,
|
|
35
|
+
BUTTON_RADIUS: () => BUTTON_RADIUS,
|
|
36
|
+
Badge: () => Badge,
|
|
37
|
+
Button: () => Button,
|
|
38
|
+
CELL_BG: () => CELL_BG,
|
|
39
|
+
CHROME_BG: () => CHROME_BG,
|
|
40
|
+
CollapsibleSidebar: () => CollapsibleSidebar,
|
|
41
|
+
Command: () => Command,
|
|
42
|
+
CommandDialog: () => CommandDialog,
|
|
43
|
+
CommandEmpty: () => CommandEmpty,
|
|
44
|
+
CommandGroup: () => CommandGroup,
|
|
45
|
+
CommandInput: () => CommandInput,
|
|
46
|
+
CommandItem: () => CommandItem,
|
|
47
|
+
CommandList: () => CommandList,
|
|
48
|
+
CommandSeparator: () => CommandSeparator,
|
|
49
|
+
CommandShortcut: () => CommandShortcut,
|
|
50
|
+
ContextMenu: () => ContextMenu,
|
|
51
|
+
ContextMenuContent: () => ContextMenuContent,
|
|
52
|
+
ContextMenuGroup: () => ContextMenuGroup,
|
|
53
|
+
ContextMenuItem: () => ContextMenuItem,
|
|
54
|
+
ContextMenuPortal: () => ContextMenuPortal,
|
|
55
|
+
ContextMenuRadioGroup: () => ContextMenuRadioGroup,
|
|
56
|
+
ContextMenuSeparator: () => ContextMenuSeparator,
|
|
57
|
+
ContextMenuSub: () => ContextMenuSub,
|
|
58
|
+
ContextMenuSubContent: () => ContextMenuSubContent,
|
|
59
|
+
ContextMenuSubTrigger: () => ContextMenuSubTrigger,
|
|
60
|
+
ContextMenuTrigger: () => ContextMenuTrigger,
|
|
61
|
+
CostCounter: () => CostCounter,
|
|
62
|
+
DataRow: () => DataRow,
|
|
63
|
+
Dialog: () => Dialog,
|
|
64
|
+
DropdownMenu: () => DropdownMenu,
|
|
65
|
+
DropdownMenuCheckboxItem: () => DropdownMenuCheckboxItem,
|
|
66
|
+
DropdownMenuContent: () => DropdownMenuContent,
|
|
67
|
+
DropdownMenuGroup: () => DropdownMenuGroup,
|
|
68
|
+
DropdownMenuItem: () => DropdownMenuItem,
|
|
69
|
+
DropdownMenuLabel: () => DropdownMenuLabel,
|
|
70
|
+
DropdownMenuPortal: () => DropdownMenuPortal,
|
|
71
|
+
DropdownMenuRadioGroup: () => DropdownMenuRadioGroup,
|
|
72
|
+
DropdownMenuRadioItem: () => DropdownMenuRadioItem,
|
|
73
|
+
DropdownMenuSeparator: () => DropdownMenuSeparator,
|
|
74
|
+
DropdownMenuShortcut: () => DropdownMenuShortcut,
|
|
75
|
+
DropdownMenuSub: () => DropdownMenuSub,
|
|
76
|
+
DropdownMenuSubContent: () => DropdownMenuSubContent,
|
|
77
|
+
DropdownMenuSubTrigger: () => DropdownMenuSubTrigger,
|
|
78
|
+
DropdownMenuTrigger: () => DropdownMenuTrigger,
|
|
79
|
+
EmptyState: () => EmptyState,
|
|
80
|
+
GlassCard: () => GlassCard,
|
|
81
|
+
Input: () => Input,
|
|
82
|
+
KhalLogo: () => KhalLogo,
|
|
83
|
+
ListView: () => ListView,
|
|
84
|
+
LiveFeed: () => LiveFeed,
|
|
85
|
+
MESH_GRADIENT_PALETTE: () => MESH_GRADIENT_PALETTE,
|
|
86
|
+
MeshGradient: () => MeshGradientInner,
|
|
87
|
+
MetricDisplay: () => MetricDisplay,
|
|
88
|
+
Note: () => Note,
|
|
89
|
+
NumberFlow: () => NumberFlow,
|
|
90
|
+
PillBadge: () => PillBadge,
|
|
91
|
+
ProgressBar: () => ProgressBar,
|
|
92
|
+
PropertyPanel: () => PropertyPanel,
|
|
93
|
+
SUBJECTS: () => import_app.SUBJECTS,
|
|
94
|
+
SectionCard: () => SectionCard,
|
|
95
|
+
SectionCardHeader: () => SectionCardHeader,
|
|
96
|
+
SectionHeader: () => SectionHeader,
|
|
97
|
+
Separator: () => Separator3,
|
|
98
|
+
SidebarNav: () => SidebarNav,
|
|
99
|
+
Spinner: () => Spinner,
|
|
100
|
+
SplitPane: () => SplitPane,
|
|
101
|
+
StatusBadge: () => StatusBadge,
|
|
102
|
+
StatusBar: () => StatusBar,
|
|
103
|
+
StatusDot: () => StatusDot,
|
|
104
|
+
TEXT_PRIMARY: () => TEXT_PRIMARY,
|
|
105
|
+
TEXT_SECONDARY: () => TEXT_SECONDARY,
|
|
106
|
+
TEXT_TERTIARY: () => TEXT_TERTIARY,
|
|
107
|
+
ThemeProvider: () => ThemeProvider,
|
|
108
|
+
ThemeSwitcher: () => ThemeSwitcher,
|
|
109
|
+
TickerBar: () => TickerBar,
|
|
110
|
+
Toggle: () => Toggle,
|
|
111
|
+
Toolbar: () => Toolbar,
|
|
112
|
+
Tooltip: () => Tooltip,
|
|
113
|
+
TooltipContent: () => TooltipContent,
|
|
114
|
+
TooltipProvider: () => TooltipProvider,
|
|
115
|
+
TooltipRoot: () => TooltipRoot,
|
|
116
|
+
TooltipTrigger: () => TooltipTrigger,
|
|
117
|
+
WINDOW_RADIUS: () => WINDOW_RADIUS,
|
|
118
|
+
WIN_BG: () => WIN_BG,
|
|
119
|
+
WIN_BORDER: () => WIN_BORDER,
|
|
120
|
+
WIN_BORDER_FOCUSED: () => WIN_BORDER_FOCUSED,
|
|
121
|
+
WindowActiveProvider: () => WindowActiveProvider,
|
|
122
|
+
WindowMinimizedProvider: () => WindowMinimizedProvider,
|
|
123
|
+
badgeVariants: () => badgeVariants,
|
|
124
|
+
buttonVariants: () => buttonVariants,
|
|
125
|
+
cn: () => cn,
|
|
126
|
+
dataRowVariants: () => dataRowVariants,
|
|
127
|
+
fadeIn: () => fadeIn,
|
|
128
|
+
fadeUp: () => fadeUp,
|
|
129
|
+
glassCardVariants: () => glassCardVariants,
|
|
130
|
+
khalEasing: () => khalEasing,
|
|
131
|
+
metricDisplayVariants: () => metricDisplayVariants,
|
|
132
|
+
pillBadgeVariants: () => pillBadgeVariants,
|
|
133
|
+
progressBarVariants: () => progressBarVariants,
|
|
134
|
+
scaleUp: () => scaleUp,
|
|
135
|
+
sectionCardVariants: () => sectionCardVariants,
|
|
136
|
+
springConfig: () => springConfig,
|
|
137
|
+
staggerChild: () => staggerChild,
|
|
138
|
+
staggerContainer: () => staggerContainer,
|
|
139
|
+
stateConfig: () => stateConfig,
|
|
140
|
+
useKhalAuth: () => import_app.useKhalAuth,
|
|
141
|
+
useNats: () => import_app.useNats,
|
|
142
|
+
useNatsSubscription: () => import_app.useNatsSubscription,
|
|
143
|
+
useNotificationStore: () => useNotificationStore,
|
|
144
|
+
useOSAuth: () => import_app.useKhalAuth,
|
|
145
|
+
useReducedMotion: () => useReducedMotion,
|
|
146
|
+
useSidebar: () => useSidebar,
|
|
147
|
+
useThemeStore: () => useThemeStore,
|
|
148
|
+
useWindowActive: () => useWindowActive,
|
|
149
|
+
useWindowMinimized: () => useWindowMinimized
|
|
150
|
+
});
|
|
151
|
+
module.exports = __toCommonJS(index_exports);
|
|
152
|
+
var import_app = require("@khal-os/sdk/app");
|
|
153
|
+
|
|
154
|
+
// src/components/avatar.tsx
|
|
155
|
+
var React = __toESM(require("react"), 1);
|
|
156
|
+
|
|
157
|
+
// src/utils.ts
|
|
158
|
+
var import_clsx = require("clsx");
|
|
159
|
+
var import_tailwind_merge = require("tailwind-merge");
|
|
160
|
+
function cn(...inputs) {
|
|
161
|
+
return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// src/components/status-dot.tsx
|
|
165
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
166
|
+
var sizeMap = { sm: 8, md: 10, lg: 12 };
|
|
167
|
+
var stateConfig = {
|
|
168
|
+
live: { color: "#22c55e", label: "Live", pulse: true },
|
|
169
|
+
online: { color: "#22c55e", label: "Online", pulse: false },
|
|
170
|
+
active: { color: "#22c55e", label: "Active", pulse: true },
|
|
171
|
+
working: { color: "#f59e0b", label: "Working", pulse: true },
|
|
172
|
+
idle: { color: "#64748b", label: "Idle", pulse: false },
|
|
173
|
+
away: { color: "#64748b", label: "Away", pulse: false },
|
|
174
|
+
queued: { color: "#f59e0b", label: "Queued", pulse: false },
|
|
175
|
+
error: { color: "#ef4444", label: "Error", pulse: true }
|
|
176
|
+
};
|
|
177
|
+
function StatusDot({
|
|
178
|
+
state,
|
|
179
|
+
color: colorProp,
|
|
180
|
+
pulse: pulseProp,
|
|
181
|
+
size = "md",
|
|
182
|
+
label: labelProp,
|
|
183
|
+
showLabel = false,
|
|
184
|
+
className,
|
|
185
|
+
style,
|
|
186
|
+
...props
|
|
187
|
+
}) {
|
|
188
|
+
const config = state ? stateConfig[state] : null;
|
|
189
|
+
const color = colorProp ?? config?.color ?? "#64748b";
|
|
190
|
+
const pulse = pulseProp ?? config?.pulse ?? false;
|
|
191
|
+
const label = labelProp ?? config?.label;
|
|
192
|
+
const px = sizeMap[size];
|
|
193
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
194
|
+
"span",
|
|
195
|
+
{
|
|
196
|
+
role: "status",
|
|
197
|
+
"aria-label": label,
|
|
198
|
+
className: cn("relative inline-flex shrink-0 items-center gap-1.5", className),
|
|
199
|
+
style,
|
|
200
|
+
...props,
|
|
201
|
+
children: [
|
|
202
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "relative inline-flex shrink-0", style: { width: px, height: px }, children: [
|
|
203
|
+
pulse && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
204
|
+
"span",
|
|
205
|
+
{
|
|
206
|
+
className: "absolute -inset-0.5 rounded-full",
|
|
207
|
+
style: {
|
|
208
|
+
backgroundColor: color,
|
|
209
|
+
opacity: 0.35,
|
|
210
|
+
animation: "khal-pulse 2s ease-in-out infinite"
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
),
|
|
214
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
215
|
+
"span",
|
|
216
|
+
{
|
|
217
|
+
className: "absolute inset-0 rounded-full",
|
|
218
|
+
style: {
|
|
219
|
+
backgroundColor: color,
|
|
220
|
+
boxShadow: pulse ? `0 0 ${px}px ${color}80` : void 0
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
)
|
|
224
|
+
] }),
|
|
225
|
+
showLabel && label && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-[11px] leading-none", style: { color }, children: label })
|
|
226
|
+
]
|
|
227
|
+
}
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// src/components/avatar.tsx
|
|
232
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
233
|
+
var sizeMap2 = { sm: 24, md: 32, lg: 40 };
|
|
234
|
+
var fontSizeMap = { sm: "10px", md: "12px", lg: "14px" };
|
|
235
|
+
var statusColorMap = {
|
|
236
|
+
online: "var(--khal-status-live)",
|
|
237
|
+
idle: "var(--khal-status-warning)",
|
|
238
|
+
away: "var(--khal-status-idle)"
|
|
239
|
+
};
|
|
240
|
+
function getInitials(name) {
|
|
241
|
+
const parts = name.trim().split(/\s+/);
|
|
242
|
+
if (parts.length >= 2) {
|
|
243
|
+
return `${parts[0][0]}${parts[parts.length - 1][0]}`.toUpperCase();
|
|
244
|
+
}
|
|
245
|
+
return name.charAt(0).toUpperCase();
|
|
246
|
+
}
|
|
247
|
+
var Avatar = React.forwardRef(
|
|
248
|
+
({ name, size = "md", status, src, className, style, ...props }, ref) => {
|
|
249
|
+
const px = sizeMap2[size];
|
|
250
|
+
const [imgError, setImgError] = React.useState(false);
|
|
251
|
+
const showImage = src && !imgError;
|
|
252
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
253
|
+
"div",
|
|
254
|
+
{
|
|
255
|
+
ref,
|
|
256
|
+
className: cn("relative inline-flex shrink-0", className),
|
|
257
|
+
style: { width: px, height: px, ...style },
|
|
258
|
+
...props,
|
|
259
|
+
children: [
|
|
260
|
+
showImage ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
261
|
+
"img",
|
|
262
|
+
{
|
|
263
|
+
src,
|
|
264
|
+
alt: name,
|
|
265
|
+
className: "h-full w-full rounded-full object-cover",
|
|
266
|
+
onError: () => setImgError(true)
|
|
267
|
+
}
|
|
268
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
269
|
+
"div",
|
|
270
|
+
{
|
|
271
|
+
className: "flex h-full w-full select-none items-center justify-center rounded-full border font-medium [background:var(--khal-surface-raised)] [border-color:var(--khal-border-subtle)]",
|
|
272
|
+
style: { fontSize: fontSizeMap[size] },
|
|
273
|
+
children: getInitials(name)
|
|
274
|
+
}
|
|
275
|
+
),
|
|
276
|
+
status && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "absolute -bottom-px -right-px", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(StatusDot, { color: statusColorMap[status], size: "sm", label: status, pulse: status === "online" }) })
|
|
277
|
+
]
|
|
278
|
+
}
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
);
|
|
282
|
+
Avatar.displayName = "Avatar";
|
|
283
|
+
|
|
284
|
+
// src/components/badge.tsx
|
|
285
|
+
var import_class_variance_authority = require("class-variance-authority");
|
|
286
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
287
|
+
var badgeVariants = (0, import_class_variance_authority.cva)(
|
|
288
|
+
"inline-flex items-center rounded-full border font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-blue-700 focus:ring-offset-2",
|
|
289
|
+
{
|
|
290
|
+
variants: {
|
|
291
|
+
variant: {
|
|
292
|
+
gray: "border-gray-alpha-400 bg-gray-100 text-gray-900",
|
|
293
|
+
blue: "border-blue-300 bg-blue-100 text-blue-900",
|
|
294
|
+
green: "border-green-300 bg-green-100 text-green-900",
|
|
295
|
+
amber: "border-amber-300 bg-amber-100 text-amber-900",
|
|
296
|
+
red: "border-red-300 bg-red-100 text-red-900",
|
|
297
|
+
purple: "border-purple-300 bg-purple-100 text-purple-900",
|
|
298
|
+
pink: "border-pink-300 bg-pink-100 text-pink-900",
|
|
299
|
+
teal: "border-teal-300 bg-teal-100 text-teal-900"
|
|
300
|
+
},
|
|
301
|
+
size: {
|
|
302
|
+
sm: "px-2 py-0 text-[11px] leading-[18px]",
|
|
303
|
+
md: "px-2.5 py-0.5 text-[12px] leading-[18px]"
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
defaultVariants: {
|
|
307
|
+
variant: "gray",
|
|
308
|
+
size: "md"
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
);
|
|
312
|
+
function Badge({ className, variant, size, contrast, ...props }) {
|
|
313
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: cn(badgeVariants({ variant, size }), className), ...props });
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// src/components/button.tsx
|
|
317
|
+
var import_react_slot = require("@radix-ui/react-slot");
|
|
318
|
+
var import_class_variance_authority2 = require("class-variance-authority");
|
|
319
|
+
var React2 = __toESM(require("react"), 1);
|
|
320
|
+
|
|
321
|
+
// src/components/spinner.tsx
|
|
322
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
323
|
+
var sizeMap3 = {
|
|
324
|
+
sm: 16,
|
|
325
|
+
md: 20,
|
|
326
|
+
lg: 24
|
|
327
|
+
};
|
|
328
|
+
function Spinner({ size = "md", className, ...props }) {
|
|
329
|
+
const px = sizeMap3[size];
|
|
330
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
331
|
+
"div",
|
|
332
|
+
{
|
|
333
|
+
role: "status",
|
|
334
|
+
"aria-label": "Loading",
|
|
335
|
+
className: cn("inline-flex items-center justify-center", className),
|
|
336
|
+
...props,
|
|
337
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: px, height: px, viewBox: "0 0 20 20", fill: "none", className: "animate-spin", children: [
|
|
338
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "10", cy: "10", r: "8", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", opacity: "0.25" }),
|
|
339
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
340
|
+
"circle",
|
|
341
|
+
{
|
|
342
|
+
cx: "10",
|
|
343
|
+
cy: "10",
|
|
344
|
+
r: "8",
|
|
345
|
+
stroke: "currentColor",
|
|
346
|
+
strokeWidth: "2",
|
|
347
|
+
strokeLinecap: "round",
|
|
348
|
+
strokeDasharray: "50.26",
|
|
349
|
+
strokeDashoffset: "37.7"
|
|
350
|
+
}
|
|
351
|
+
)
|
|
352
|
+
] })
|
|
353
|
+
}
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// src/components/button.tsx
|
|
358
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
359
|
+
var buttonVariants = (0, import_class_variance_authority2.cva)(
|
|
360
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-[var(--khal-radius-button,10px)] text-copy-13 font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--khal-accent-primary)] focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 cursor-pointer",
|
|
361
|
+
{
|
|
362
|
+
variants: {
|
|
363
|
+
variant: {
|
|
364
|
+
default: "bg-gray-1000 text-white [color:white] dark:text-black dark:[color:black] hover:bg-gray-900",
|
|
365
|
+
secondary: "bg-background-100 text-gray-1000 border border-gray-alpha-400 hover:bg-gray-alpha-100",
|
|
366
|
+
tertiary: "bg-transparent text-gray-1000 hover:bg-gray-alpha-200",
|
|
367
|
+
error: "bg-red-700 text-white [color:white] hover:bg-red-600",
|
|
368
|
+
warning: "bg-amber-700 text-white [color:white] hover:bg-amber-600",
|
|
369
|
+
ghost: "hover:bg-gray-alpha-200 text-gray-1000",
|
|
370
|
+
link: "text-blue-700 underline-offset-4 hover:underline"
|
|
371
|
+
},
|
|
372
|
+
size: {
|
|
373
|
+
small: "h-8 px-3 text-copy-13",
|
|
374
|
+
medium: "h-9 px-4 text-copy-13",
|
|
375
|
+
large: "h-10 px-5 text-copy-14",
|
|
376
|
+
icon: "h-9 w-9"
|
|
377
|
+
}
|
|
378
|
+
},
|
|
379
|
+
defaultVariants: {
|
|
380
|
+
variant: "default",
|
|
381
|
+
size: "medium"
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
);
|
|
385
|
+
var Button = React2.forwardRef(
|
|
386
|
+
({
|
|
387
|
+
className,
|
|
388
|
+
variant,
|
|
389
|
+
size,
|
|
390
|
+
asChild = false,
|
|
391
|
+
loading = false,
|
|
392
|
+
prefix,
|
|
393
|
+
suffix,
|
|
394
|
+
typeName,
|
|
395
|
+
type,
|
|
396
|
+
disabled,
|
|
397
|
+
children,
|
|
398
|
+
...props
|
|
399
|
+
}, ref) => {
|
|
400
|
+
let resolvedVariant = variant;
|
|
401
|
+
if (!resolvedVariant && type) {
|
|
402
|
+
if (type === "invert") resolvedVariant = "default";
|
|
403
|
+
else if (type === "shadow") resolvedVariant = "secondary";
|
|
404
|
+
else if (type === "unstyled") resolvedVariant = "ghost";
|
|
405
|
+
}
|
|
406
|
+
const Comp = asChild ? import_react_slot.Slot : "button";
|
|
407
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
408
|
+
Comp,
|
|
409
|
+
{
|
|
410
|
+
className: cn(buttonVariants({ variant: resolvedVariant, size, className })),
|
|
411
|
+
ref,
|
|
412
|
+
type: typeName ?? "button",
|
|
413
|
+
disabled: disabled || loading,
|
|
414
|
+
...props,
|
|
415
|
+
children: loading ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Spinner, { size: "sm" }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
416
|
+
prefix && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "inline-flex shrink-0", children: prefix }),
|
|
417
|
+
children,
|
|
418
|
+
suffix && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "inline-flex shrink-0", children: suffix })
|
|
419
|
+
] })
|
|
420
|
+
}
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
);
|
|
424
|
+
Button.displayName = "Button";
|
|
425
|
+
|
|
426
|
+
// src/components/ContextMenu.tsx
|
|
427
|
+
var ContextMenuPrimitive = __toESM(require("@radix-ui/react-context-menu"), 1);
|
|
428
|
+
var React3 = __toESM(require("react"), 1);
|
|
429
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
430
|
+
var ContextMenu = ContextMenuPrimitive.Root;
|
|
431
|
+
var ContextMenuTrigger = ContextMenuPrimitive.Trigger;
|
|
432
|
+
var ContextMenuGroup = ContextMenuPrimitive.Group;
|
|
433
|
+
var ContextMenuPortal = ContextMenuPrimitive.Portal;
|
|
434
|
+
var ContextMenuSub = ContextMenuPrimitive.Sub;
|
|
435
|
+
var ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup;
|
|
436
|
+
var ContextMenuSubTrigger = React3.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
437
|
+
ContextMenuPrimitive.SubTrigger,
|
|
438
|
+
{
|
|
439
|
+
ref,
|
|
440
|
+
className: cn(
|
|
441
|
+
"flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-copy-13 outline-none select-none",
|
|
442
|
+
"focus:bg-[var(--khal-menu-hover)]",
|
|
443
|
+
"data-[state=open]:bg-[var(--khal-menu-hover)]",
|
|
444
|
+
inset && "pl-8",
|
|
445
|
+
className
|
|
446
|
+
),
|
|
447
|
+
style: { color: "var(--khal-text-primary)" },
|
|
448
|
+
...props,
|
|
449
|
+
children
|
|
450
|
+
}
|
|
451
|
+
));
|
|
452
|
+
ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName;
|
|
453
|
+
var ContextMenuSubContent = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
454
|
+
ContextMenuPrimitive.SubContent,
|
|
455
|
+
{
|
|
456
|
+
ref,
|
|
457
|
+
className: cn(
|
|
458
|
+
"z-[9999] min-w-[8rem] overflow-hidden rounded-xl p-1",
|
|
459
|
+
"data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
|
|
460
|
+
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
|
|
461
|
+
className
|
|
462
|
+
),
|
|
463
|
+
style: {
|
|
464
|
+
background: "var(--khal-menu-bg)",
|
|
465
|
+
border: "1px solid var(--khal-menu-border)",
|
|
466
|
+
boxShadow: "var(--khal-menu-shadow)",
|
|
467
|
+
color: "var(--khal-text-primary)"
|
|
468
|
+
},
|
|
469
|
+
...props
|
|
470
|
+
}
|
|
471
|
+
));
|
|
472
|
+
ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName;
|
|
473
|
+
var ContextMenuContent = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ContextMenuPrimitive.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
474
|
+
ContextMenuPrimitive.Content,
|
|
475
|
+
{
|
|
476
|
+
ref,
|
|
477
|
+
className: cn(
|
|
478
|
+
"z-[9999] min-w-[8rem] overflow-hidden rounded-xl p-1",
|
|
479
|
+
"data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
|
|
480
|
+
className
|
|
481
|
+
),
|
|
482
|
+
style: {
|
|
483
|
+
background: "var(--khal-menu-bg)",
|
|
484
|
+
border: "1px solid var(--khal-menu-border)",
|
|
485
|
+
boxShadow: "var(--khal-menu-shadow)",
|
|
486
|
+
color: "var(--khal-text-primary)"
|
|
487
|
+
},
|
|
488
|
+
...props
|
|
489
|
+
}
|
|
490
|
+
) }));
|
|
491
|
+
ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName;
|
|
492
|
+
var ContextMenuItem = React3.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
493
|
+
ContextMenuPrimitive.Item,
|
|
494
|
+
{
|
|
495
|
+
ref,
|
|
496
|
+
className: cn(
|
|
497
|
+
"relative flex cursor-default items-center gap-2 rounded-lg px-2 py-1.5 text-copy-13 outline-none select-none transition-colors",
|
|
498
|
+
"focus:bg-[var(--khal-menu-hover)]",
|
|
499
|
+
"data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
500
|
+
inset && "pl-8",
|
|
501
|
+
className
|
|
502
|
+
),
|
|
503
|
+
style: { color: "var(--khal-text-primary)" },
|
|
504
|
+
...props
|
|
505
|
+
}
|
|
506
|
+
));
|
|
507
|
+
ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName;
|
|
508
|
+
var ContextMenuSeparator = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
509
|
+
ContextMenuPrimitive.Separator,
|
|
510
|
+
{
|
|
511
|
+
ref,
|
|
512
|
+
className: cn("-mx-1 my-1 h-px", className),
|
|
513
|
+
style: { background: "var(--khal-border-default)" },
|
|
514
|
+
...props
|
|
515
|
+
}
|
|
516
|
+
));
|
|
517
|
+
ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName;
|
|
518
|
+
|
|
519
|
+
// src/components/command.tsx
|
|
520
|
+
var DialogPrimitive = __toESM(require("@radix-ui/react-dialog"), 1);
|
|
521
|
+
var import_cmdk = require("cmdk");
|
|
522
|
+
var import_lucide_react = require("lucide-react");
|
|
523
|
+
var React4 = __toESM(require("react"), 1);
|
|
524
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
525
|
+
var Command = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
526
|
+
import_cmdk.Command,
|
|
527
|
+
{
|
|
528
|
+
ref,
|
|
529
|
+
className: cn("flex h-full w-full flex-col overflow-hidden rounded-xl bg-background-100 text-gray-1000", className),
|
|
530
|
+
...props
|
|
531
|
+
}
|
|
532
|
+
));
|
|
533
|
+
Command.displayName = import_cmdk.Command.displayName;
|
|
534
|
+
function CommandDialog({
|
|
535
|
+
children,
|
|
536
|
+
open,
|
|
537
|
+
onOpenChange,
|
|
538
|
+
...props
|
|
539
|
+
}) {
|
|
540
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DialogPrimitive.Root, { open, onOpenChange, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(DialogPrimitive.Portal, { children: [
|
|
541
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
542
|
+
DialogPrimitive.Overlay,
|
|
543
|
+
{
|
|
544
|
+
className: "fixed inset-0 z-[9999] bg-black/40 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=closed]:animate-out data-[state=closed]:fade-out-0",
|
|
545
|
+
"cmdk-overlay": ""
|
|
546
|
+
}
|
|
547
|
+
),
|
|
548
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
549
|
+
DialogPrimitive.Content,
|
|
550
|
+
{
|
|
551
|
+
className: "fixed left-[50%] top-[20%] z-[9999] w-full max-w-lg translate-x-[-50%] overflow-hidden rounded-xl shadow-lg",
|
|
552
|
+
style: {
|
|
553
|
+
background: "var(--khal-menu-bg)",
|
|
554
|
+
border: "1px solid var(--khal-menu-border)",
|
|
555
|
+
boxShadow: "var(--khal-menu-shadow)",
|
|
556
|
+
backdropFilter: "blur(24px)",
|
|
557
|
+
WebkitBackdropFilter: "blur(24px)"
|
|
558
|
+
},
|
|
559
|
+
"cmdk-dialog": "",
|
|
560
|
+
"aria-describedby": void 0,
|
|
561
|
+
children: [
|
|
562
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DialogPrimitive.Title, { className: "sr-only", children: "Command palette" }),
|
|
563
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
564
|
+
Command,
|
|
565
|
+
{
|
|
566
|
+
className: "[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-gray-700 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3",
|
|
567
|
+
...props,
|
|
568
|
+
children
|
|
569
|
+
}
|
|
570
|
+
)
|
|
571
|
+
]
|
|
572
|
+
}
|
|
573
|
+
)
|
|
574
|
+
] }) });
|
|
575
|
+
}
|
|
576
|
+
var CommandInput = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
577
|
+
"div",
|
|
578
|
+
{
|
|
579
|
+
className: "flex items-center px-3",
|
|
580
|
+
style: { borderBottom: "1px solid var(--khal-border-default)" },
|
|
581
|
+
"cmdk-input-wrapper": "",
|
|
582
|
+
children: [
|
|
583
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react.Search, { className: "mr-2 h-4 w-4 shrink-0 opacity-50" }),
|
|
584
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
585
|
+
import_cmdk.Command.Input,
|
|
586
|
+
{
|
|
587
|
+
ref,
|
|
588
|
+
className: cn(
|
|
589
|
+
"flex h-10 w-full rounded-md bg-transparent py-3 text-copy-13 outline-none",
|
|
590
|
+
"placeholder:text-gray-700",
|
|
591
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
592
|
+
className
|
|
593
|
+
),
|
|
594
|
+
...props
|
|
595
|
+
}
|
|
596
|
+
)
|
|
597
|
+
]
|
|
598
|
+
}
|
|
599
|
+
));
|
|
600
|
+
CommandInput.displayName = import_cmdk.Command.Input.displayName;
|
|
601
|
+
var CommandList = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
602
|
+
import_cmdk.Command.List,
|
|
603
|
+
{
|
|
604
|
+
ref,
|
|
605
|
+
className: cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className),
|
|
606
|
+
...props
|
|
607
|
+
}
|
|
608
|
+
));
|
|
609
|
+
CommandList.displayName = import_cmdk.Command.List.displayName;
|
|
610
|
+
var CommandEmpty = React4.forwardRef((props, ref) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_cmdk.Command.Empty, { ref, className: "py-6 text-center text-copy-13 text-gray-700", ...props }));
|
|
611
|
+
CommandEmpty.displayName = import_cmdk.Command.Empty.displayName;
|
|
612
|
+
var CommandGroup = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
613
|
+
import_cmdk.Command.Group,
|
|
614
|
+
{
|
|
615
|
+
ref,
|
|
616
|
+
className: cn(
|
|
617
|
+
"overflow-hidden p-1 text-gray-1000",
|
|
618
|
+
"[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-label-12 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-gray-700",
|
|
619
|
+
className
|
|
620
|
+
),
|
|
621
|
+
...props
|
|
622
|
+
}
|
|
623
|
+
));
|
|
624
|
+
CommandGroup.displayName = import_cmdk.Command.Group.displayName;
|
|
625
|
+
var CommandSeparator = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_cmdk.Command.Separator, { ref, className: cn("-mx-1 h-px bg-gray-alpha-400", className), ...props }));
|
|
626
|
+
CommandSeparator.displayName = import_cmdk.Command.Separator.displayName;
|
|
627
|
+
var CommandItem = React4.forwardRef(({ className, prefix, callback, onSelect, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
628
|
+
import_cmdk.Command.Item,
|
|
629
|
+
{
|
|
630
|
+
ref,
|
|
631
|
+
onSelect: onSelect ?? callback,
|
|
632
|
+
className: cn(
|
|
633
|
+
"relative flex cursor-default items-center gap-2 rounded-lg px-2 py-1.5 text-copy-13 outline-none select-none",
|
|
634
|
+
"data-[selected=true]:text-gray-1000",
|
|
635
|
+
"data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50",
|
|
636
|
+
className
|
|
637
|
+
),
|
|
638
|
+
...props,
|
|
639
|
+
children: [
|
|
640
|
+
prefix && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "inline-flex shrink-0", children: prefix }),
|
|
641
|
+
children
|
|
642
|
+
]
|
|
643
|
+
}
|
|
644
|
+
));
|
|
645
|
+
CommandItem.displayName = import_cmdk.Command.Item.displayName;
|
|
646
|
+
var CommandShortcut = ({ className, ...props }) => {
|
|
647
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: cn("ml-auto text-label-12 tracking-widest text-gray-700", className), ...props });
|
|
648
|
+
};
|
|
649
|
+
|
|
650
|
+
// src/components/cost-counter.tsx
|
|
651
|
+
var import_react2 = require("motion/react");
|
|
652
|
+
var import_react3 = require("react");
|
|
653
|
+
|
|
654
|
+
// src/components/number-flow.tsx
|
|
655
|
+
var import_react = __toESM(require("@number-flow/react"), 1);
|
|
656
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
657
|
+
function NumberFlow({ transformTiming, spinTiming, opacityTiming, ...props }) {
|
|
658
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
659
|
+
import_react.default,
|
|
660
|
+
{
|
|
661
|
+
transformTiming: transformTiming ?? { duration: 800, easing: "cubic-bezier(0.34, 1.56, 0.64, 1)" },
|
|
662
|
+
spinTiming: spinTiming ?? { duration: 800, easing: "cubic-bezier(0.34, 1.56, 0.64, 1)" },
|
|
663
|
+
opacityTiming: opacityTiming ?? { duration: 350, easing: "ease-out" },
|
|
664
|
+
willChange: true,
|
|
665
|
+
...props
|
|
666
|
+
}
|
|
667
|
+
);
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
// src/components/cost-counter.tsx
|
|
671
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
672
|
+
function CostCounter({ value, suffix, prefix, label, description, budget, budgetColor, className }) {
|
|
673
|
+
const [displayed, setDisplayed] = (0, import_react3.useState)(0);
|
|
674
|
+
const triggered = (0, import_react3.useRef)(false);
|
|
675
|
+
const barRef = (0, import_react3.useRef)(null);
|
|
676
|
+
const barInView = (0, import_react2.useInView)(barRef, { once: true, amount: 0.6 });
|
|
677
|
+
const handleViewport = (0, import_react3.useCallback)(() => {
|
|
678
|
+
if (!triggered.current) {
|
|
679
|
+
triggered.current = true;
|
|
680
|
+
setDisplayed(value);
|
|
681
|
+
}
|
|
682
|
+
}, [value]);
|
|
683
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
684
|
+
import_react2.motion.div,
|
|
685
|
+
{
|
|
686
|
+
onViewportEnter: handleViewport,
|
|
687
|
+
viewport: { once: true, amount: 0.5 },
|
|
688
|
+
className: cn("flex flex-col gap-3", className),
|
|
689
|
+
children: [
|
|
690
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
691
|
+
"div",
|
|
692
|
+
{
|
|
693
|
+
className: "flex items-baseline tabular-nums font-semibold tracking-tight leading-none",
|
|
694
|
+
style: { fontFamily: "var(--font-display, var(--font-geist-sans))" },
|
|
695
|
+
children: [
|
|
696
|
+
prefix && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-[0.7em]", children: prefix }),
|
|
697
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(NumberFlow, { value: displayed }),
|
|
698
|
+
suffix && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-[0.65em] ml-0.5 opacity-70", children: suffix })
|
|
699
|
+
]
|
|
700
|
+
}
|
|
701
|
+
),
|
|
702
|
+
budget != null && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { ref: barRef, className: "w-full h-2 rounded-full overflow-hidden bg-[var(--ds-gray-alpha-200)]", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
703
|
+
import_react2.motion.div,
|
|
704
|
+
{
|
|
705
|
+
initial: { width: 0 },
|
|
706
|
+
animate: barInView ? { width: `${Math.min(budget, 100)}%` } : { width: 0 },
|
|
707
|
+
transition: { duration: 1, ease: [0.22, 1, 0.36, 1], delay: 0.15 },
|
|
708
|
+
className: "h-full rounded-full",
|
|
709
|
+
style: { backgroundColor: budgetColor ?? "var(--ds-accent-warm)" }
|
|
710
|
+
}
|
|
711
|
+
) }),
|
|
712
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex flex-col gap-0.5", children: [
|
|
713
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-sm font-medium leading-5", children: label }),
|
|
714
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-xs opacity-50 leading-4", children: description })
|
|
715
|
+
] })
|
|
716
|
+
]
|
|
717
|
+
}
|
|
718
|
+
);
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
// src/components/data-row.tsx
|
|
722
|
+
var import_class_variance_authority3 = require("class-variance-authority");
|
|
723
|
+
var React5 = __toESM(require("react"), 1);
|
|
724
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
725
|
+
var dataRowVariants = (0, import_class_variance_authority3.cva)("flex items-center gap-3 rounded-lg border border-[#FFFFFF14] font-mono", {
|
|
726
|
+
variants: {
|
|
727
|
+
variant: {
|
|
728
|
+
/** Standard data row — subtle bg */
|
|
729
|
+
default: "bg-[#FFFFFF08] py-2.5 px-3",
|
|
730
|
+
/** Inline/compact — for observability-style data */
|
|
731
|
+
inline: "bg-[#FFFFFF06] py-1.5 px-2.5 text-[11px]",
|
|
732
|
+
/** Nested rule row — for indented rule displays */
|
|
733
|
+
rule: "bg-[#FFFFFF05] py-2.5 px-3"
|
|
734
|
+
}
|
|
735
|
+
},
|
|
736
|
+
defaultVariants: {
|
|
737
|
+
variant: "default"
|
|
738
|
+
}
|
|
739
|
+
});
|
|
740
|
+
var DataRow = React5.forwardRef(
|
|
741
|
+
({ className, variant, label, value, accentColor, statusDot, dotColor, tag, tagColor, children, ...props }, ref) => {
|
|
742
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { ref, className: cn(dataRowVariants({ variant }), className), ...props, children: [
|
|
743
|
+
statusDot && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "size-[6px] shrink-0 rounded-full", style: { backgroundColor: dotColor || "#FFFFFF40" } }),
|
|
744
|
+
tag && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
745
|
+
"span",
|
|
746
|
+
{
|
|
747
|
+
className: "shrink-0 rounded py-0.5 px-2 text-[10px] font-bold uppercase tracking-wide leading-3.5",
|
|
748
|
+
style: {
|
|
749
|
+
color: tagColor || "var(--color-accent, #D49355)",
|
|
750
|
+
backgroundColor: tagColor ? `color-mix(in srgb, ${tagColor} 10%, transparent)` : "rgba(var(--color-accent-rgb, 212,147,85), 0.1)"
|
|
751
|
+
},
|
|
752
|
+
children: tag
|
|
753
|
+
}
|
|
754
|
+
),
|
|
755
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-[12px] text-[#FFFFFFCC] leading-4 min-w-0 truncate", children: label }),
|
|
756
|
+
(value || children) && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "grow" }),
|
|
757
|
+
value && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-[12px] leading-4 tabular-nums shrink-0", style: { color: accentColor || "#FFFFFF99" }, children: value }),
|
|
758
|
+
children
|
|
759
|
+
] });
|
|
760
|
+
}
|
|
761
|
+
);
|
|
762
|
+
DataRow.displayName = "DataRow";
|
|
763
|
+
|
|
764
|
+
// src/components/dropdown-menu.tsx
|
|
765
|
+
var DropdownMenuPrimitive = __toESM(require("@radix-ui/react-dropdown-menu"), 1);
|
|
766
|
+
var React6 = __toESM(require("react"), 1);
|
|
767
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
768
|
+
var DropdownMenu = DropdownMenuPrimitive.Root;
|
|
769
|
+
var DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
|
|
770
|
+
var DropdownMenuGroup = DropdownMenuPrimitive.Group;
|
|
771
|
+
var DropdownMenuPortal = DropdownMenuPrimitive.Portal;
|
|
772
|
+
var DropdownMenuSub = DropdownMenuPrimitive.Sub;
|
|
773
|
+
var DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
|
|
774
|
+
var DropdownMenuSubTrigger = React6.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
775
|
+
DropdownMenuPrimitive.SubTrigger,
|
|
776
|
+
{
|
|
777
|
+
ref,
|
|
778
|
+
className: cn(
|
|
779
|
+
"flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-copy-13 outline-none select-none",
|
|
780
|
+
"focus:bg-[var(--khal-menu-hover)]",
|
|
781
|
+
"data-[state=open]:bg-[var(--khal-menu-hover)]",
|
|
782
|
+
inset && "pl-8",
|
|
783
|
+
className
|
|
784
|
+
),
|
|
785
|
+
style: { color: "var(--khal-text-primary)" },
|
|
786
|
+
...props,
|
|
787
|
+
children
|
|
788
|
+
}
|
|
789
|
+
));
|
|
790
|
+
DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
|
|
791
|
+
var DropdownMenuSubContent = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
792
|
+
DropdownMenuPrimitive.SubContent,
|
|
793
|
+
{
|
|
794
|
+
ref,
|
|
795
|
+
className: cn(
|
|
796
|
+
"z-[9999] min-w-[8rem] overflow-hidden rounded-xl p-1",
|
|
797
|
+
"data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
|
|
798
|
+
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
|
|
799
|
+
"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",
|
|
800
|
+
className
|
|
801
|
+
),
|
|
802
|
+
style: {
|
|
803
|
+
background: "var(--khal-menu-bg)",
|
|
804
|
+
border: "1px solid var(--khal-menu-border)",
|
|
805
|
+
boxShadow: "var(--khal-menu-shadow)",
|
|
806
|
+
color: "var(--khal-text-primary)"
|
|
807
|
+
},
|
|
808
|
+
...props
|
|
809
|
+
}
|
|
810
|
+
));
|
|
811
|
+
DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
|
|
812
|
+
var DropdownMenuContent = React6.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
813
|
+
DropdownMenuPrimitive.Content,
|
|
814
|
+
{
|
|
815
|
+
ref,
|
|
816
|
+
sideOffset,
|
|
817
|
+
className: cn(
|
|
818
|
+
"z-[9999] min-w-[8rem] overflow-hidden rounded-xl p-1",
|
|
819
|
+
"data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
|
|
820
|
+
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
|
|
821
|
+
"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",
|
|
822
|
+
className
|
|
823
|
+
),
|
|
824
|
+
style: {
|
|
825
|
+
background: "var(--khal-menu-bg)",
|
|
826
|
+
border: "1px solid var(--khal-menu-border)",
|
|
827
|
+
boxShadow: "var(--khal-menu-shadow)",
|
|
828
|
+
color: "var(--khal-text-primary)"
|
|
829
|
+
},
|
|
830
|
+
...props
|
|
831
|
+
}
|
|
832
|
+
) }));
|
|
833
|
+
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
|
|
834
|
+
var DropdownMenuItem = React6.forwardRef(({ className, inset, prefix, suffix, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
835
|
+
DropdownMenuPrimitive.Item,
|
|
836
|
+
{
|
|
837
|
+
ref,
|
|
838
|
+
className: cn(
|
|
839
|
+
"relative flex cursor-default items-center gap-2 rounded-lg px-2 py-1.5 text-copy-13 outline-none select-none transition-colors",
|
|
840
|
+
"focus:bg-[var(--khal-menu-hover)]",
|
|
841
|
+
"data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
842
|
+
inset && "pl-8",
|
|
843
|
+
className
|
|
844
|
+
),
|
|
845
|
+
style: { color: "var(--khal-text-primary)" },
|
|
846
|
+
...props,
|
|
847
|
+
children: [
|
|
848
|
+
prefix && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "inline-flex shrink-0", children: prefix }),
|
|
849
|
+
children,
|
|
850
|
+
suffix && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "ml-auto inline-flex shrink-0", style: { color: "var(--khal-text-muted)" }, children: suffix })
|
|
851
|
+
]
|
|
852
|
+
}
|
|
853
|
+
));
|
|
854
|
+
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
|
|
855
|
+
var DropdownMenuCheckboxItem = React6.forwardRef(({ className, children, checked, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
856
|
+
DropdownMenuPrimitive.CheckboxItem,
|
|
857
|
+
{
|
|
858
|
+
ref,
|
|
859
|
+
className: cn(
|
|
860
|
+
"relative flex cursor-default items-center rounded-lg py-1.5 pl-8 pr-2 text-copy-13 outline-none select-none transition-colors",
|
|
861
|
+
"focus:bg-[var(--khal-menu-hover)]",
|
|
862
|
+
"data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
863
|
+
className
|
|
864
|
+
),
|
|
865
|
+
style: { color: "var(--khal-text-primary)" },
|
|
866
|
+
checked,
|
|
867
|
+
...props,
|
|
868
|
+
children: [
|
|
869
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("svg", { width: "15", height: "15", viewBox: "0 0 15 15", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
870
|
+
"path",
|
|
871
|
+
{
|
|
872
|
+
d: "M11.4669 3.72684C11.7558 3.91574 11.8369 4.30308 11.648 4.59198L7.39799 11.092C7.29783 11.2452 7.13556 11.3467 6.95402 11.3699C6.77247 11.3931 6.58989 11.3354 6.45446 11.2124L3.70446 8.71241C3.44905 8.48022 3.43023 8.08494 3.66242 7.82953C3.89461 7.57412 4.28989 7.5553 4.5453 7.78749L6.75292 9.79441L10.6018 3.90792C10.7907 3.61902 11.178 3.53795 11.4669 3.72684Z",
|
|
873
|
+
fill: "currentColor",
|
|
874
|
+
fillRule: "evenodd",
|
|
875
|
+
clipRule: "evenodd"
|
|
876
|
+
}
|
|
877
|
+
) }) }) }),
|
|
878
|
+
children
|
|
879
|
+
]
|
|
880
|
+
}
|
|
881
|
+
));
|
|
882
|
+
DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
|
|
883
|
+
var DropdownMenuRadioItem = React6.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
884
|
+
DropdownMenuPrimitive.RadioItem,
|
|
885
|
+
{
|
|
886
|
+
ref,
|
|
887
|
+
className: cn(
|
|
888
|
+
"relative flex cursor-default items-center rounded-lg py-1.5 pl-8 pr-2 text-copy-13 outline-none select-none transition-colors",
|
|
889
|
+
"focus:bg-[var(--khal-menu-hover)]",
|
|
890
|
+
"data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
891
|
+
className
|
|
892
|
+
),
|
|
893
|
+
style: { color: "var(--khal-text-primary)" },
|
|
894
|
+
...props,
|
|
895
|
+
children: [
|
|
896
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("svg", { width: "8", height: "8", viewBox: "0 0 8 8", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("circle", { cx: "4", cy: "4", r: "4", fill: "currentColor" }) }) }) }),
|
|
897
|
+
children
|
|
898
|
+
]
|
|
899
|
+
}
|
|
900
|
+
));
|
|
901
|
+
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
|
|
902
|
+
var DropdownMenuLabel = React6.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
903
|
+
DropdownMenuPrimitive.Label,
|
|
904
|
+
{
|
|
905
|
+
ref,
|
|
906
|
+
className: cn("px-2 py-1.5 text-label-12 font-semibold", inset && "pl-8", className),
|
|
907
|
+
style: { color: "var(--khal-text-secondary)" },
|
|
908
|
+
...props
|
|
909
|
+
}
|
|
910
|
+
));
|
|
911
|
+
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
|
|
912
|
+
var DropdownMenuSeparator = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
913
|
+
DropdownMenuPrimitive.Separator,
|
|
914
|
+
{
|
|
915
|
+
ref,
|
|
916
|
+
className: cn("-mx-1 my-1 h-px", className),
|
|
917
|
+
style: { background: "var(--khal-border-default)" },
|
|
918
|
+
...props
|
|
919
|
+
}
|
|
920
|
+
));
|
|
921
|
+
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
|
|
922
|
+
var DropdownMenuShortcut = ({ className, ...props }) => {
|
|
923
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
924
|
+
"span",
|
|
925
|
+
{
|
|
926
|
+
className: cn("ml-auto text-label-12 tracking-widest", className),
|
|
927
|
+
style: { color: "var(--khal-text-muted)" },
|
|
928
|
+
...props
|
|
929
|
+
}
|
|
930
|
+
);
|
|
931
|
+
};
|
|
932
|
+
|
|
933
|
+
// src/components/glass-card.tsx
|
|
934
|
+
var import_class_variance_authority4 = require("class-variance-authority");
|
|
935
|
+
var React7 = __toESM(require("react"), 1);
|
|
936
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
937
|
+
var glassCardVariants = (0, import_class_variance_authority4.cva)(
|
|
938
|
+
"relative overflow-hidden border transition-all [background:var(--khal-glass-tint)] [border-color:var(--khal-glass-border)]",
|
|
939
|
+
{
|
|
940
|
+
variants: {
|
|
941
|
+
variant: {
|
|
942
|
+
default: "[box-shadow:var(--khal-shadow-sm)]",
|
|
943
|
+
raised: "[box-shadow:var(--khal-shadow-md)]"
|
|
944
|
+
},
|
|
945
|
+
padding: {
|
|
946
|
+
sm: "p-3",
|
|
947
|
+
md: "p-4",
|
|
948
|
+
lg: "p-6"
|
|
949
|
+
}
|
|
950
|
+
},
|
|
951
|
+
defaultVariants: {
|
|
952
|
+
variant: "default",
|
|
953
|
+
padding: "md"
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
);
|
|
957
|
+
var GlassCard = React7.forwardRef(
|
|
958
|
+
({ className, variant, padding, hover = false, glow, style, children, ...props }, ref) => {
|
|
959
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
|
|
960
|
+
"div",
|
|
961
|
+
{
|
|
962
|
+
ref,
|
|
963
|
+
className: cn(
|
|
964
|
+
glassCardVariants({ variant, padding }),
|
|
965
|
+
hover && [
|
|
966
|
+
"cursor-pointer",
|
|
967
|
+
"hover:-translate-y-0.5",
|
|
968
|
+
"hover:[border-color:var(--khal-border-strong)]",
|
|
969
|
+
"hover:[box-shadow:var(--khal-shadow-lg)]"
|
|
970
|
+
],
|
|
971
|
+
className
|
|
972
|
+
),
|
|
973
|
+
style: {
|
|
974
|
+
backdropFilter: "var(--khal-glass-filter)",
|
|
975
|
+
WebkitBackdropFilter: "var(--khal-glass-filter)",
|
|
976
|
+
borderRadius: "var(--khal-radius-xl)",
|
|
977
|
+
transitionTimingFunction: "var(--khal-ease-spring)",
|
|
978
|
+
transitionDuration: "var(--khal-duration-normal)",
|
|
979
|
+
...style
|
|
980
|
+
},
|
|
981
|
+
...props,
|
|
982
|
+
children: [
|
|
983
|
+
glow && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
984
|
+
"div",
|
|
985
|
+
{
|
|
986
|
+
className: "pointer-events-none absolute inset-0 rounded-[inherit]",
|
|
987
|
+
style: {
|
|
988
|
+
background: `radial-gradient(ellipse at 50% 0%, color-mix(in srgb, ${glow} 20%, transparent), transparent 70%)`
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
),
|
|
992
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "relative", children })
|
|
993
|
+
]
|
|
994
|
+
}
|
|
995
|
+
);
|
|
996
|
+
}
|
|
997
|
+
);
|
|
998
|
+
GlassCard.displayName = "GlassCard";
|
|
999
|
+
|
|
1000
|
+
// src/components/input.tsx
|
|
1001
|
+
var React8 = __toESM(require("react"), 1);
|
|
1002
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1003
|
+
var Input = React8.forwardRef(
|
|
1004
|
+
({ className, label, size, typeName, type, ...props }, ref) => {
|
|
1005
|
+
const input = /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1006
|
+
"input",
|
|
1007
|
+
{
|
|
1008
|
+
type: typeName ?? type,
|
|
1009
|
+
className: cn(
|
|
1010
|
+
"flex w-full rounded-md border border-gray-alpha-400 bg-background-100 px-3 text-copy-13 text-gray-1000 transition-colors",
|
|
1011
|
+
"file:border-0 file:bg-transparent file:text-sm file:font-medium",
|
|
1012
|
+
"placeholder:text-gray-700",
|
|
1013
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-700 focus-visible:ring-offset-1",
|
|
1014
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
1015
|
+
size === "small" ? "h-8" : size === "large" ? "h-11" : "h-9",
|
|
1016
|
+
className
|
|
1017
|
+
),
|
|
1018
|
+
ref,
|
|
1019
|
+
...props
|
|
1020
|
+
}
|
|
1021
|
+
);
|
|
1022
|
+
if (label) {
|
|
1023
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col gap-1.5", children: [
|
|
1024
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { className: "text-label-13 text-gray-900", children: label }),
|
|
1025
|
+
input
|
|
1026
|
+
] });
|
|
1027
|
+
}
|
|
1028
|
+
return input;
|
|
1029
|
+
}
|
|
1030
|
+
);
|
|
1031
|
+
Input.displayName = "Input";
|
|
1032
|
+
|
|
1033
|
+
// src/components/khal-logo.tsx
|
|
1034
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1035
|
+
function KhalLogo({ size = 20, variant = "light", className }) {
|
|
1036
|
+
const color = variant === "light" ? "#FFFFFF" : "#0A0A0A";
|
|
1037
|
+
const showFull = size >= 20;
|
|
1038
|
+
if (!showFull) {
|
|
1039
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1040
|
+
"svg",
|
|
1041
|
+
{
|
|
1042
|
+
viewBox: "0 0 156 155",
|
|
1043
|
+
fill: "none",
|
|
1044
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1045
|
+
width: size,
|
|
1046
|
+
height: size,
|
|
1047
|
+
className,
|
|
1048
|
+
"aria-label": "K",
|
|
1049
|
+
style: { color },
|
|
1050
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1051
|
+
"path",
|
|
1052
|
+
{
|
|
1053
|
+
d: "M0 0H27.4425V65.9519H71.7054L122.829 0H155.362L95.3869 76.1317L164.657 154.92H128.805L72.5913 92.2878H27.4425V154.92H0V0Z",
|
|
1054
|
+
fill: "currentColor"
|
|
1055
|
+
}
|
|
1056
|
+
)
|
|
1057
|
+
}
|
|
1058
|
+
);
|
|
1059
|
+
}
|
|
1060
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1061
|
+
"svg",
|
|
1062
|
+
{
|
|
1063
|
+
viewBox: "0 0 756 155",
|
|
1064
|
+
fill: "none",
|
|
1065
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1066
|
+
width: size * (756 / 155),
|
|
1067
|
+
height: size,
|
|
1068
|
+
className,
|
|
1069
|
+
"aria-label": "khal",
|
|
1070
|
+
style: { color },
|
|
1071
|
+
children: [
|
|
1072
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("g", { clipPath: "url(#khal-logo-clip)", children: [
|
|
1073
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1074
|
+
"path",
|
|
1075
|
+
{
|
|
1076
|
+
d: "M616.81 0H644.252V128.584H765.533V154.92H638.499C635.4 154.92 632.524 154.33 629.867 153.149C627.211 151.969 624.924 150.42 623.007 148.502C621.088 146.584 619.539 144.371 618.359 141.863C617.326 139.206 616.81 136.403 616.81 133.453V0Z",
|
|
1077
|
+
fill: "currentColor"
|
|
1078
|
+
}
|
|
1079
|
+
),
|
|
1080
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1081
|
+
"path",
|
|
1082
|
+
{
|
|
1083
|
+
d: "M443.058 21.2467C445.123 14.4594 448.295 9.22105 452.573 5.53287C456.853 1.8447 462.533 0 469.616 0H519.632C527.009 0 532.911 1.91744 537.337 5.75467C541.763 9.44285 545.009 14.6072 547.076 21.2467L589.125 154.92H560.133L546.411 110.657H461.87L468.73 84.3212H538.665L521.181 26.3359H468.951L430 154.92H400.786L443.058 21.2467Z",
|
|
1084
|
+
fill: "currentColor"
|
|
1085
|
+
}
|
|
1086
|
+
),
|
|
1087
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1088
|
+
"path",
|
|
1089
|
+
{
|
|
1090
|
+
d: "M190.123 0H217.565V62.6322H344.6V0H372.043V154.92H344.6V88.9681H217.565V154.92H190.123V0Z",
|
|
1091
|
+
fill: "currentColor"
|
|
1092
|
+
}
|
|
1093
|
+
),
|
|
1094
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1095
|
+
"path",
|
|
1096
|
+
{
|
|
1097
|
+
d: "M0 0H27.4425V65.9519H71.7054L122.829 0H155.362L95.3869 76.1317L164.657 154.92H128.805L72.5913 92.2878H27.4425V154.92H0V0Z",
|
|
1098
|
+
fill: "currentColor"
|
|
1099
|
+
}
|
|
1100
|
+
)
|
|
1101
|
+
] }),
|
|
1102
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("clipPath", { id: "khal-logo-clip", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("rect", { width: "756", height: "155", fill: "white" }) }) })
|
|
1103
|
+
]
|
|
1104
|
+
}
|
|
1105
|
+
);
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
// src/components/live-feed.tsx
|
|
1109
|
+
var import_react4 = require("motion/react");
|
|
1110
|
+
var import_react5 = require("react");
|
|
1111
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
1112
|
+
var typeColors = {
|
|
1113
|
+
info: "var(--ds-blue-600)",
|
|
1114
|
+
success: "var(--ds-green-600)",
|
|
1115
|
+
warning: "var(--ds-amber-600)",
|
|
1116
|
+
error: "var(--ds-red-600)",
|
|
1117
|
+
agent: "var(--ds-purple-600)",
|
|
1118
|
+
system: "var(--ds-gray-600)"
|
|
1119
|
+
};
|
|
1120
|
+
function LiveFeed({
|
|
1121
|
+
events: externalEvents,
|
|
1122
|
+
maxVisible = 50,
|
|
1123
|
+
showTimestamps = true,
|
|
1124
|
+
height = 300,
|
|
1125
|
+
className
|
|
1126
|
+
}) {
|
|
1127
|
+
const [events, setEvents] = (0, import_react5.useState)(externalEvents ?? []);
|
|
1128
|
+
const scrollRef = (0, import_react5.useRef)(null);
|
|
1129
|
+
const isAtBottom = (0, import_react5.useRef)(true);
|
|
1130
|
+
(0, import_react5.useEffect)(() => {
|
|
1131
|
+
if (externalEvents) {
|
|
1132
|
+
setEvents((prev) => {
|
|
1133
|
+
const combined = [...prev, ...externalEvents.filter((e) => !prev.some((p) => p.id === e.id))];
|
|
1134
|
+
return combined.slice(-maxVisible);
|
|
1135
|
+
});
|
|
1136
|
+
}
|
|
1137
|
+
}, [externalEvents, maxVisible]);
|
|
1138
|
+
(0, import_react5.useEffect)(() => {
|
|
1139
|
+
const el = scrollRef.current;
|
|
1140
|
+
if (el && isAtBottom.current) {
|
|
1141
|
+
el.scrollTop = el.scrollHeight;
|
|
1142
|
+
}
|
|
1143
|
+
}, [events]);
|
|
1144
|
+
const handleScroll = (0, import_react5.useCallback)(() => {
|
|
1145
|
+
const el = scrollRef.current;
|
|
1146
|
+
if (el) {
|
|
1147
|
+
isAtBottom.current = el.scrollHeight - el.scrollTop - el.clientHeight < 24;
|
|
1148
|
+
}
|
|
1149
|
+
}, []);
|
|
1150
|
+
const formatTime = (d) => d.toLocaleTimeString("en-US", { hour12: false, hour: "2-digit", minute: "2-digit", second: "2-digit" });
|
|
1151
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1152
|
+
"div",
|
|
1153
|
+
{
|
|
1154
|
+
ref: scrollRef,
|
|
1155
|
+
onScroll: handleScroll,
|
|
1156
|
+
className: cn("overflow-y-auto overflow-x-hidden font-mono text-xs leading-5 scrollbar-thin", className),
|
|
1157
|
+
style: { height },
|
|
1158
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react4.AnimatePresence, { initial: false, children: events.map((event) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
1159
|
+
import_react4.motion.div,
|
|
1160
|
+
{
|
|
1161
|
+
initial: { opacity: 0, height: 0 },
|
|
1162
|
+
animate: { opacity: 1, height: "auto" },
|
|
1163
|
+
exit: { opacity: 0, height: 0 },
|
|
1164
|
+
transition: { duration: 0.25, ease: [0.22, 1, 0.36, 1] },
|
|
1165
|
+
className: "flex gap-2 px-2 py-0.5 hover:bg-[var(--ds-gray-alpha-100)]",
|
|
1166
|
+
children: [
|
|
1167
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
1168
|
+
"span",
|
|
1169
|
+
{
|
|
1170
|
+
className: "inline-block w-1.5 h-1.5 rounded-full mt-1.5 shrink-0",
|
|
1171
|
+
style: { backgroundColor: typeColors[event.type] }
|
|
1172
|
+
}
|
|
1173
|
+
),
|
|
1174
|
+
showTimestamps && event.timestamp && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "shrink-0 opacity-40 tabular-nums", children: formatTime(event.timestamp) }),
|
|
1175
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "opacity-80 break-words min-w-0", children: event.message })
|
|
1176
|
+
]
|
|
1177
|
+
},
|
|
1178
|
+
event.id
|
|
1179
|
+
)) })
|
|
1180
|
+
}
|
|
1181
|
+
);
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
// src/components/mesh-gradient.tsx
|
|
1185
|
+
var import_react7 = require("react");
|
|
1186
|
+
|
|
1187
|
+
// src/hooks/useReducedMotion.ts
|
|
1188
|
+
var import_react6 = require("react");
|
|
1189
|
+
function useReducedMotion() {
|
|
1190
|
+
const [reduced, setReduced] = (0, import_react6.useState)(false);
|
|
1191
|
+
(0, import_react6.useEffect)(() => {
|
|
1192
|
+
const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
1193
|
+
setReduced(mq.matches || document.documentElement.dataset.reduceMotion === "true");
|
|
1194
|
+
const handler = (e) => setReduced(e.matches);
|
|
1195
|
+
mq.addEventListener("change", handler);
|
|
1196
|
+
return () => mq.removeEventListener("change", handler);
|
|
1197
|
+
}, []);
|
|
1198
|
+
return reduced;
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
// src/components/mesh-gradient.tsx
|
|
1202
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
1203
|
+
var MeshGradientShader = (0, import_react7.lazy)(() => import("@paper-design/shaders-react").then((m) => ({ default: m.MeshGradient })));
|
|
1204
|
+
function StaticFallback({ colors }) {
|
|
1205
|
+
const bg = colors.length >= 2 ? `linear-gradient(135deg, ${colors[0]} 0%, ${colors[Math.floor(colors.length / 2)]} 50%, ${colors[colors.length - 1]} 100%)` : colors[0] ?? "#0A0A0A";
|
|
1206
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { width: "100%", height: "100%", background: bg } });
|
|
1207
|
+
}
|
|
1208
|
+
function MeshGradientInner({ colors, speed = 0.02, className, style }) {
|
|
1209
|
+
const ref = (0, import_react7.useRef)(null);
|
|
1210
|
+
const [visible, setVisible] = (0, import_react7.useState)(false);
|
|
1211
|
+
const reducedMotion = useReducedMotion();
|
|
1212
|
+
(0, import_react7.useEffect)(() => {
|
|
1213
|
+
const el = ref.current;
|
|
1214
|
+
if (!el) return;
|
|
1215
|
+
const observer = new IntersectionObserver(([entry]) => setVisible(entry.isIntersecting), {
|
|
1216
|
+
rootMargin: "100px"
|
|
1217
|
+
});
|
|
1218
|
+
observer.observe(el);
|
|
1219
|
+
return () => observer.disconnect();
|
|
1220
|
+
}, []);
|
|
1221
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { ref, className, style: { position: "absolute", inset: 0, ...style }, children: visible && !reducedMotion ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react7.Suspense, { fallback: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(StaticFallback, { colors }), children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(MeshGradientShader, { colors, speed, style: { width: "100%", height: "100%" } }) }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(StaticFallback, { colors }) });
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
// src/components/metric-display.tsx
|
|
1225
|
+
var import_class_variance_authority5 = require("class-variance-authority");
|
|
1226
|
+
var React9 = __toESM(require("react"), 1);
|
|
1227
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
1228
|
+
var metricDisplayVariants = (0, import_class_variance_authority5.cva)("flex flex-col", {
|
|
1229
|
+
variants: {
|
|
1230
|
+
size: {
|
|
1231
|
+
/** Compact — for inline/tile use (architecture mockup metric tiles) */
|
|
1232
|
+
sm: "gap-1",
|
|
1233
|
+
/** Standard — for dashboard displays */
|
|
1234
|
+
md: "gap-1.5",
|
|
1235
|
+
/** Large — hero stat cards (metrics.tsx) */
|
|
1236
|
+
lg: "gap-2"
|
|
1237
|
+
}
|
|
1238
|
+
},
|
|
1239
|
+
defaultVariants: {
|
|
1240
|
+
size: "md"
|
|
1241
|
+
}
|
|
1242
|
+
});
|
|
1243
|
+
var valueSizeMap = {
|
|
1244
|
+
sm: "text-[22px] font-semibold leading-7 tracking-tight",
|
|
1245
|
+
md: "text-[28px] font-semibold leading-8 tracking-[-0.02em]",
|
|
1246
|
+
lg: "text-[36px] sm:text-[44px] font-semibold leading-none tracking-[-0.04em]"
|
|
1247
|
+
};
|
|
1248
|
+
var labelSizeMap = {
|
|
1249
|
+
sm: "text-[11px] uppercase tracking-[0.06em] text-[#FFFFFF80] font-medium leading-3.5",
|
|
1250
|
+
md: "text-[13px] text-[#FFFFFFCC] font-medium leading-4",
|
|
1251
|
+
lg: "text-[15px] text-[#FFFFFFCC] font-medium leading-5"
|
|
1252
|
+
};
|
|
1253
|
+
var MetricDisplay = React9.forwardRef(
|
|
1254
|
+
({ className, size = "md", value, label, description, prefix, suffix, accentColor, ...props }, ref) => {
|
|
1255
|
+
const resolvedSize = size ?? "md";
|
|
1256
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { ref, className: cn(metricDisplayVariants({ size }), className), ...props, children: [
|
|
1257
|
+
resolvedSize === "sm" && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: labelSizeMap[resolvedSize], children: label }),
|
|
1258
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
1259
|
+
"div",
|
|
1260
|
+
{
|
|
1261
|
+
className: cn(valueSizeMap[resolvedSize], "tabular-nums"),
|
|
1262
|
+
style: accentColor ? { color: accentColor } : void 0,
|
|
1263
|
+
children: [
|
|
1264
|
+
prefix && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { children: prefix }),
|
|
1265
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { children: value }),
|
|
1266
|
+
suffix && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: resolvedSize === "lg" ? "text-[32px] tracking-[-0.02em] ml-0.5" : "ml-0.5", children: suffix })
|
|
1267
|
+
]
|
|
1268
|
+
}
|
|
1269
|
+
),
|
|
1270
|
+
resolvedSize !== "sm" && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: labelSizeMap[resolvedSize], children: label }),
|
|
1271
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "text-[13px] text-[#FFFFFF80] leading-4", children: description })
|
|
1272
|
+
] });
|
|
1273
|
+
}
|
|
1274
|
+
);
|
|
1275
|
+
MetricDisplay.displayName = "MetricDisplay";
|
|
1276
|
+
|
|
1277
|
+
// src/components/note.tsx
|
|
1278
|
+
var import_class_variance_authority6 = require("class-variance-authority");
|
|
1279
|
+
var import_lucide_react2 = require("lucide-react");
|
|
1280
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
1281
|
+
var noteVariants = (0, import_class_variance_authority6.cva)("flex items-start gap-2 rounded-md border p-3 text-copy-13", {
|
|
1282
|
+
variants: {
|
|
1283
|
+
type: {
|
|
1284
|
+
default: "border-gray-alpha-400 bg-gray-alpha-100 text-gray-900",
|
|
1285
|
+
error: "border-red-300 bg-red-100 text-red-900",
|
|
1286
|
+
warning: "border-amber-300 bg-amber-100 text-amber-900",
|
|
1287
|
+
success: "border-green-300 bg-green-100 text-green-900"
|
|
1288
|
+
},
|
|
1289
|
+
size: {
|
|
1290
|
+
default: "p-3",
|
|
1291
|
+
small: "p-2 text-label-12"
|
|
1292
|
+
}
|
|
1293
|
+
},
|
|
1294
|
+
defaultVariants: {
|
|
1295
|
+
type: "default",
|
|
1296
|
+
size: "default"
|
|
1297
|
+
}
|
|
1298
|
+
});
|
|
1299
|
+
var iconMap = {
|
|
1300
|
+
default: import_lucide_react2.Info,
|
|
1301
|
+
error: import_lucide_react2.AlertCircle,
|
|
1302
|
+
warning: import_lucide_react2.AlertTriangle,
|
|
1303
|
+
success: import_lucide_react2.CheckCircle
|
|
1304
|
+
};
|
|
1305
|
+
function Note({ className, type = "default", size, label, action, children, ...props }) {
|
|
1306
|
+
const Icon2 = iconMap[type];
|
|
1307
|
+
const showLabel = label !== false;
|
|
1308
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: cn(noteVariants({ type, size }), className), role: "alert", ...props, children: [
|
|
1309
|
+
showLabel && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Icon2, { className: "h-4 w-4 shrink-0 mt-0.5" }),
|
|
1310
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex-1 min-w-0", children }),
|
|
1311
|
+
action && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "shrink-0", children: action })
|
|
1312
|
+
] });
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
// src/components/pill-badge.tsx
|
|
1316
|
+
var import_class_variance_authority7 = require("class-variance-authority");
|
|
1317
|
+
var React10 = __toESM(require("react"), 1);
|
|
1318
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
1319
|
+
var pillBadgeVariants = (0, import_class_variance_authority7.cva)(
|
|
1320
|
+
"inline-flex items-center gap-1.5 rounded-full font-medium uppercase leading-none whitespace-nowrap",
|
|
1321
|
+
{
|
|
1322
|
+
variants: {
|
|
1323
|
+
variant: {
|
|
1324
|
+
/** Subtle border badge — compliance tags, capability tags */
|
|
1325
|
+
default: "border border-[#FFFFFF26] bg-[#FFFFFF08] text-[#FFFFFFCC]",
|
|
1326
|
+
/** Muted badge — less prominent */
|
|
1327
|
+
muted: "border border-[#FFFFFF14] bg-[#FFFFFF05] text-[#FFFFFFCC]",
|
|
1328
|
+
/** Accent-filled badge — ROI labels, active state badges */
|
|
1329
|
+
accent: "text-[var(--color-accent,#D49355)] bg-[rgba(var(--color-accent-rgb,212,147,85),0.12)]"
|
|
1330
|
+
},
|
|
1331
|
+
size: {
|
|
1332
|
+
sm: "py-1 px-2.5 text-[10px] tracking-[0.08em]",
|
|
1333
|
+
md: "py-1.5 px-3.5 text-[11px] tracking-widest",
|
|
1334
|
+
lg: "py-2 px-4 text-[11px] tracking-widest"
|
|
1335
|
+
}
|
|
1336
|
+
},
|
|
1337
|
+
defaultVariants: {
|
|
1338
|
+
variant: "default",
|
|
1339
|
+
size: "md"
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
);
|
|
1343
|
+
var PillBadge = React10.forwardRef(
|
|
1344
|
+
({ className, variant, size, dot, dotColor, children, ...props }, ref) => {
|
|
1345
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("span", { ref, className: cn(pillBadgeVariants({ variant, size }), className), ...props, children: [
|
|
1346
|
+
dot && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "size-1.5 shrink-0 rounded-full", style: { backgroundColor: dotColor || "#FFFFFF40" } }),
|
|
1347
|
+
children
|
|
1348
|
+
] });
|
|
1349
|
+
}
|
|
1350
|
+
);
|
|
1351
|
+
PillBadge.displayName = "PillBadge";
|
|
1352
|
+
|
|
1353
|
+
// src/components/progress-bar.tsx
|
|
1354
|
+
var import_class_variance_authority8 = require("class-variance-authority");
|
|
1355
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
1356
|
+
var progressBarVariants = (0, import_class_variance_authority8.cva)(
|
|
1357
|
+
"relative w-full overflow-hidden rounded-full [background:var(--khal-border-default)]",
|
|
1358
|
+
{
|
|
1359
|
+
variants: {
|
|
1360
|
+
size: {
|
|
1361
|
+
sm: "h-1.5",
|
|
1362
|
+
md: "h-2.5"
|
|
1363
|
+
}
|
|
1364
|
+
},
|
|
1365
|
+
defaultVariants: {
|
|
1366
|
+
size: "md"
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
);
|
|
1370
|
+
function ProgressBar({
|
|
1371
|
+
value,
|
|
1372
|
+
max = 100,
|
|
1373
|
+
color = "var(--khal-stage-build)",
|
|
1374
|
+
size,
|
|
1375
|
+
showLabel = false,
|
|
1376
|
+
className,
|
|
1377
|
+
...props
|
|
1378
|
+
}) {
|
|
1379
|
+
const percentage = Math.min(100, Math.max(0, value / max * 100));
|
|
1380
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: cn("flex items-center gap-2", className), ...props, children: [
|
|
1381
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1382
|
+
"div",
|
|
1383
|
+
{
|
|
1384
|
+
role: "progressbar",
|
|
1385
|
+
"aria-valuenow": value,
|
|
1386
|
+
"aria-valuemin": 0,
|
|
1387
|
+
"aria-valuemax": max,
|
|
1388
|
+
className: progressBarVariants({ size }),
|
|
1389
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
1390
|
+
"div",
|
|
1391
|
+
{
|
|
1392
|
+
className: "h-full rounded-full",
|
|
1393
|
+
style: {
|
|
1394
|
+
width: `${percentage}%`,
|
|
1395
|
+
background: `linear-gradient(90deg, color-mix(in srgb, ${color} 85%, black), ${color})`,
|
|
1396
|
+
transition: "width var(--khal-duration-normal) var(--khal-ease-spring)"
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
)
|
|
1400
|
+
}
|
|
1401
|
+
),
|
|
1402
|
+
showLabel && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "shrink-0 text-xs tabular-nums opacity-60", children: [
|
|
1403
|
+
value,
|
|
1404
|
+
"/",
|
|
1405
|
+
max
|
|
1406
|
+
] })
|
|
1407
|
+
] });
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
// src/components/section-card.tsx
|
|
1411
|
+
var import_class_variance_authority9 = require("class-variance-authority");
|
|
1412
|
+
var React11 = __toESM(require("react"), 1);
|
|
1413
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
1414
|
+
var sectionCardVariants = (0, import_class_variance_authority9.cva)("relative flex flex-col overflow-hidden", {
|
|
1415
|
+
variants: {
|
|
1416
|
+
variant: {
|
|
1417
|
+
default: "rounded-2xl border border-[#FFFFFF1A] bg-[#FFFFFF0A]",
|
|
1418
|
+
inset: "rounded-tl-xl border-t border-l border-[#FFFFFF26] bg-[#111111]",
|
|
1419
|
+
solid: "rounded-2xl border border-[#FFFFFF1A] bg-[#0D0D0D]"
|
|
1420
|
+
},
|
|
1421
|
+
padding: {
|
|
1422
|
+
none: "",
|
|
1423
|
+
sm: "p-4",
|
|
1424
|
+
md: "p-5 sm:p-6",
|
|
1425
|
+
lg: "p-5 sm:p-6 md:p-8"
|
|
1426
|
+
}
|
|
1427
|
+
},
|
|
1428
|
+
defaultVariants: {
|
|
1429
|
+
variant: "default",
|
|
1430
|
+
padding: "md"
|
|
1431
|
+
}
|
|
1432
|
+
});
|
|
1433
|
+
var SectionCard = React11.forwardRef(
|
|
1434
|
+
({ className, variant, padding, glow, children, ...props }, ref) => {
|
|
1435
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { ref, className: cn(sectionCardVariants({ variant, padding }), className), ...props, children: [
|
|
1436
|
+
glow && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
1437
|
+
"div",
|
|
1438
|
+
{
|
|
1439
|
+
className: "pointer-events-none absolute inset-0 z-0",
|
|
1440
|
+
style: {
|
|
1441
|
+
background: `linear-gradient(180deg, ${glow}22 0%, transparent 60%)`
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
),
|
|
1445
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "relative z-10 flex flex-col h-full", children })
|
|
1446
|
+
] });
|
|
1447
|
+
}
|
|
1448
|
+
);
|
|
1449
|
+
SectionCard.displayName = "SectionCard";
|
|
1450
|
+
function SectionCardHeader({ className, children, ...props }) {
|
|
1451
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
1452
|
+
"div",
|
|
1453
|
+
{
|
|
1454
|
+
className: cn("flex items-center justify-between py-3 px-4 border-b border-[#FFFFFF1A]", className),
|
|
1455
|
+
...props,
|
|
1456
|
+
children
|
|
1457
|
+
}
|
|
1458
|
+
);
|
|
1459
|
+
}
|
|
1460
|
+
SectionCardHeader.displayName = "SectionCardHeader";
|
|
1461
|
+
|
|
1462
|
+
// src/components/separator.tsx
|
|
1463
|
+
var SeparatorPrimitive = __toESM(require("@radix-ui/react-separator"), 1);
|
|
1464
|
+
var React12 = __toESM(require("react"), 1);
|
|
1465
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
1466
|
+
var Separator3 = React12.forwardRef(({ className, orientation = "horizontal", decorative = true, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
1467
|
+
SeparatorPrimitive.Root,
|
|
1468
|
+
{
|
|
1469
|
+
ref,
|
|
1470
|
+
decorative,
|
|
1471
|
+
orientation,
|
|
1472
|
+
className: cn(
|
|
1473
|
+
"shrink-0 bg-gray-alpha-400",
|
|
1474
|
+
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
|
|
1475
|
+
className
|
|
1476
|
+
),
|
|
1477
|
+
...props
|
|
1478
|
+
}
|
|
1479
|
+
));
|
|
1480
|
+
Separator3.displayName = SeparatorPrimitive.Root.displayName;
|
|
1481
|
+
|
|
1482
|
+
// src/components/switch.tsx
|
|
1483
|
+
var SwitchPrimitive = __toESM(require("@radix-ui/react-switch"), 1);
|
|
1484
|
+
var React13 = __toESM(require("react"), 1);
|
|
1485
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
1486
|
+
var Toggle = React13.forwardRef(
|
|
1487
|
+
({ className, onChange, onCheckedChange, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
1488
|
+
SwitchPrimitive.Root,
|
|
1489
|
+
{
|
|
1490
|
+
className: cn(
|
|
1491
|
+
"peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors",
|
|
1492
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-700 focus-visible:ring-offset-2 focus-visible:ring-offset-background-100",
|
|
1493
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
1494
|
+
"data-[state=checked]:bg-gray-1000 data-[state=unchecked]:bg-gray-alpha-400",
|
|
1495
|
+
className
|
|
1496
|
+
),
|
|
1497
|
+
onCheckedChange: onCheckedChange ?? onChange,
|
|
1498
|
+
...props,
|
|
1499
|
+
ref,
|
|
1500
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
1501
|
+
SwitchPrimitive.Thumb,
|
|
1502
|
+
{
|
|
1503
|
+
className: cn(
|
|
1504
|
+
"pointer-events-none block h-4 w-4 rounded-full bg-white shadow-lg ring-0 transition-transform",
|
|
1505
|
+
"data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0"
|
|
1506
|
+
)
|
|
1507
|
+
}
|
|
1508
|
+
)
|
|
1509
|
+
}
|
|
1510
|
+
)
|
|
1511
|
+
);
|
|
1512
|
+
Toggle.displayName = "Toggle";
|
|
1513
|
+
|
|
1514
|
+
// src/components/theme-provider.tsx
|
|
1515
|
+
var import_next_themes = require("next-themes");
|
|
1516
|
+
var import_react8 = require("react");
|
|
1517
|
+
|
|
1518
|
+
// src/stores/theme-store.ts
|
|
1519
|
+
var import_zustand = require("zustand");
|
|
1520
|
+
var import_middleware = require("zustand/middleware");
|
|
1521
|
+
var useThemeStore = (0, import_zustand.create)()(
|
|
1522
|
+
(0, import_middleware.persist)(
|
|
1523
|
+
(set) => ({
|
|
1524
|
+
mode: "dark",
|
|
1525
|
+
setMode: (mode) => set({ mode }),
|
|
1526
|
+
reduceMotion: false,
|
|
1527
|
+
setReduceMotion: (reduceMotion) => set({ reduceMotion }),
|
|
1528
|
+
glassEnabled: false,
|
|
1529
|
+
setGlassEnabled: (glassEnabled) => set({ glassEnabled }),
|
|
1530
|
+
gpuTerminals: false,
|
|
1531
|
+
setGpuTerminals: (gpuTerminals) => set({ gpuTerminals })
|
|
1532
|
+
}),
|
|
1533
|
+
{
|
|
1534
|
+
name: "khal-theme"
|
|
1535
|
+
}
|
|
1536
|
+
)
|
|
1537
|
+
);
|
|
1538
|
+
|
|
1539
|
+
// src/components/theme-provider.tsx
|
|
1540
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
1541
|
+
function ReduceMotionSync() {
|
|
1542
|
+
const reduceMotion = useThemeStore((s) => s.reduceMotion);
|
|
1543
|
+
(0, import_react8.useEffect)(() => {
|
|
1544
|
+
document.documentElement.setAttribute("data-reduce-motion", String(reduceMotion));
|
|
1545
|
+
}, [reduceMotion]);
|
|
1546
|
+
return null;
|
|
1547
|
+
}
|
|
1548
|
+
function GlassSync() {
|
|
1549
|
+
const glassEnabled = useThemeStore((s) => s.glassEnabled);
|
|
1550
|
+
(0, import_react8.useEffect)(() => {
|
|
1551
|
+
const el = document.documentElement;
|
|
1552
|
+
if (glassEnabled) {
|
|
1553
|
+
el.setAttribute("data-glass", "");
|
|
1554
|
+
el.style.setProperty("--khal-glass-enabled", "1");
|
|
1555
|
+
} else {
|
|
1556
|
+
el.removeAttribute("data-glass");
|
|
1557
|
+
el.style.setProperty("--khal-glass-enabled", "0");
|
|
1558
|
+
}
|
|
1559
|
+
}, [glassEnabled]);
|
|
1560
|
+
return null;
|
|
1561
|
+
}
|
|
1562
|
+
function GpuTerminalsSync() {
|
|
1563
|
+
const gpuTerminals = useThemeStore((s) => s.gpuTerminals);
|
|
1564
|
+
(0, import_react8.useEffect)(() => {
|
|
1565
|
+
if (gpuTerminals) {
|
|
1566
|
+
localStorage.setItem("khal-gpu-terminals", "true");
|
|
1567
|
+
} else {
|
|
1568
|
+
localStorage.removeItem("khal-gpu-terminals");
|
|
1569
|
+
}
|
|
1570
|
+
}, [gpuTerminals]);
|
|
1571
|
+
return null;
|
|
1572
|
+
}
|
|
1573
|
+
function ThemeProvider({ children, ...props }) {
|
|
1574
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_next_themes.ThemeProvider, { ...props, children: [
|
|
1575
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ReduceMotionSync, {}),
|
|
1576
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(GlassSync, {}),
|
|
1577
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(GpuTerminalsSync, {}),
|
|
1578
|
+
children
|
|
1579
|
+
] });
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
// src/components/theme-switcher.tsx
|
|
1583
|
+
var import_lucide_react3 = require("lucide-react");
|
|
1584
|
+
var import_next_themes2 = require("next-themes");
|
|
1585
|
+
var import_react9 = require("react");
|
|
1586
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
1587
|
+
var themes = [
|
|
1588
|
+
{ value: "system", label: "System", icon: import_lucide_react3.Monitor },
|
|
1589
|
+
{ value: "light", label: "Light", icon: import_lucide_react3.Sun },
|
|
1590
|
+
{ value: "dark", label: "Dark", icon: import_lucide_react3.Moon }
|
|
1591
|
+
];
|
|
1592
|
+
function ThemeSwitcher({ small, className, onThemeSwitch, disabled }) {
|
|
1593
|
+
const { theme, setTheme } = (0, import_next_themes2.useTheme)();
|
|
1594
|
+
const [mounted, setMounted] = (0, import_react9.useState)(false);
|
|
1595
|
+
(0, import_react9.useEffect)(() => setMounted(true), []);
|
|
1596
|
+
const resolvedTheme = mounted ? theme : void 0;
|
|
1597
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
1598
|
+
"fieldset",
|
|
1599
|
+
{
|
|
1600
|
+
className: cn("inline-flex items-center gap-1 rounded-lg bg-gray-alpha-100 p-1", className),
|
|
1601
|
+
disabled,
|
|
1602
|
+
children: themes.map(({ value, label, icon: Icon2 }) => /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
1603
|
+
"button",
|
|
1604
|
+
{
|
|
1605
|
+
type: "button",
|
|
1606
|
+
role: "radio",
|
|
1607
|
+
"aria-checked": resolvedTheme === value,
|
|
1608
|
+
onClick: () => {
|
|
1609
|
+
setTheme(value);
|
|
1610
|
+
onThemeSwitch?.(value);
|
|
1611
|
+
},
|
|
1612
|
+
className: cn(
|
|
1613
|
+
"inline-flex items-center gap-1.5 rounded-md px-2.5 py-1 text-label-12 transition-colors cursor-pointer",
|
|
1614
|
+
resolvedTheme === value ? "bg-background-100 text-gray-1000 shadow-sm" : "text-gray-700 hover:text-gray-1000"
|
|
1615
|
+
),
|
|
1616
|
+
children: [
|
|
1617
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Icon2, { className: small ? "h-3.5 w-3.5" : "h-4 w-4" }),
|
|
1618
|
+
!small && label
|
|
1619
|
+
]
|
|
1620
|
+
},
|
|
1621
|
+
value
|
|
1622
|
+
))
|
|
1623
|
+
}
|
|
1624
|
+
);
|
|
1625
|
+
}
|
|
1626
|
+
|
|
1627
|
+
// src/components/ticker-bar.tsx
|
|
1628
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
1629
|
+
function TickerBar({ children, duration = 30, pauseOnHover = true, className }) {
|
|
1630
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
1631
|
+
"div",
|
|
1632
|
+
{
|
|
1633
|
+
className: cn("relative w-full overflow-hidden", className),
|
|
1634
|
+
style: {
|
|
1635
|
+
maskImage: "linear-gradient(to right, transparent, black 10%, black 90%, transparent)",
|
|
1636
|
+
WebkitMaskImage: "linear-gradient(to right, transparent, black 10%, black 90%, transparent)"
|
|
1637
|
+
},
|
|
1638
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
1639
|
+
"div",
|
|
1640
|
+
{
|
|
1641
|
+
className: cn("flex w-max", pauseOnHover && "hover:[animation-play-state:paused]"),
|
|
1642
|
+
style: {
|
|
1643
|
+
animation: `khal-ticker ${duration}s linear infinite`
|
|
1644
|
+
},
|
|
1645
|
+
children: [
|
|
1646
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "flex shrink-0 items-center", children }),
|
|
1647
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "flex shrink-0 items-center", "aria-hidden": true, children })
|
|
1648
|
+
]
|
|
1649
|
+
}
|
|
1650
|
+
)
|
|
1651
|
+
}
|
|
1652
|
+
);
|
|
1653
|
+
}
|
|
1654
|
+
|
|
1655
|
+
// src/components/tooltip.tsx
|
|
1656
|
+
var TooltipPrimitive = __toESM(require("@radix-ui/react-tooltip"), 1);
|
|
1657
|
+
var React14 = __toESM(require("react"), 1);
|
|
1658
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
1659
|
+
var TooltipProvider = TooltipPrimitive.Provider;
|
|
1660
|
+
var TooltipRoot = TooltipPrimitive.Root;
|
|
1661
|
+
var TooltipTrigger = TooltipPrimitive.Trigger;
|
|
1662
|
+
var TooltipContent = React14.forwardRef(({ className, sideOffset = 4, style, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(TooltipPrimitive.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
1663
|
+
TooltipPrimitive.Content,
|
|
1664
|
+
{
|
|
1665
|
+
ref,
|
|
1666
|
+
sideOffset,
|
|
1667
|
+
className: cn(
|
|
1668
|
+
"z-[9999] overflow-hidden rounded-md px-2.5 py-1 text-label-12",
|
|
1669
|
+
"animate-in fade-in-0 zoom-in-95",
|
|
1670
|
+
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
|
|
1671
|
+
"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",
|
|
1672
|
+
className
|
|
1673
|
+
),
|
|
1674
|
+
style: {
|
|
1675
|
+
background: "var(--khal-text-primary, var(--ds-gray-1000))",
|
|
1676
|
+
color: "var(--khal-text-inverse, var(--ds-background-100))",
|
|
1677
|
+
...style
|
|
1678
|
+
},
|
|
1679
|
+
...props
|
|
1680
|
+
}
|
|
1681
|
+
) }));
|
|
1682
|
+
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
|
1683
|
+
function Tooltip({ text, children, position = "top", delay, delayTime, desktopOnly, className }) {
|
|
1684
|
+
const delayDuration = delayTime ?? (delay ? 400 : 200);
|
|
1685
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(TooltipProvider, { delayDuration, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(TooltipRoot, { children: [
|
|
1686
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(TooltipTrigger, { asChild: true, children }),
|
|
1687
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(TooltipContent, { side: position, className: cn(desktopOnly && "max-md:hidden", className), children: text })
|
|
1688
|
+
] }) });
|
|
1689
|
+
}
|
|
1690
|
+
|
|
1691
|
+
// src/components/window-minimized-context.tsx
|
|
1692
|
+
var import_react10 = require("react");
|
|
1693
|
+
var WindowMinimizedContext = (0, import_react10.createContext)(false);
|
|
1694
|
+
var WindowMinimizedProvider = WindowMinimizedContext.Provider;
|
|
1695
|
+
function useWindowMinimized() {
|
|
1696
|
+
return (0, import_react10.useContext)(WindowMinimizedContext);
|
|
1697
|
+
}
|
|
1698
|
+
var WindowActiveContext = (0, import_react10.createContext)(true);
|
|
1699
|
+
var WindowActiveProvider = WindowActiveContext.Provider;
|
|
1700
|
+
function useWindowActive() {
|
|
1701
|
+
return (0, import_react10.useContext)(WindowActiveContext);
|
|
1702
|
+
}
|
|
1703
|
+
|
|
1704
|
+
// src/lib/animations.ts
|
|
1705
|
+
var khalEasing = [0.22, 1, 0.36, 1];
|
|
1706
|
+
var springConfig = {
|
|
1707
|
+
stiffness: 300,
|
|
1708
|
+
damping: 22
|
|
1709
|
+
};
|
|
1710
|
+
var fadeUp = {
|
|
1711
|
+
initial: { opacity: 0, y: 12, filter: "blur(4px)" },
|
|
1712
|
+
animate: { opacity: 1, y: 0, filter: "blur(0px)" },
|
|
1713
|
+
transition: { duration: 0.7, ease: khalEasing }
|
|
1714
|
+
};
|
|
1715
|
+
var scaleUp = {
|
|
1716
|
+
initial: { opacity: 0, scale: 0.96, filter: "blur(6px)" },
|
|
1717
|
+
animate: { opacity: 1, scale: 1, filter: "blur(0px)" },
|
|
1718
|
+
transition: { duration: 0.9, ease: khalEasing }
|
|
1719
|
+
};
|
|
1720
|
+
var staggerContainer = {
|
|
1721
|
+
animate: {
|
|
1722
|
+
transition: {
|
|
1723
|
+
staggerChildren: 0.12
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
};
|
|
1727
|
+
var staggerChild = {
|
|
1728
|
+
initial: { opacity: 0, y: 8 },
|
|
1729
|
+
animate: { opacity: 1, y: 0 },
|
|
1730
|
+
transition: { duration: 0.4, ease: khalEasing }
|
|
1731
|
+
};
|
|
1732
|
+
var fadeIn = {
|
|
1733
|
+
initial: { opacity: 0 },
|
|
1734
|
+
animate: { opacity: 1 },
|
|
1735
|
+
transition: { duration: 0.5, ease: khalEasing }
|
|
1736
|
+
};
|
|
1737
|
+
|
|
1738
|
+
// src/primitives/collapsible-sidebar.tsx
|
|
1739
|
+
var import_react11 = require("react");
|
|
1740
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
1741
|
+
var SidebarContext = (0, import_react11.createContext)({
|
|
1742
|
+
collapsed: false,
|
|
1743
|
+
toggle: () => {
|
|
1744
|
+
},
|
|
1745
|
+
size: 220
|
|
1746
|
+
});
|
|
1747
|
+
function useSidebar() {
|
|
1748
|
+
return (0, import_react11.useContext)(SidebarContext);
|
|
1749
|
+
}
|
|
1750
|
+
function CollapsibleSidebarRoot({
|
|
1751
|
+
children,
|
|
1752
|
+
defaultSize = 220,
|
|
1753
|
+
min = 140,
|
|
1754
|
+
max = 400,
|
|
1755
|
+
defaultCollapsed = false,
|
|
1756
|
+
side = "left",
|
|
1757
|
+
className = ""
|
|
1758
|
+
}) {
|
|
1759
|
+
const [collapsed, setCollapsed] = (0, import_react11.useState)(defaultCollapsed);
|
|
1760
|
+
const [size, setSize] = (0, import_react11.useState)(defaultSize);
|
|
1761
|
+
const dragging = (0, import_react11.useRef)(false);
|
|
1762
|
+
const startX = (0, import_react11.useRef)(0);
|
|
1763
|
+
const startSize = (0, import_react11.useRef)(0);
|
|
1764
|
+
const toggle = (0, import_react11.useCallback)(() => setCollapsed((v) => !v), []);
|
|
1765
|
+
const onPointerDown = (0, import_react11.useCallback)(
|
|
1766
|
+
(e) => {
|
|
1767
|
+
if (collapsed) return;
|
|
1768
|
+
e.preventDefault();
|
|
1769
|
+
dragging.current = true;
|
|
1770
|
+
startX.current = e.clientX;
|
|
1771
|
+
startSize.current = size;
|
|
1772
|
+
e.target.setPointerCapture(e.pointerId);
|
|
1773
|
+
},
|
|
1774
|
+
[collapsed, size]
|
|
1775
|
+
);
|
|
1776
|
+
const onPointerMove = (0, import_react11.useCallback)(
|
|
1777
|
+
(e) => {
|
|
1778
|
+
if (!dragging.current) return;
|
|
1779
|
+
const delta = side === "left" ? e.clientX - startX.current : startX.current - e.clientX;
|
|
1780
|
+
setSize(Math.min(max, Math.max(min, startSize.current + delta)));
|
|
1781
|
+
},
|
|
1782
|
+
[side, min, max]
|
|
1783
|
+
);
|
|
1784
|
+
const onPointerUp = (0, import_react11.useCallback)(() => {
|
|
1785
|
+
dragging.current = false;
|
|
1786
|
+
}, []);
|
|
1787
|
+
const resizeHandle = /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
1788
|
+
"div",
|
|
1789
|
+
{
|
|
1790
|
+
className: `w-px shrink-0 cursor-col-resize bg-gray-alpha-200 transition-colors hover:w-0.5 hover:bg-blue-700/50 active:w-0.5 active:bg-blue-700 ${collapsed ? "pointer-events-none" : ""}`,
|
|
1791
|
+
onPointerDown,
|
|
1792
|
+
onPointerMove,
|
|
1793
|
+
onPointerUp,
|
|
1794
|
+
role: "separator",
|
|
1795
|
+
"aria-orientation": "vertical"
|
|
1796
|
+
}
|
|
1797
|
+
);
|
|
1798
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(SidebarContext.Provider, { value: { collapsed, toggle, size }, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: `flex shrink-0 ${className}`, style: { width: collapsed ? 0 : size }, children: [
|
|
1799
|
+
side === "right" && resizeHandle,
|
|
1800
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
1801
|
+
"div",
|
|
1802
|
+
{
|
|
1803
|
+
className: `flex h-full flex-col overflow-hidden transition-[width] duration-150 ${collapsed ? "w-0" : "w-full"}`,
|
|
1804
|
+
children
|
|
1805
|
+
}
|
|
1806
|
+
),
|
|
1807
|
+
side === "left" && resizeHandle
|
|
1808
|
+
] }) });
|
|
1809
|
+
}
|
|
1810
|
+
function SidebarHeader({ children, className = "" }) {
|
|
1811
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: `flex h-9 shrink-0 items-center justify-between border-b border-gray-alpha-200 px-3 ${className}`, children });
|
|
1812
|
+
}
|
|
1813
|
+
function CollapseButton({ className = "" }) {
|
|
1814
|
+
const { collapsed, toggle } = useSidebar();
|
|
1815
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
1816
|
+
"button",
|
|
1817
|
+
{
|
|
1818
|
+
onClick: toggle,
|
|
1819
|
+
className: `inline-flex h-5 w-5 items-center justify-center rounded text-gray-800 hover:bg-gray-alpha-200 hover:text-gray-1000 transition-colors ${className}`,
|
|
1820
|
+
"aria-label": collapsed ? "Expand sidebar" : "Collapse sidebar",
|
|
1821
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
1822
|
+
"path",
|
|
1823
|
+
{
|
|
1824
|
+
d: collapsed ? "M4.5 2L8.5 6L4.5 10" : "M8.5 2L4.5 6L8.5 10",
|
|
1825
|
+
stroke: "currentColor",
|
|
1826
|
+
strokeWidth: "1.5",
|
|
1827
|
+
strokeLinecap: "round",
|
|
1828
|
+
strokeLinejoin: "round"
|
|
1829
|
+
}
|
|
1830
|
+
) })
|
|
1831
|
+
}
|
|
1832
|
+
);
|
|
1833
|
+
}
|
|
1834
|
+
function SidebarContent({ children, className = "" }) {
|
|
1835
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: `flex-1 overflow-y-auto ${className}`, children });
|
|
1836
|
+
}
|
|
1837
|
+
function SidebarSection({
|
|
1838
|
+
title,
|
|
1839
|
+
children,
|
|
1840
|
+
className = ""
|
|
1841
|
+
}) {
|
|
1842
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: `${className}`, children: [
|
|
1843
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "px-3 pt-2 pb-1", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "text-label-13 font-medium text-gray-800", children: title }) }),
|
|
1844
|
+
children
|
|
1845
|
+
] });
|
|
1846
|
+
}
|
|
1847
|
+
function SidebarItem({ children, icon, active, indent = 0, onClick, className = "" }) {
|
|
1848
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
1849
|
+
"button",
|
|
1850
|
+
{
|
|
1851
|
+
onClick,
|
|
1852
|
+
className: `flex w-full items-center gap-2 rounded-md px-2 py-1 text-left text-label-13 transition-colors
|
|
1853
|
+
${active ? "bg-gray-alpha-200 text-gray-1000" : "text-gray-900 hover:bg-gray-alpha-100 hover:text-gray-1000"}
|
|
1854
|
+
${className}`,
|
|
1855
|
+
style: { paddingLeft: 8 + indent * 12 },
|
|
1856
|
+
children: [
|
|
1857
|
+
icon && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "shrink-0 text-gray-800 [&>svg]:h-3.5 [&>svg]:w-3.5", children: icon }),
|
|
1858
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "min-w-0 truncate", children })
|
|
1859
|
+
]
|
|
1860
|
+
}
|
|
1861
|
+
);
|
|
1862
|
+
}
|
|
1863
|
+
var CollapsibleSidebar = Object.assign(CollapsibleSidebarRoot, {
|
|
1864
|
+
Header: SidebarHeader,
|
|
1865
|
+
CollapseButton,
|
|
1866
|
+
Content: SidebarContent,
|
|
1867
|
+
Section: SidebarSection,
|
|
1868
|
+
Item: SidebarItem
|
|
1869
|
+
});
|
|
1870
|
+
|
|
1871
|
+
// src/primitives/dialog.tsx
|
|
1872
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
1873
|
+
function DialogRoot({ open, onClose, children }) {
|
|
1874
|
+
if (!open) return null;
|
|
1875
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/40", onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
1876
|
+
"div",
|
|
1877
|
+
{
|
|
1878
|
+
className: "bg-popover text-popover-foreground rounded-lg border p-6 shadow-lg",
|
|
1879
|
+
onClick: (e) => e.stopPropagation(),
|
|
1880
|
+
children
|
|
1881
|
+
}
|
|
1882
|
+
) });
|
|
1883
|
+
}
|
|
1884
|
+
function Body({ children }) {
|
|
1885
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "flex items-start gap-4", children });
|
|
1886
|
+
}
|
|
1887
|
+
function Icon({ children, variant: _variant }) {
|
|
1888
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "shrink-0", children });
|
|
1889
|
+
}
|
|
1890
|
+
function Title2({ children }) {
|
|
1891
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("h2", { className: "text-lg font-semibold", children });
|
|
1892
|
+
}
|
|
1893
|
+
function Description({ children }) {
|
|
1894
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { className: "text-muted-foreground text-sm", children });
|
|
1895
|
+
}
|
|
1896
|
+
function Actions({ children }) {
|
|
1897
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: "mt-4 flex justify-end gap-2", children });
|
|
1898
|
+
}
|
|
1899
|
+
function Cancel({ children, ...props }) {
|
|
1900
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("button", { type: "button", className: "rounded px-3 py-1.5 text-sm hover:bg-muted", ...props, children });
|
|
1901
|
+
}
|
|
1902
|
+
function Confirm({ children, variant: _variant, ...props }) {
|
|
1903
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("button", { type: "button", className: "rounded bg-destructive px-3 py-1.5 text-sm text-destructive-foreground", ...props, children });
|
|
1904
|
+
}
|
|
1905
|
+
var Dialog = Object.assign(DialogRoot, {
|
|
1906
|
+
Body,
|
|
1907
|
+
Icon,
|
|
1908
|
+
Title: Title2,
|
|
1909
|
+
Description,
|
|
1910
|
+
Actions,
|
|
1911
|
+
Cancel,
|
|
1912
|
+
Confirm
|
|
1913
|
+
});
|
|
1914
|
+
|
|
1915
|
+
// src/primitives/empty-state.tsx
|
|
1916
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
1917
|
+
function EmptyState({ icon, title, description, action, compact, className = "" }) {
|
|
1918
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
|
|
1919
|
+
"div",
|
|
1920
|
+
{
|
|
1921
|
+
className: `flex flex-col items-center justify-center text-center ${compact ? "gap-2 py-6" : "gap-3 py-12"} ${className}`,
|
|
1922
|
+
children: [
|
|
1923
|
+
icon && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: `text-gray-700 ${compact ? "[&>svg]:h-5 [&>svg]:w-5" : "[&>svg]:h-8 [&>svg]:w-8"}`, children: icon }),
|
|
1924
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "space-y-0.5", children: [
|
|
1925
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)("p", { className: "text-label-13 font-medium text-gray-1000", children: title }),
|
|
1926
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("p", { className: `text-gray-800 ${compact ? "text-label-13" : "text-label-13"}`, children: description })
|
|
1927
|
+
] }),
|
|
1928
|
+
action && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "mt-2 shrink-0", children: action })
|
|
1929
|
+
]
|
|
1930
|
+
}
|
|
1931
|
+
);
|
|
1932
|
+
}
|
|
1933
|
+
|
|
1934
|
+
// src/primitives/list-view.tsx
|
|
1935
|
+
var import_react12 = require("react");
|
|
1936
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
1937
|
+
function ListView({
|
|
1938
|
+
items,
|
|
1939
|
+
selected,
|
|
1940
|
+
onSelect,
|
|
1941
|
+
onActivate,
|
|
1942
|
+
renderItem,
|
|
1943
|
+
getKey,
|
|
1944
|
+
multiSelect = false,
|
|
1945
|
+
emptyMessage = "No items",
|
|
1946
|
+
className = ""
|
|
1947
|
+
}) {
|
|
1948
|
+
const [focusIndex, setFocusIndex] = (0, import_react12.useState)(0);
|
|
1949
|
+
const listRef = (0, import_react12.useRef)(null);
|
|
1950
|
+
const selectedSet = new Set(selected == null ? [] : Array.isArray(selected) ? selected : [selected]);
|
|
1951
|
+
const clamp = (0, import_react12.useCallback)((i) => Math.max(0, Math.min(items.length - 1, i)), [items.length]);
|
|
1952
|
+
(0, import_react12.useEffect)(() => {
|
|
1953
|
+
setFocusIndex((prev) => clamp(prev));
|
|
1954
|
+
}, [items.length, clamp]);
|
|
1955
|
+
const scrollToIndex = (0, import_react12.useCallback)((i) => {
|
|
1956
|
+
const el = listRef.current?.children[i];
|
|
1957
|
+
el?.scrollIntoView({ block: "nearest" });
|
|
1958
|
+
}, []);
|
|
1959
|
+
const handleKeyDown = (0, import_react12.useCallback)(
|
|
1960
|
+
(e) => {
|
|
1961
|
+
switch (e.key) {
|
|
1962
|
+
case "ArrowDown": {
|
|
1963
|
+
e.preventDefault();
|
|
1964
|
+
const next = clamp(focusIndex + 1);
|
|
1965
|
+
setFocusIndex(next);
|
|
1966
|
+
scrollToIndex(next);
|
|
1967
|
+
if (!multiSelect) onSelect?.(getKey(items[next]));
|
|
1968
|
+
break;
|
|
1969
|
+
}
|
|
1970
|
+
case "ArrowUp": {
|
|
1971
|
+
e.preventDefault();
|
|
1972
|
+
const prev = clamp(focusIndex - 1);
|
|
1973
|
+
setFocusIndex(prev);
|
|
1974
|
+
scrollToIndex(prev);
|
|
1975
|
+
if (!multiSelect) onSelect?.(getKey(items[prev]));
|
|
1976
|
+
break;
|
|
1977
|
+
}
|
|
1978
|
+
case "Home": {
|
|
1979
|
+
e.preventDefault();
|
|
1980
|
+
setFocusIndex(0);
|
|
1981
|
+
scrollToIndex(0);
|
|
1982
|
+
if (!multiSelect && items.length > 0) onSelect?.(getKey(items[0]));
|
|
1983
|
+
break;
|
|
1984
|
+
}
|
|
1985
|
+
case "End": {
|
|
1986
|
+
e.preventDefault();
|
|
1987
|
+
const last = items.length - 1;
|
|
1988
|
+
setFocusIndex(last);
|
|
1989
|
+
scrollToIndex(last);
|
|
1990
|
+
if (!multiSelect && items.length > 0) onSelect?.(getKey(items[last]));
|
|
1991
|
+
break;
|
|
1992
|
+
}
|
|
1993
|
+
case "Enter":
|
|
1994
|
+
case " ": {
|
|
1995
|
+
e.preventDefault();
|
|
1996
|
+
const item = items[focusIndex];
|
|
1997
|
+
if (item) {
|
|
1998
|
+
onSelect?.(getKey(item));
|
|
1999
|
+
if (e.key === "Enter") onActivate?.(item);
|
|
2000
|
+
}
|
|
2001
|
+
break;
|
|
2002
|
+
}
|
|
2003
|
+
}
|
|
2004
|
+
},
|
|
2005
|
+
[focusIndex, items, clamp, scrollToIndex, onSelect, onActivate, getKey, multiSelect]
|
|
2006
|
+
);
|
|
2007
|
+
if (items.length === 0) {
|
|
2008
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: `flex h-full items-center justify-center text-label-13 text-gray-800 ${className}`, children: emptyMessage });
|
|
2009
|
+
}
|
|
2010
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
2011
|
+
"div",
|
|
2012
|
+
{
|
|
2013
|
+
ref: listRef,
|
|
2014
|
+
className: `overflow-y-auto outline-none ${className}`,
|
|
2015
|
+
role: "listbox",
|
|
2016
|
+
tabIndex: 0,
|
|
2017
|
+
onKeyDown: handleKeyDown,
|
|
2018
|
+
"aria-multiselectable": multiSelect,
|
|
2019
|
+
children: items.map((item, i) => {
|
|
2020
|
+
const key = getKey(item);
|
|
2021
|
+
const isSelected = selectedSet.has(key);
|
|
2022
|
+
const isFocused = i === focusIndex;
|
|
2023
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
2024
|
+
"div",
|
|
2025
|
+
{
|
|
2026
|
+
role: "option",
|
|
2027
|
+
"aria-selected": isSelected,
|
|
2028
|
+
className: `cursor-default select-none px-2 py-1 transition-colors
|
|
2029
|
+
${isSelected ? "bg-blue-700/15 text-gray-1000" : "text-gray-1000"}
|
|
2030
|
+
${isFocused && !isSelected ? "bg-gray-alpha-100" : ""}
|
|
2031
|
+
hover:bg-gray-alpha-200`,
|
|
2032
|
+
onClick: () => {
|
|
2033
|
+
setFocusIndex(i);
|
|
2034
|
+
onSelect?.(key);
|
|
2035
|
+
},
|
|
2036
|
+
onDoubleClick: () => onActivate?.(item),
|
|
2037
|
+
children: renderItem(item, { selected: isSelected, focused: isFocused, index: i })
|
|
2038
|
+
},
|
|
2039
|
+
key
|
|
2040
|
+
);
|
|
2041
|
+
})
|
|
2042
|
+
}
|
|
2043
|
+
);
|
|
2044
|
+
}
|
|
2045
|
+
|
|
2046
|
+
// src/primitives/property-panel.tsx
|
|
2047
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
2048
|
+
function PropertyPanelRoot({ title, children, className = "" }) {
|
|
2049
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: `flex flex-col overflow-y-auto ${className}`, children: [
|
|
2050
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "sticky top-0 z-10 border-b border-gray-alpha-200 bg-background-100 px-3 py-2", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("h3", { className: "text-label-13 font-medium text-gray-1000", children: title }) }),
|
|
2051
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "flex flex-col", children })
|
|
2052
|
+
] });
|
|
2053
|
+
}
|
|
2054
|
+
function PropertySection({
|
|
2055
|
+
title,
|
|
2056
|
+
children,
|
|
2057
|
+
collapsible: _collapsible = false,
|
|
2058
|
+
defaultOpen: _defaultOpen = true
|
|
2059
|
+
}) {
|
|
2060
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "border-b border-gray-alpha-200 last:border-b-0", children: [
|
|
2061
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: "px-3 pt-3 pb-1", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-label-13 font-medium text-gray-800", children: title }) }),
|
|
2062
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { className: `px-3 pb-2 ${title ? "" : "pt-2"}`, children })
|
|
2063
|
+
] });
|
|
2064
|
+
}
|
|
2065
|
+
function PropertyRow({ label, value, children, mono }) {
|
|
2066
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "flex items-baseline justify-between gap-4 py-1", children: [
|
|
2067
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("dt", { className: "shrink-0 text-label-13 text-gray-800", children: label }),
|
|
2068
|
+
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)("dd", { className: `min-w-0 truncate text-right text-label-13 text-gray-1000 ${mono ? "font-mono" : ""}`, children: children ?? value })
|
|
2069
|
+
] });
|
|
2070
|
+
}
|
|
2071
|
+
function PropertySeparator() {
|
|
2072
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Separator3, { className: "my-1" });
|
|
2073
|
+
}
|
|
2074
|
+
var PropertyPanel = Object.assign(PropertyPanelRoot, {
|
|
2075
|
+
Section: PropertySection,
|
|
2076
|
+
Row: PropertyRow,
|
|
2077
|
+
Separator: PropertySeparator
|
|
2078
|
+
});
|
|
2079
|
+
|
|
2080
|
+
// src/primitives/section-header.tsx
|
|
2081
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
2082
|
+
function SectionHeader({
|
|
2083
|
+
title,
|
|
2084
|
+
description,
|
|
2085
|
+
children
|
|
2086
|
+
}) {
|
|
2087
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "mb-4 flex items-start justify-between", children: [
|
|
2088
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { children: [
|
|
2089
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("h2", { className: "text-copy-13 font-medium text-gray-1000", children: title }),
|
|
2090
|
+
description && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { className: "mt-0.5 text-copy-13 text-gray-900", children: description })
|
|
2091
|
+
] }),
|
|
2092
|
+
children
|
|
2093
|
+
] });
|
|
2094
|
+
}
|
|
2095
|
+
|
|
2096
|
+
// src/primitives/sidebar-nav.tsx
|
|
2097
|
+
var import_jsx_runtime34 = require("react/jsx-runtime");
|
|
2098
|
+
function SidebarNavRoot({ children, label, title, className = "" }) {
|
|
2099
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("nav", { className: `flex flex-col py-2 ${className}`, "aria-label": label, children: [
|
|
2100
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "px-3 pb-1", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "text-copy-13 font-medium text-gray-800", children: title }) }),
|
|
2101
|
+
children
|
|
2102
|
+
] });
|
|
2103
|
+
}
|
|
2104
|
+
function SidebarNavGroup({ children, title, className = "" }) {
|
|
2105
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className, children: [
|
|
2106
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { className: "px-3 pt-4 pb-1", children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "text-copy-13 font-medium text-gray-800", children: title }) }),
|
|
2107
|
+
children
|
|
2108
|
+
] });
|
|
2109
|
+
}
|
|
2110
|
+
function SidebarNavItem({ children, active, onClick, icon, suffix, className = "" }) {
|
|
2111
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(
|
|
2112
|
+
"button",
|
|
2113
|
+
{
|
|
2114
|
+
onClick,
|
|
2115
|
+
className: `mx-1 flex items-center gap-2 rounded-md px-2 py-1 text-copy-13 transition-colors ${active ? "bg-gray-alpha-200 text-gray-1000" : "text-gray-900 hover:bg-gray-alpha-100 hover:text-gray-1000"} ${className}`,
|
|
2116
|
+
children: [
|
|
2117
|
+
icon && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "shrink-0 text-gray-800 [&>svg]:h-3.5 [&>svg]:w-3.5", children: icon }),
|
|
2118
|
+
/* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "min-w-0 truncate", children }),
|
|
2119
|
+
suffix && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { className: "ml-auto font-mono text-copy-13 tabular-nums text-gray-700", children: suffix })
|
|
2120
|
+
]
|
|
2121
|
+
}
|
|
2122
|
+
);
|
|
2123
|
+
}
|
|
2124
|
+
var SidebarNav = Object.assign(SidebarNavRoot, {
|
|
2125
|
+
Group: SidebarNavGroup,
|
|
2126
|
+
Item: SidebarNavItem
|
|
2127
|
+
});
|
|
2128
|
+
|
|
2129
|
+
// src/primitives/split-pane.tsx
|
|
2130
|
+
var import_react13 = require("react");
|
|
2131
|
+
var import_jsx_runtime35 = require("react/jsx-runtime");
|
|
2132
|
+
function useMediaQuery(query) {
|
|
2133
|
+
const subscribe = (0, import_react13.useCallback)(
|
|
2134
|
+
(callback) => {
|
|
2135
|
+
const mql = window.matchMedia(query);
|
|
2136
|
+
mql.addEventListener("change", callback);
|
|
2137
|
+
return () => mql.removeEventListener("change", callback);
|
|
2138
|
+
},
|
|
2139
|
+
[query]
|
|
2140
|
+
);
|
|
2141
|
+
const getSnapshot = (0, import_react13.useCallback)(() => window.matchMedia(query).matches, [query]);
|
|
2142
|
+
const getServerSnapshot = (0, import_react13.useCallback)(() => false, []);
|
|
2143
|
+
return (0, import_react13.useSyncExternalStore)(subscribe, getSnapshot, getServerSnapshot);
|
|
2144
|
+
}
|
|
2145
|
+
function SplitPaneRoot({
|
|
2146
|
+
children,
|
|
2147
|
+
direction = "horizontal",
|
|
2148
|
+
defaultSize = 240,
|
|
2149
|
+
min = 100,
|
|
2150
|
+
max = 600,
|
|
2151
|
+
collapseBelow = 640,
|
|
2152
|
+
onResize,
|
|
2153
|
+
className = ""
|
|
2154
|
+
}) {
|
|
2155
|
+
const [size, setSize] = (0, import_react13.useState)(defaultSize);
|
|
2156
|
+
const containerRef = (0, import_react13.useRef)(null);
|
|
2157
|
+
const dragging = (0, import_react13.useRef)(false);
|
|
2158
|
+
const startPos = (0, import_react13.useRef)(0);
|
|
2159
|
+
const startSize = (0, import_react13.useRef)(0);
|
|
2160
|
+
const isMobile = useMediaQuery(`(max-width: ${collapseBelow}px)`);
|
|
2161
|
+
const isHorizontal = direction === "horizontal" && !isMobile;
|
|
2162
|
+
const [first, second] = children;
|
|
2163
|
+
const onPointerDown = (0, import_react13.useCallback)(
|
|
2164
|
+
(e) => {
|
|
2165
|
+
e.preventDefault();
|
|
2166
|
+
dragging.current = true;
|
|
2167
|
+
startPos.current = isHorizontal ? e.clientX : e.clientY;
|
|
2168
|
+
startSize.current = size;
|
|
2169
|
+
e.target.setPointerCapture(e.pointerId);
|
|
2170
|
+
},
|
|
2171
|
+
[isHorizontal, size]
|
|
2172
|
+
);
|
|
2173
|
+
const onPointerMove = (0, import_react13.useCallback)(
|
|
2174
|
+
(e) => {
|
|
2175
|
+
if (!dragging.current) return;
|
|
2176
|
+
const delta = (isHorizontal ? e.clientX : e.clientY) - startPos.current;
|
|
2177
|
+
const next = Math.min(max, Math.max(min, startSize.current + delta));
|
|
2178
|
+
setSize(next);
|
|
2179
|
+
onResize?.(next);
|
|
2180
|
+
},
|
|
2181
|
+
[isHorizontal, min, max, onResize]
|
|
2182
|
+
);
|
|
2183
|
+
const onPointerUp = (0, import_react13.useCallback)(() => {
|
|
2184
|
+
dragging.current = false;
|
|
2185
|
+
}, []);
|
|
2186
|
+
if (isMobile) {
|
|
2187
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { ref: containerRef, className: `flex flex-col h-full w-full overflow-hidden ${className}`, children: [
|
|
2188
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "shrink-0 overflow-auto border-b border-gray-alpha-200", children: first }),
|
|
2189
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "flex-1 overflow-hidden", children: second })
|
|
2190
|
+
] });
|
|
2191
|
+
}
|
|
2192
|
+
const firstStyle = isHorizontal ? { width: size, minWidth: min, maxWidth: max, flexShrink: 0 } : { height: size, minHeight: min, maxHeight: max, flexShrink: 0 };
|
|
2193
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
|
|
2194
|
+
"div",
|
|
2195
|
+
{
|
|
2196
|
+
ref: containerRef,
|
|
2197
|
+
className: `flex ${isHorizontal ? "flex-row" : "flex-col"} h-full w-full overflow-hidden ${className}`,
|
|
2198
|
+
children: [
|
|
2199
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { style: firstStyle, className: "overflow-hidden", children: first }),
|
|
2200
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
2201
|
+
"div",
|
|
2202
|
+
{
|
|
2203
|
+
className: `shrink-0 ${isHorizontal ? "w-px cursor-col-resize hover:w-0.5 hover:bg-blue-700/50 active:w-0.5 active:bg-blue-700" : "h-px cursor-row-resize hover:h-0.5 hover:bg-blue-700/50 active:h-0.5 active:bg-blue-700"} bg-gray-alpha-200 transition-colors`,
|
|
2204
|
+
onPointerDown,
|
|
2205
|
+
onPointerMove,
|
|
2206
|
+
onPointerUp,
|
|
2207
|
+
role: "separator",
|
|
2208
|
+
"aria-orientation": isHorizontal ? "vertical" : "horizontal",
|
|
2209
|
+
tabIndex: 0
|
|
2210
|
+
}
|
|
2211
|
+
),
|
|
2212
|
+
/* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "flex-1 overflow-hidden", children: second })
|
|
2213
|
+
]
|
|
2214
|
+
}
|
|
2215
|
+
);
|
|
2216
|
+
}
|
|
2217
|
+
function Panel({ children, className = "" }) {
|
|
2218
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: `h-full w-full overflow-auto ${className}`, children });
|
|
2219
|
+
}
|
|
2220
|
+
var SplitPane = Object.assign(SplitPaneRoot, {
|
|
2221
|
+
Panel
|
|
2222
|
+
});
|
|
2223
|
+
|
|
2224
|
+
// src/primitives/status-badge.tsx
|
|
2225
|
+
var import_jsx_runtime36 = require("react/jsx-runtime");
|
|
2226
|
+
function StatusBadge({ status }) {
|
|
2227
|
+
const variant = status === "active" ? "green" : status === "creating" ? "amber" : status === "error" ? "red" : "gray";
|
|
2228
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Badge, { variant, size: "sm", contrast: "low", children: status });
|
|
2229
|
+
}
|
|
2230
|
+
|
|
2231
|
+
// src/primitives/status-bar.tsx
|
|
2232
|
+
var import_jsx_runtime37 = require("react/jsx-runtime");
|
|
2233
|
+
function StatusBarRoot({ children, className = "" }) {
|
|
2234
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
2235
|
+
"div",
|
|
2236
|
+
{
|
|
2237
|
+
className: `flex h-6 shrink-0 items-center gap-0 border-t border-gray-alpha-200 bg-background-100 px-2 font-mono text-label-13 text-gray-900 ${className}`,
|
|
2238
|
+
role: "status",
|
|
2239
|
+
children
|
|
2240
|
+
}
|
|
2241
|
+
);
|
|
2242
|
+
}
|
|
2243
|
+
var variantColors = {
|
|
2244
|
+
default: "text-gray-900",
|
|
2245
|
+
success: "text-green-900",
|
|
2246
|
+
warning: "text-amber-900",
|
|
2247
|
+
error: "text-red-900"
|
|
2248
|
+
};
|
|
2249
|
+
function StatusBarItem({ children, icon, variant = "default", onClick, className = "" }) {
|
|
2250
|
+
const classes = `inline-flex items-center gap-1 px-1.5 py-0.5 rounded-sm ${variantColors[variant]} ${onClick ? "cursor-pointer hover:bg-gray-alpha-200 transition-colors" : ""} ${className}`;
|
|
2251
|
+
if (onClick) {
|
|
2252
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("button", { className: classes, onClick, children: [
|
|
2253
|
+
icon,
|
|
2254
|
+
children
|
|
2255
|
+
] });
|
|
2256
|
+
}
|
|
2257
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { className: classes, children: [
|
|
2258
|
+
icon,
|
|
2259
|
+
children
|
|
2260
|
+
] });
|
|
2261
|
+
}
|
|
2262
|
+
function StatusBarSeparator() {
|
|
2263
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(Separator3, { orientation: "vertical", className: "mx-0.5 h-3" });
|
|
2264
|
+
}
|
|
2265
|
+
function StatusBarSpacer() {
|
|
2266
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "flex-1" });
|
|
2267
|
+
}
|
|
2268
|
+
var StatusBar = Object.assign(StatusBarRoot, {
|
|
2269
|
+
Item: StatusBarItem,
|
|
2270
|
+
Separator: StatusBarSeparator,
|
|
2271
|
+
Spacer: StatusBarSpacer
|
|
2272
|
+
});
|
|
2273
|
+
|
|
2274
|
+
// src/primitives/toolbar.tsx
|
|
2275
|
+
var import_react14 = require("react");
|
|
2276
|
+
var import_jsx_runtime38 = require("react/jsx-runtime");
|
|
2277
|
+
function ToolbarRoot({ children, className = "" }) {
|
|
2278
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
2279
|
+
"div",
|
|
2280
|
+
{
|
|
2281
|
+
className: `flex h-9 shrink-0 items-center gap-0.5 border-b border-gray-alpha-200 bg-background-100 px-1.5 ${className}`,
|
|
2282
|
+
role: "toolbar",
|
|
2283
|
+
children
|
|
2284
|
+
}
|
|
2285
|
+
);
|
|
2286
|
+
}
|
|
2287
|
+
var ToolbarButton = (0, import_react14.forwardRef)(function ToolbarButton2({ tooltip, active, children, className = "", disabled, ...props }, ref) {
|
|
2288
|
+
const btn = /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
2289
|
+
"button",
|
|
2290
|
+
{
|
|
2291
|
+
ref,
|
|
2292
|
+
disabled,
|
|
2293
|
+
className: `inline-flex h-7 w-7 items-center justify-center rounded-md text-gray-900 transition-colors [&>svg]:h-3.5 [&>svg]:w-3.5
|
|
2294
|
+
hover:bg-gray-alpha-200 hover:text-gray-1000
|
|
2295
|
+
disabled:pointer-events-none disabled:opacity-40
|
|
2296
|
+
${active ? "bg-gray-alpha-200 text-gray-1000" : ""}
|
|
2297
|
+
${className}`,
|
|
2298
|
+
...props,
|
|
2299
|
+
children
|
|
2300
|
+
}
|
|
2301
|
+
);
|
|
2302
|
+
if (tooltip) {
|
|
2303
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Tooltip, { text: tooltip, desktopOnly: true, children: btn });
|
|
2304
|
+
}
|
|
2305
|
+
return btn;
|
|
2306
|
+
});
|
|
2307
|
+
function ToolbarGroup({ children, className = "" }) {
|
|
2308
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: `flex items-center gap-px ${className}`, children });
|
|
2309
|
+
}
|
|
2310
|
+
function ToolbarSeparator() {
|
|
2311
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Separator3, { orientation: "vertical", className: "mx-1 h-4" });
|
|
2312
|
+
}
|
|
2313
|
+
function ToolbarSpacer() {
|
|
2314
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "flex-1" });
|
|
2315
|
+
}
|
|
2316
|
+
function ToolbarText({ children, className = "" }) {
|
|
2317
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: `px-1.5 text-label-13 text-gray-900 ${className}`, children });
|
|
2318
|
+
}
|
|
2319
|
+
function ToolbarInput({
|
|
2320
|
+
value,
|
|
2321
|
+
onChange,
|
|
2322
|
+
placeholder,
|
|
2323
|
+
className = "",
|
|
2324
|
+
readOnly
|
|
2325
|
+
}) {
|
|
2326
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
2327
|
+
"input",
|
|
2328
|
+
{
|
|
2329
|
+
type: "text",
|
|
2330
|
+
value,
|
|
2331
|
+
onChange,
|
|
2332
|
+
placeholder,
|
|
2333
|
+
readOnly,
|
|
2334
|
+
className: `h-6 flex-1 rounded-md border border-gray-alpha-200 bg-gray-alpha-100 px-2 font-mono text-label-13 text-gray-1000 placeholder:text-gray-700 outline-none transition-colors focus:border-blue-700 ${className}`
|
|
2335
|
+
}
|
|
2336
|
+
);
|
|
2337
|
+
}
|
|
2338
|
+
var Toolbar = Object.assign(ToolbarRoot, {
|
|
2339
|
+
Button: ToolbarButton,
|
|
2340
|
+
Group: ToolbarGroup,
|
|
2341
|
+
Separator: ToolbarSeparator,
|
|
2342
|
+
Spacer: ToolbarSpacer,
|
|
2343
|
+
Text: ToolbarText,
|
|
2344
|
+
Input: ToolbarInput
|
|
2345
|
+
});
|
|
2346
|
+
|
|
2347
|
+
// src/stores/notification-store.ts
|
|
2348
|
+
var import_zustand2 = require("zustand");
|
|
2349
|
+
var MAX_VISIBLE = 5;
|
|
2350
|
+
var MAX_HISTORY = 50;
|
|
2351
|
+
var PREFS_KEY = "khal_os_notification_prefs";
|
|
2352
|
+
function loadPrefs() {
|
|
2353
|
+
if (typeof window === "undefined") return { doNotDisturb: false, desktopNotifMode: "background" };
|
|
2354
|
+
try {
|
|
2355
|
+
const raw = localStorage.getItem(PREFS_KEY);
|
|
2356
|
+
if (raw) return JSON.parse(raw);
|
|
2357
|
+
} catch {
|
|
2358
|
+
}
|
|
2359
|
+
return { doNotDisturb: false, desktopNotifMode: "background" };
|
|
2360
|
+
}
|
|
2361
|
+
function savePrefs(prefs) {
|
|
2362
|
+
try {
|
|
2363
|
+
localStorage.setItem(PREFS_KEY, JSON.stringify(prefs));
|
|
2364
|
+
} catch {
|
|
2365
|
+
}
|
|
2366
|
+
}
|
|
2367
|
+
function getBrowserPermission() {
|
|
2368
|
+
if (typeof window === "undefined" || !("Notification" in window)) return "denied";
|
|
2369
|
+
return Notification.permission;
|
|
2370
|
+
}
|
|
2371
|
+
function sendBrowserNotification(notif) {
|
|
2372
|
+
if (typeof window === "undefined" || !("Notification" in window) || Notification.permission !== "granted") return;
|
|
2373
|
+
const n = new Notification(notif.summary, {
|
|
2374
|
+
body: notif.body || void 0,
|
|
2375
|
+
icon: notif.icon || void 0,
|
|
2376
|
+
tag: String(notif.id),
|
|
2377
|
+
silent: notif.urgency === "low"
|
|
2378
|
+
});
|
|
2379
|
+
n.onclick = () => {
|
|
2380
|
+
window.focus();
|
|
2381
|
+
n.close();
|
|
2382
|
+
};
|
|
2383
|
+
if (notif.expires > 0) {
|
|
2384
|
+
setTimeout(() => n.close(), notif.expires);
|
|
2385
|
+
} else if (notif.urgency !== "critical") {
|
|
2386
|
+
setTimeout(() => n.close(), 6e3);
|
|
2387
|
+
}
|
|
2388
|
+
}
|
|
2389
|
+
var initialPrefs = loadPrefs();
|
|
2390
|
+
var useNotificationStore = (0, import_zustand2.create)()((set, get) => ({
|
|
2391
|
+
notifications: [],
|
|
2392
|
+
history: [],
|
|
2393
|
+
trayIcons: /* @__PURE__ */ new Map(),
|
|
2394
|
+
centerOpen: false,
|
|
2395
|
+
unreadCount: 0,
|
|
2396
|
+
doNotDisturb: initialPrefs.doNotDisturb,
|
|
2397
|
+
desktopNotifMode: initialPrefs.desktopNotifMode,
|
|
2398
|
+
browserPermission: getBrowserPermission(),
|
|
2399
|
+
setDoNotDisturb: (value) => {
|
|
2400
|
+
set({ doNotDisturb: value });
|
|
2401
|
+
savePrefs({ doNotDisturb: value, desktopNotifMode: get().desktopNotifMode });
|
|
2402
|
+
},
|
|
2403
|
+
setDesktopNotifMode: (mode) => {
|
|
2404
|
+
set({ desktopNotifMode: mode });
|
|
2405
|
+
savePrefs({ doNotDisturb: get().doNotDisturb, desktopNotifMode: mode });
|
|
2406
|
+
},
|
|
2407
|
+
requestBrowserPermission: async () => {
|
|
2408
|
+
if (typeof window === "undefined" || !("Notification" in window)) return "denied";
|
|
2409
|
+
const result = await Notification.requestPermission();
|
|
2410
|
+
set({ browserPermission: result });
|
|
2411
|
+
return result;
|
|
2412
|
+
},
|
|
2413
|
+
syncBrowserPermission: () => {
|
|
2414
|
+
set({ browserPermission: getBrowserPermission() });
|
|
2415
|
+
},
|
|
2416
|
+
addNotification: (notification) => {
|
|
2417
|
+
const full = {
|
|
2418
|
+
...notification,
|
|
2419
|
+
appName: notification.appName ?? "",
|
|
2420
|
+
urgency: notification.urgency ?? "normal",
|
|
2421
|
+
category: notification.category ?? null,
|
|
2422
|
+
transient: notification.transient ?? false,
|
|
2423
|
+
workspaceId: notification.workspaceId ?? null,
|
|
2424
|
+
timestamp: Date.now(),
|
|
2425
|
+
read: false
|
|
2426
|
+
};
|
|
2427
|
+
const { doNotDisturb, desktopNotifMode, browserPermission } = get();
|
|
2428
|
+
set((state) => {
|
|
2429
|
+
const history = full.transient ? state.history : [full, ...state.history].slice(0, MAX_HISTORY);
|
|
2430
|
+
if (doNotDisturb && full.urgency !== "critical") {
|
|
2431
|
+
return {
|
|
2432
|
+
history,
|
|
2433
|
+
unreadCount: full.transient ? state.unreadCount : state.unreadCount + 1
|
|
2434
|
+
};
|
|
2435
|
+
}
|
|
2436
|
+
let notifications = [...state.notifications];
|
|
2437
|
+
if (notification.replacesId) {
|
|
2438
|
+
notifications = notifications.filter((n) => n.id !== notification.replacesId);
|
|
2439
|
+
}
|
|
2440
|
+
notifications = [full, ...notifications].slice(0, MAX_VISIBLE);
|
|
2441
|
+
return {
|
|
2442
|
+
notifications,
|
|
2443
|
+
history,
|
|
2444
|
+
unreadCount: full.transient ? state.unreadCount : state.unreadCount + 1
|
|
2445
|
+
};
|
|
2446
|
+
});
|
|
2447
|
+
if (browserPermission === "granted" && desktopNotifMode !== "off" && !full.transient) {
|
|
2448
|
+
const shouldSend = desktopNotifMode === "always" || desktopNotifMode === "background" && document.hidden;
|
|
2449
|
+
if (shouldSend) {
|
|
2450
|
+
sendBrowserNotification(full);
|
|
2451
|
+
}
|
|
2452
|
+
}
|
|
2453
|
+
const isCritical = full.urgency === "critical";
|
|
2454
|
+
if (full.expires > 0) {
|
|
2455
|
+
setTimeout(() => {
|
|
2456
|
+
get().hideNotification(full.id);
|
|
2457
|
+
}, full.expires);
|
|
2458
|
+
} else if (!isCritical) {
|
|
2459
|
+
setTimeout(() => {
|
|
2460
|
+
get().hideNotification(full.id);
|
|
2461
|
+
}, 6e3);
|
|
2462
|
+
}
|
|
2463
|
+
},
|
|
2464
|
+
dismissNotification: (id) => {
|
|
2465
|
+
set((state) => ({
|
|
2466
|
+
notifications: state.notifications.filter((n) => n.id !== id)
|
|
2467
|
+
}));
|
|
2468
|
+
},
|
|
2469
|
+
hideNotification: (id) => {
|
|
2470
|
+
set((state) => ({
|
|
2471
|
+
notifications: state.notifications.filter((n) => n.id !== id)
|
|
2472
|
+
}));
|
|
2473
|
+
},
|
|
2474
|
+
clearHistory: () => {
|
|
2475
|
+
set({ history: [], unreadCount: 0 });
|
|
2476
|
+
},
|
|
2477
|
+
markAllRead: () => {
|
|
2478
|
+
set((state) => ({
|
|
2479
|
+
history: state.history.map((n) => ({ ...n, read: true })),
|
|
2480
|
+
unreadCount: 0
|
|
2481
|
+
}));
|
|
2482
|
+
},
|
|
2483
|
+
toggleCenter: () => {
|
|
2484
|
+
const opening = !get().centerOpen;
|
|
2485
|
+
set({ centerOpen: opening });
|
|
2486
|
+
if (opening) {
|
|
2487
|
+
get().markAllRead();
|
|
2488
|
+
}
|
|
2489
|
+
},
|
|
2490
|
+
closeCenter: () => {
|
|
2491
|
+
set({ centerOpen: false });
|
|
2492
|
+
},
|
|
2493
|
+
addTrayIcon: (icon) => {
|
|
2494
|
+
set((state) => {
|
|
2495
|
+
const next = new Map(state.trayIcons);
|
|
2496
|
+
next.set(icon.wid, icon);
|
|
2497
|
+
return { trayIcons: next };
|
|
2498
|
+
});
|
|
2499
|
+
},
|
|
2500
|
+
removeTrayIcon: (wid) => {
|
|
2501
|
+
set((state) => {
|
|
2502
|
+
const next = new Map(state.trayIcons);
|
|
2503
|
+
next.delete(wid);
|
|
2504
|
+
return { trayIcons: next };
|
|
2505
|
+
});
|
|
2506
|
+
},
|
|
2507
|
+
updateTrayIcon: (wid, updates) => {
|
|
2508
|
+
set((state) => {
|
|
2509
|
+
const next = new Map(state.trayIcons);
|
|
2510
|
+
const existing = next.get(wid);
|
|
2511
|
+
if (existing) {
|
|
2512
|
+
next.set(wid, { ...existing, ...updates });
|
|
2513
|
+
}
|
|
2514
|
+
return { trayIcons: next };
|
|
2515
|
+
});
|
|
2516
|
+
}
|
|
2517
|
+
}));
|
|
2518
|
+
|
|
2519
|
+
// src/tokens/lp-tokens.ts
|
|
2520
|
+
var WIN_BG = "#111318";
|
|
2521
|
+
var CHROME_BG = "#0D0F14";
|
|
2522
|
+
var CELL_BG = "#0D1017";
|
|
2523
|
+
var WIN_BORDER = "#1E2330";
|
|
2524
|
+
var WIN_BORDER_FOCUSED = "#333D55";
|
|
2525
|
+
var TEXT_PRIMARY = "#E8EAF0";
|
|
2526
|
+
var TEXT_SECONDARY = "#8B92A5";
|
|
2527
|
+
var TEXT_TERTIARY = "#555D73";
|
|
2528
|
+
var ACCENT_BLUE = "#0A6FE0";
|
|
2529
|
+
var MESH_GRADIENT_PALETTE = [
|
|
2530
|
+
"#030508",
|
|
2531
|
+
"#070D15",
|
|
2532
|
+
"#0C1A2E",
|
|
2533
|
+
"#1A4A7A",
|
|
2534
|
+
"#2A3040",
|
|
2535
|
+
"#5C4A38",
|
|
2536
|
+
"#8B6B42",
|
|
2537
|
+
"#D49355"
|
|
2538
|
+
];
|
|
2539
|
+
var WINDOW_RADIUS = "12px";
|
|
2540
|
+
var BUTTON_RADIUS = "10px";
|
|
2541
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
2542
|
+
0 && (module.exports = {
|
|
2543
|
+
ACCENT_BLUE,
|
|
2544
|
+
Avatar,
|
|
2545
|
+
BUTTON_RADIUS,
|
|
2546
|
+
Badge,
|
|
2547
|
+
Button,
|
|
2548
|
+
CELL_BG,
|
|
2549
|
+
CHROME_BG,
|
|
2550
|
+
CollapsibleSidebar,
|
|
2551
|
+
Command,
|
|
2552
|
+
CommandDialog,
|
|
2553
|
+
CommandEmpty,
|
|
2554
|
+
CommandGroup,
|
|
2555
|
+
CommandInput,
|
|
2556
|
+
CommandItem,
|
|
2557
|
+
CommandList,
|
|
2558
|
+
CommandSeparator,
|
|
2559
|
+
CommandShortcut,
|
|
2560
|
+
ContextMenu,
|
|
2561
|
+
ContextMenuContent,
|
|
2562
|
+
ContextMenuGroup,
|
|
2563
|
+
ContextMenuItem,
|
|
2564
|
+
ContextMenuPortal,
|
|
2565
|
+
ContextMenuRadioGroup,
|
|
2566
|
+
ContextMenuSeparator,
|
|
2567
|
+
ContextMenuSub,
|
|
2568
|
+
ContextMenuSubContent,
|
|
2569
|
+
ContextMenuSubTrigger,
|
|
2570
|
+
ContextMenuTrigger,
|
|
2571
|
+
CostCounter,
|
|
2572
|
+
DataRow,
|
|
2573
|
+
Dialog,
|
|
2574
|
+
DropdownMenu,
|
|
2575
|
+
DropdownMenuCheckboxItem,
|
|
2576
|
+
DropdownMenuContent,
|
|
2577
|
+
DropdownMenuGroup,
|
|
2578
|
+
DropdownMenuItem,
|
|
2579
|
+
DropdownMenuLabel,
|
|
2580
|
+
DropdownMenuPortal,
|
|
2581
|
+
DropdownMenuRadioGroup,
|
|
2582
|
+
DropdownMenuRadioItem,
|
|
2583
|
+
DropdownMenuSeparator,
|
|
2584
|
+
DropdownMenuShortcut,
|
|
2585
|
+
DropdownMenuSub,
|
|
2586
|
+
DropdownMenuSubContent,
|
|
2587
|
+
DropdownMenuSubTrigger,
|
|
2588
|
+
DropdownMenuTrigger,
|
|
2589
|
+
EmptyState,
|
|
2590
|
+
GlassCard,
|
|
2591
|
+
Input,
|
|
2592
|
+
KhalLogo,
|
|
2593
|
+
ListView,
|
|
2594
|
+
LiveFeed,
|
|
2595
|
+
MESH_GRADIENT_PALETTE,
|
|
2596
|
+
MeshGradient,
|
|
2597
|
+
MetricDisplay,
|
|
2598
|
+
Note,
|
|
2599
|
+
NumberFlow,
|
|
2600
|
+
PillBadge,
|
|
2601
|
+
ProgressBar,
|
|
2602
|
+
PropertyPanel,
|
|
2603
|
+
SUBJECTS,
|
|
2604
|
+
SectionCard,
|
|
2605
|
+
SectionCardHeader,
|
|
2606
|
+
SectionHeader,
|
|
2607
|
+
Separator,
|
|
2608
|
+
SidebarNav,
|
|
2609
|
+
Spinner,
|
|
2610
|
+
SplitPane,
|
|
2611
|
+
StatusBadge,
|
|
2612
|
+
StatusBar,
|
|
2613
|
+
StatusDot,
|
|
2614
|
+
TEXT_PRIMARY,
|
|
2615
|
+
TEXT_SECONDARY,
|
|
2616
|
+
TEXT_TERTIARY,
|
|
2617
|
+
ThemeProvider,
|
|
2618
|
+
ThemeSwitcher,
|
|
2619
|
+
TickerBar,
|
|
2620
|
+
Toggle,
|
|
2621
|
+
Toolbar,
|
|
2622
|
+
Tooltip,
|
|
2623
|
+
TooltipContent,
|
|
2624
|
+
TooltipProvider,
|
|
2625
|
+
TooltipRoot,
|
|
2626
|
+
TooltipTrigger,
|
|
2627
|
+
WINDOW_RADIUS,
|
|
2628
|
+
WIN_BG,
|
|
2629
|
+
WIN_BORDER,
|
|
2630
|
+
WIN_BORDER_FOCUSED,
|
|
2631
|
+
WindowActiveProvider,
|
|
2632
|
+
WindowMinimizedProvider,
|
|
2633
|
+
badgeVariants,
|
|
2634
|
+
buttonVariants,
|
|
2635
|
+
cn,
|
|
2636
|
+
dataRowVariants,
|
|
2637
|
+
fadeIn,
|
|
2638
|
+
fadeUp,
|
|
2639
|
+
glassCardVariants,
|
|
2640
|
+
khalEasing,
|
|
2641
|
+
metricDisplayVariants,
|
|
2642
|
+
pillBadgeVariants,
|
|
2643
|
+
progressBarVariants,
|
|
2644
|
+
scaleUp,
|
|
2645
|
+
sectionCardVariants,
|
|
2646
|
+
springConfig,
|
|
2647
|
+
staggerChild,
|
|
2648
|
+
staggerContainer,
|
|
2649
|
+
stateConfig,
|
|
2650
|
+
useKhalAuth,
|
|
2651
|
+
useNats,
|
|
2652
|
+
useNatsSubscription,
|
|
2653
|
+
useNotificationStore,
|
|
2654
|
+
useOSAuth,
|
|
2655
|
+
useReducedMotion,
|
|
2656
|
+
useSidebar,
|
|
2657
|
+
useThemeStore,
|
|
2658
|
+
useWindowActive,
|
|
2659
|
+
useWindowMinimized
|
|
2660
|
+
});
|
|
2661
|
+
//# sourceMappingURL=index.cjs.map
|