@arbidocs/blocks 0.3.119 → 0.3.120
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/dist/chunk-AHWIZJ4M.cjs +1540 -0
- package/dist/chunk-AHWIZJ4M.cjs.map +1 -0
- package/dist/chunk-L6GG4KN2.js +1480 -0
- package/dist/chunk-L6GG4KN2.js.map +1 -0
- package/dist/index.cjs +638 -1560
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +123 -591
- package/dist/index.d.ts +123 -591
- package/dist/index.js +403 -1533
- package/dist/index.js.map +1 -1
- package/dist/record/index.cjs +178 -0
- package/dist/record/index.cjs.map +1 -0
- package/dist/record/index.d.cts +96 -0
- package/dist/record/index.d.ts +96 -0
- package/dist/record/index.js +176 -0
- package/dist/record/index.js.map +1 -0
- package/dist/site/index.cjs +216 -0
- package/dist/site/index.cjs.map +1 -0
- package/dist/site/index.d.cts +688 -0
- package/dist/site/index.d.ts +688 -0
- package/dist/site/index.js +3 -0
- package/dist/site/index.js.map +1 -0
- package/package.json +20 -3
package/dist/index.js
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import { createContext, useState,
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
1
|
+
import { tid, initials, fromNow, fmtDate, assetRefId, applyStoredTheme, AssetResolverProvider, ThemeEditor, applyThemeVars, SectionHeading, PricingTable, Tabs as Tabs$1, Accordion, Gallery, VideoEmbed, ContactForm, Banner, MediaText, TeamGrid, Steps, TestimonialGrid, Columns, Spacer, Container, Hero, FeatureGrid, Testimonial, CTABanner, LogoCloud, FAQ, RichTextBlock, Callout, BlockImage, AvatarBlock, Navbar, Footer, ListBlock, isAssetRef, asAssetRef } from './chunk-L6GG4KN2.js';
|
|
2
|
+
export { ASSET_REF_PREFIX, Accordion, AssetResolverProvider, AvatarBlock, Banner, BlockImage, BlockLink, CTABanner, Callout, Columns, ContactForm, Container, FAQ, FONT_PAIRINGS, FeatureGrid, Footer, Gallery, Hero, ListBlock, LogoCloud, MediaText, Navbar, PricingTable, RichTextBlock, SectionHeading, Spacer, Steps, THEME_STYLE_ID, Tabs, TeamGrid, Testimonial, TestimonialGrid, ThemeEditor, VideoEmbed, applyFontVars, applyStoredTheme, applyThemeVars, asAssetRef, assetRefId, clearFontVars, clearThemeVars, createThemeStore, daysUntil, fmtDate, fmtDateTime, fontPackages, fromNow, gbp, getFontPairing, hrs, initials, isAssetRef, matchFontPairing, pct, tid, toEmbedUrl, toHslTriplet, useAssetRenderer, useAssetResolverActive } from './chunk-L6GG4KN2.js';
|
|
3
|
+
import { createContext, useState, useCallback, useMemo, useContext, useRef, useEffect } from 'react';
|
|
4
|
+
import { useArbi, ArbiProvider, useAiTask, useWorkspaceDocs as useWorkspaceDocs$1, useSemanticSearch as useSemanticSearch$1, cn, Table, TableHeader, TableRow, TableHead, TableBody, TableCell, Input, Card, CardHeader, Badge, CardTitle, CardDescription, CardContent, Avatar, AvatarImage, AvatarFallback, CardFooter, Button, TooltipProvider, NotificationBell, UserMenu, useThumbnails, Switch, useConfigs, useAgents, Checkbox, Tabs, TabsList, TabsTrigger, TabsContent, Separator, ArbiWebSocketProvider, useDocuments, ImageCropModal, DEFAULT_ASPECT_OPTIONS, useConversations } from '@arbidocs/react';
|
|
5
|
+
export { DocumentCard, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, redlineStats, textToArtifact, toRedlineMarkdown } from '@arbidocs/react';
|
|
6
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
8
7
|
import { QueryClient, QueryClientProvider, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
9
8
|
import { AgGridReact } from 'ag-grid-react';
|
|
10
9
|
import { themeQuartz, AllCommunityModule } from 'ag-grid-community';
|
|
10
|
+
import { MessageSquare, Cpu, Code, Cloud, Layers, Target, Award, MapPin, Phone, Mail, Lock, Globe, Heart, Star, Rocket, Shield, Zap, Sparkles, Gavel, Scale, Bell, Activity, BarChart3, DollarSign, TrendingUp, Info, AlertCircle, CheckCircle, Clock, Calendar, Briefcase, Users, Folder, FileText, Loader2, UploadCloud, Search, ArrowUpRight, ArrowDownRight, FolderLock, CheckCircle2, ArrowLeftRight, X, Menu, ArrowLeft, Palette, RotateCcw, ChevronUp, ChevronDown, BrainCircuit, Bot, LayoutGrid, FileJson, Download, Crop, ImagePlus, Upload, Link2, MessagesSquare } from 'lucide-react';
|
|
11
11
|
import { useLocation, Link, useParams, NavLink } from 'react-router-dom';
|
|
12
12
|
import { Puck, Render } from '@measured/puck';
|
|
13
|
+
import { create } from 'zustand';
|
|
14
|
+
import { persist } from 'zustand/middleware';
|
|
13
15
|
|
|
14
16
|
// src/prompts.ts
|
|
15
17
|
function matterToContext(m) {
|
|
@@ -192,380 +194,23 @@ Lead with why the firm is the right choice, reference relevant experience at a t
|
|
|
192
194
|
];
|
|
193
195
|
return { prompts, WORKFLOW_ACTIONS };
|
|
194
196
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
var
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
if (hex.length === 3) {
|
|
203
|
-
hex = hex.split("").map((ch) => ch + ch).join("");
|
|
204
|
-
}
|
|
205
|
-
if (hex.length === 6 && /^[0-9a-fA-F]{6}$/.test(hex)) {
|
|
206
|
-
return {
|
|
207
|
-
r: parseInt(hex.slice(0, 2), 16),
|
|
208
|
-
g: parseInt(hex.slice(2, 4), 16),
|
|
209
|
-
b: parseInt(hex.slice(4, 6), 16)
|
|
210
|
-
};
|
|
211
|
-
}
|
|
197
|
+
var ConnectionContext = createContext(null);
|
|
198
|
+
var WORKSPACE_STORAGE_PREFIX = "arbi:selectedWorkspace";
|
|
199
|
+
var workspaceStorageKey = (apiUrl) => `${WORKSPACE_STORAGE_PREFIX}:${apiUrl || "demo"}`;
|
|
200
|
+
function readPersistedWorkspace(apiUrl) {
|
|
201
|
+
try {
|
|
202
|
+
return window.localStorage.getItem(workspaceStorageKey(apiUrl));
|
|
203
|
+
} catch {
|
|
212
204
|
return null;
|
|
213
205
|
}
|
|
214
|
-
const m = color.match(/^rgba?\(\s*([\d.]+)[\s,]+([\d.]+)[\s,]+([\d.]+)/i);
|
|
215
|
-
if (m) return { r: Number(m[1]), g: Number(m[2]), b: Number(m[3]) };
|
|
216
|
-
return null;
|
|
217
|
-
}
|
|
218
|
-
function rgbToHslTriplet(r, g, b) {
|
|
219
|
-
const rn = r / 255;
|
|
220
|
-
const gn = g / 255;
|
|
221
|
-
const bn = b / 255;
|
|
222
|
-
const max = Math.max(rn, gn, bn);
|
|
223
|
-
const min = Math.min(rn, gn, bn);
|
|
224
|
-
const l = (max + min) / 2;
|
|
225
|
-
const d = max - min;
|
|
226
|
-
let h = 0;
|
|
227
|
-
let s = 0;
|
|
228
|
-
if (d !== 0) {
|
|
229
|
-
s = d / (1 - Math.abs(2 * l - 1));
|
|
230
|
-
switch (max) {
|
|
231
|
-
case rn:
|
|
232
|
-
h = 60 * ((gn - bn) / d % 6);
|
|
233
|
-
break;
|
|
234
|
-
case gn:
|
|
235
|
-
h = 60 * ((bn - rn) / d + 2);
|
|
236
|
-
break;
|
|
237
|
-
default:
|
|
238
|
-
h = 60 * ((rn - gn) / d + 4);
|
|
239
|
-
break;
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
if (h < 0) h += 360;
|
|
243
|
-
return `${Math.round(h)} ${Math.round(s * 100)}% ${Math.round(l * 100)}%`;
|
|
244
|
-
}
|
|
245
|
-
function toHslTriplet(color) {
|
|
246
|
-
const c = color.trim();
|
|
247
|
-
if (TRIPLET_RE.test(c)) return c;
|
|
248
|
-
const rgb = parseRgb(c);
|
|
249
|
-
if (!rgb) return c;
|
|
250
|
-
return rgbToHslTriplet(rgb.r, rgb.g, rgb.b);
|
|
251
|
-
}
|
|
252
|
-
function renderTripletBlock(colors) {
|
|
253
|
-
return Object.entries(colors).map(([key, value]) => ` --${key}: ${toHslTriplet(value)};`).join("\n");
|
|
254
|
-
}
|
|
255
|
-
function emitCssVars(theme, dark) {
|
|
256
|
-
if (typeof document === "undefined") return;
|
|
257
|
-
const meta = [
|
|
258
|
-
` --font-display: ${theme.fonts.display};`,
|
|
259
|
-
` --font-sans: ${theme.fonts.sans};`,
|
|
260
|
-
` --radius: ${theme.radius}rem;`
|
|
261
|
-
].join("\n");
|
|
262
|
-
let css = `:root {
|
|
263
|
-
${renderTripletBlock(theme.colors)}
|
|
264
|
-
${meta}
|
|
265
|
-
}`;
|
|
266
|
-
if (dark) {
|
|
267
|
-
css += `
|
|
268
|
-
:root.dark {
|
|
269
|
-
${renderTripletBlock(dark)}
|
|
270
|
-
}`;
|
|
271
|
-
}
|
|
272
|
-
let style = document.getElementById(THEME_STYLE_ID);
|
|
273
|
-
if (!style) {
|
|
274
|
-
style = document.createElement("style");
|
|
275
|
-
style.id = THEME_STYLE_ID;
|
|
276
|
-
document.head.appendChild(style);
|
|
277
|
-
}
|
|
278
|
-
style.textContent = css;
|
|
279
|
-
}
|
|
280
|
-
function removeCssVars() {
|
|
281
|
-
if (typeof document === "undefined") return;
|
|
282
|
-
document.getElementById(THEME_STYLE_ID)?.remove();
|
|
283
|
-
}
|
|
284
|
-
function normalizeOptions(optionsOrRoot) {
|
|
285
|
-
if (typeof HTMLElement !== "undefined" && optionsOrRoot instanceof HTMLElement) {
|
|
286
|
-
return { root: optionsOrRoot };
|
|
287
|
-
}
|
|
288
|
-
return optionsOrRoot;
|
|
289
|
-
}
|
|
290
|
-
function applyThemeVars(theme, optionsOrRoot = {}) {
|
|
291
|
-
const { mode = "flat", dark, root = document.documentElement } = normalizeOptions(optionsOrRoot);
|
|
292
|
-
if (mode === "cssVars") {
|
|
293
|
-
emitCssVars(theme, dark);
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
for (const [key, value] of Object.entries(theme.colors)) {
|
|
297
|
-
root.style.setProperty(`--color-${key}`, value);
|
|
298
|
-
}
|
|
299
|
-
root.style.setProperty("--font-display", theme.fonts.display);
|
|
300
|
-
root.style.setProperty("--font-sans", theme.fonts.sans);
|
|
301
|
-
root.style.setProperty("--radius", `${theme.radius}rem`);
|
|
302
|
-
}
|
|
303
|
-
function clearThemeVars(theme, optionsOrRoot = {}) {
|
|
304
|
-
const { mode = "flat", root = document.documentElement } = normalizeOptions(optionsOrRoot);
|
|
305
|
-
if (mode === "cssVars") {
|
|
306
|
-
removeCssVars();
|
|
307
|
-
return;
|
|
308
|
-
}
|
|
309
|
-
for (const key of Object.keys(theme.colors)) {
|
|
310
|
-
root.style.removeProperty(`--color-${key}`);
|
|
311
|
-
}
|
|
312
|
-
root.style.removeProperty("--font-display");
|
|
313
|
-
root.style.removeProperty("--font-sans");
|
|
314
|
-
root.style.removeProperty("--radius");
|
|
315
|
-
}
|
|
316
|
-
function createThemeStore(config) {
|
|
317
|
-
const { defaultTheme, presets, storageKey } = config;
|
|
318
|
-
const useStore = create()(
|
|
319
|
-
persist(
|
|
320
|
-
(set, get) => ({
|
|
321
|
-
...defaultTheme,
|
|
322
|
-
activePresetId: presets[0]?.id ?? null,
|
|
323
|
-
setColor: (key, value) => set((s) => ({ colors: { ...s.colors, [key]: value }, activePresetId: null })),
|
|
324
|
-
setFont: (which, value) => set((s) => ({ fonts: { ...s.fonts, [which]: value }, activePresetId: null })),
|
|
325
|
-
setRadius: (radius) => set({ radius, activePresetId: null }),
|
|
326
|
-
applyPreset: (presetId) => {
|
|
327
|
-
const preset = presets.find((p) => p.id === presetId);
|
|
328
|
-
if (!preset) return;
|
|
329
|
-
set({
|
|
330
|
-
colors: { ...preset.tokens.colors },
|
|
331
|
-
fonts: { ...preset.tokens.fonts },
|
|
332
|
-
radius: preset.tokens.radius,
|
|
333
|
-
activePresetId: presetId
|
|
334
|
-
});
|
|
335
|
-
},
|
|
336
|
-
reset: () => set({
|
|
337
|
-
colors: { ...defaultTheme.colors },
|
|
338
|
-
fonts: { ...defaultTheme.fonts },
|
|
339
|
-
radius: defaultTheme.radius,
|
|
340
|
-
activePresetId: presets[0]?.id ?? null
|
|
341
|
-
}),
|
|
342
|
-
snapshot: () => {
|
|
343
|
-
const { colors, fonts, radius } = get();
|
|
344
|
-
return { colors, fonts, radius };
|
|
345
|
-
}
|
|
346
|
-
}),
|
|
347
|
-
{ name: storageKey }
|
|
348
|
-
)
|
|
349
|
-
);
|
|
350
|
-
return { ...config, useStore };
|
|
351
|
-
}
|
|
352
|
-
function applyStoredTheme(bundle) {
|
|
353
|
-
const { colors, fonts, radius } = bundle.useStore.getState();
|
|
354
|
-
applyThemeVars({ colors, fonts, radius }, { mode: bundle.mode, dark: bundle.darkColors });
|
|
355
206
|
}
|
|
356
|
-
function
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
testIdPrefix = "theme"
|
|
362
|
-
}) {
|
|
363
|
-
const { useStore, tokens, presets, groupLabels, mode, darkColors } = bundle;
|
|
364
|
-
const colors = useStore((s) => s.colors);
|
|
365
|
-
const fonts = useStore((s) => s.fonts);
|
|
366
|
-
const radius = useStore((s) => s.radius);
|
|
367
|
-
const activePresetId = useStore((s) => s.activePresetId);
|
|
368
|
-
const setColor = useStore((s) => s.setColor);
|
|
369
|
-
const setFont = useStore((s) => s.setFont);
|
|
370
|
-
const setRadius = useStore((s) => s.setRadius);
|
|
371
|
-
const applyPreset = useStore((s) => s.applyPreset);
|
|
372
|
-
const reset = useStore((s) => s.reset);
|
|
373
|
-
const [saving, setSaving] = useState(false);
|
|
374
|
-
const [savedVia, setSavedVia] = useState(null);
|
|
375
|
-
useEffect(() => {
|
|
376
|
-
applyThemeVars({ colors, fonts, radius }, { mode, dark: darkColors });
|
|
377
|
-
}, [colors, fonts, radius, mode, darkColors]);
|
|
378
|
-
const tid2 = (suffix) => `${testIdPrefix}-${suffix}`;
|
|
379
|
-
const groups = [...new Set(tokens.map((t) => t.group))];
|
|
380
|
-
const save = async () => {
|
|
381
|
-
if (!onSave) return;
|
|
382
|
-
setSaving(true);
|
|
383
|
-
const via = await onSave();
|
|
384
|
-
setSavedVia(typeof via === "string" ? via : "saved");
|
|
385
|
-
setSaving(false);
|
|
386
|
-
};
|
|
387
|
-
const Presets = /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
388
|
-
presets.map((p) => /* @__PURE__ */ jsx(
|
|
389
|
-
"button",
|
|
390
|
-
{
|
|
391
|
-
type: "button",
|
|
392
|
-
onClick: () => applyPreset(p.id),
|
|
393
|
-
className: `rounded-full border px-3 py-1 text-xs font-medium transition-colors ${activePresetId === p.id ? "border-primary bg-primary text-primary-foreground" : "border-border text-foreground hover:border-primary"}`,
|
|
394
|
-
"data-testid": tid2(`preset-${p.id}`),
|
|
395
|
-
children: p.label
|
|
396
|
-
},
|
|
397
|
-
p.id
|
|
398
|
-
)),
|
|
399
|
-
/* @__PURE__ */ jsxs(
|
|
400
|
-
"button",
|
|
401
|
-
{
|
|
402
|
-
type: "button",
|
|
403
|
-
onClick: reset,
|
|
404
|
-
className: "ml-auto inline-flex items-center gap-1.5 text-xs font-medium text-muted-foreground hover:text-foreground",
|
|
405
|
-
"data-testid": tid2("reset"),
|
|
406
|
-
children: [
|
|
407
|
-
/* @__PURE__ */ jsx(RotateCcw, { className: "size-3" }),
|
|
408
|
-
" Reset"
|
|
409
|
-
]
|
|
410
|
-
}
|
|
411
|
-
)
|
|
412
|
-
] });
|
|
413
|
-
const colorRow = (k, label) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
414
|
-
/* @__PURE__ */ jsx(
|
|
415
|
-
"input",
|
|
416
|
-
{
|
|
417
|
-
type: "color",
|
|
418
|
-
value: colors[k] ?? "#000000",
|
|
419
|
-
onChange: (e) => setColor(k, e.target.value),
|
|
420
|
-
className: "size-9 shrink-0 cursor-pointer rounded-md border border-border bg-transparent",
|
|
421
|
-
"aria-label": label,
|
|
422
|
-
"data-testid": tid2(`color-${k}`)
|
|
423
|
-
}
|
|
424
|
-
),
|
|
425
|
-
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
426
|
-
/* @__PURE__ */ jsx("span", { className: "block text-xs text-muted-foreground", children: label }),
|
|
427
|
-
/* @__PURE__ */ jsx(
|
|
428
|
-
Input,
|
|
429
|
-
{
|
|
430
|
-
value: colors[k] ?? "",
|
|
431
|
-
onChange: (e) => setColor(k, e.target.value),
|
|
432
|
-
className: "bg-card placeholder:text-muted-foreground/70 focus-visible:border-ring/60 focus-visible:ring-2 focus-visible:ring-ring/50 h-7 font-mono text-xs",
|
|
433
|
-
"data-testid": tid2(`hex-${k}`)
|
|
434
|
-
}
|
|
435
|
-
)
|
|
436
|
-
] })
|
|
437
|
-
] }, k);
|
|
438
|
-
const Typography = /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
439
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
440
|
-
/* @__PURE__ */ jsx("span", { className: "block text-xs text-muted-foreground", children: "Display font stack" }),
|
|
441
|
-
/* @__PURE__ */ jsx(
|
|
442
|
-
Input,
|
|
443
|
-
{
|
|
444
|
-
value: fonts.display,
|
|
445
|
-
onChange: (e) => setFont("display", e.target.value),
|
|
446
|
-
className: "bg-card placeholder:text-muted-foreground/70 focus-visible:border-ring/60 focus-visible:ring-2 focus-visible:ring-ring/50 mt-1 font-mono text-xs",
|
|
447
|
-
"data-testid": tid2("font-display")
|
|
448
|
-
}
|
|
449
|
-
)
|
|
450
|
-
] }),
|
|
451
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
452
|
-
/* @__PURE__ */ jsx("span", { className: "block text-xs text-muted-foreground", children: "Body font stack" }),
|
|
453
|
-
/* @__PURE__ */ jsx(
|
|
454
|
-
Input,
|
|
455
|
-
{
|
|
456
|
-
value: fonts.sans,
|
|
457
|
-
onChange: (e) => setFont("sans", e.target.value),
|
|
458
|
-
className: "bg-card placeholder:text-muted-foreground/70 focus-visible:border-ring/60 focus-visible:ring-2 focus-visible:ring-ring/50 mt-1 font-mono text-xs",
|
|
459
|
-
"data-testid": tid2("font-sans")
|
|
460
|
-
}
|
|
461
|
-
)
|
|
462
|
-
] }),
|
|
463
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
464
|
-
/* @__PURE__ */ jsxs("span", { className: "block text-xs text-muted-foreground", children: [
|
|
465
|
-
"Base radius \u2014 ",
|
|
466
|
-
radius,
|
|
467
|
-
"rem"
|
|
468
|
-
] }),
|
|
469
|
-
/* @__PURE__ */ jsx(
|
|
470
|
-
"input",
|
|
471
|
-
{
|
|
472
|
-
type: "range",
|
|
473
|
-
min: 0,
|
|
474
|
-
max: 1.5,
|
|
475
|
-
step: 0.125,
|
|
476
|
-
value: radius,
|
|
477
|
-
onChange: (e) => setRadius(Number(e.target.value)),
|
|
478
|
-
className: "mt-2 w-full accent-[color:var(--color-primary)]",
|
|
479
|
-
"data-testid": tid2("radius")
|
|
480
|
-
}
|
|
481
|
-
)
|
|
482
|
-
] })
|
|
483
|
-
] });
|
|
484
|
-
const Preview = /* @__PURE__ */ jsxs(Card, { variant: "elevated", className: "rounded-xl", "data-testid": tid2("preview"), children: [
|
|
485
|
-
/* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx(CardTitle, { className: "text-base", children: "Live preview" }) }),
|
|
486
|
-
/* @__PURE__ */ jsxs(CardContent, { className: "space-y-3", children: [
|
|
487
|
-
/* @__PURE__ */ jsxs("div", { className: "rounded-[var(--radius)] bg-primary p-4 text-primary-foreground", children: [
|
|
488
|
-
/* @__PURE__ */ jsx("p", { className: "font-display text-lg font-semibold", children: preview?.title ?? "Preview" }),
|
|
489
|
-
preview?.subtitle && /* @__PURE__ */ jsx("p", { className: "text-xs opacity-80", children: preview.subtitle })
|
|
490
|
-
] }),
|
|
491
|
-
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-6 gap-1.5", children: tokens.map((t) => /* @__PURE__ */ jsx(
|
|
492
|
-
"div",
|
|
493
|
-
{
|
|
494
|
-
title: t.label,
|
|
495
|
-
className: "aspect-square rounded-md border border-border",
|
|
496
|
-
style: { background: `var(--color-${t.key})` }
|
|
497
|
-
},
|
|
498
|
-
t.key
|
|
499
|
-
)) }),
|
|
500
|
-
/* @__PURE__ */ jsxs("div", { className: "rounded-[var(--radius)] border border-border bg-[color:var(--color-ai-accent-soft,var(--color-accent))] p-3", children: [
|
|
501
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-[color:var(--color-ai-accent,var(--color-primary))]", children: "AI action surface" }),
|
|
502
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Themed by the AI-kit accent tokens." })
|
|
503
|
-
] })
|
|
504
|
-
] })
|
|
505
|
-
] });
|
|
506
|
-
const SaveBar = onSave && /* @__PURE__ */ jsxs("div", { className: "mt-6 flex items-center gap-3", children: [
|
|
507
|
-
/* @__PURE__ */ jsxs(
|
|
508
|
-
"button",
|
|
509
|
-
{
|
|
510
|
-
type: "button",
|
|
511
|
-
onClick: () => void save(),
|
|
512
|
-
disabled: saving,
|
|
513
|
-
className: "inline-flex items-center gap-1.5 rounded-md bg-primary px-3 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 disabled:opacity-60",
|
|
514
|
-
"data-testid": tid2("save"),
|
|
515
|
-
children: [
|
|
516
|
-
savedVia ? /* @__PURE__ */ jsx(Check, { className: "size-4" }) : /* @__PURE__ */ jsx(Save, { className: "size-4" }),
|
|
517
|
-
saving ? "Saving\u2026" : savedVia ? "Saved" : "Save theme"
|
|
518
|
-
]
|
|
519
|
-
}
|
|
520
|
-
),
|
|
521
|
-
savedVia && /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", "data-testid": tid2("via"), children: [
|
|
522
|
-
"stored via ",
|
|
523
|
-
savedVia
|
|
524
|
-
] })
|
|
525
|
-
] });
|
|
526
|
-
if (variant === "drawer") {
|
|
527
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col overflow-y-auto bg-card p-5", "data-testid": testIdPrefix, children: [
|
|
528
|
-
/* @__PURE__ */ jsx("div", { className: "mb-4 flex items-center justify-between", children: /* @__PURE__ */ jsx("h2", { className: "font-display text-lg font-semibold text-foreground", children: "Theme" }) }),
|
|
529
|
-
Presets,
|
|
530
|
-
/* @__PURE__ */ jsx("p", { className: "mt-5 mb-2 text-[10px] font-semibold uppercase tracking-[0.14em] text-muted-foreground", children: "Colours" }),
|
|
531
|
-
/* @__PURE__ */ jsx("div", { className: "space-y-3", children: tokens.map((t) => colorRow(t.key, t.label)) }),
|
|
532
|
-
/* @__PURE__ */ jsx("p", { className: "mt-6 mb-2 text-[10px] font-semibold uppercase tracking-[0.14em] text-muted-foreground", children: "Typography & shape" }),
|
|
533
|
-
Typography,
|
|
534
|
-
SaveBar
|
|
535
|
-
] });
|
|
207
|
+
function persistWorkspace(apiUrl, id) {
|
|
208
|
+
try {
|
|
209
|
+
if (id) window.localStorage.setItem(workspaceStorageKey(apiUrl), id);
|
|
210
|
+
else window.localStorage.removeItem(workspaceStorageKey(apiUrl));
|
|
211
|
+
} catch {
|
|
536
212
|
}
|
|
537
|
-
return /* @__PURE__ */ jsxs("div", { className: "grid gap-6 lg:grid-cols-[1fr_320px]", "data-testid": testIdPrefix, children: [
|
|
538
|
-
/* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
539
|
-
/* @__PURE__ */ jsxs(Card, { variant: "elevated", className: "rounded-xl", children: [
|
|
540
|
-
/* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center gap-2 text-base", children: [
|
|
541
|
-
/* @__PURE__ */ jsx(Palette, { className: "size-4 text-[color:var(--color-primary)]" }),
|
|
542
|
-
" Presets"
|
|
543
|
-
] }) }),
|
|
544
|
-
/* @__PURE__ */ jsx(CardContent, { children: Presets })
|
|
545
|
-
] }),
|
|
546
|
-
groups.map((group) => /* @__PURE__ */ jsxs(
|
|
547
|
-
Card,
|
|
548
|
-
{
|
|
549
|
-
variant: "elevated",
|
|
550
|
-
className: "rounded-xl",
|
|
551
|
-
"data-testid": tid2(`group-${group}`),
|
|
552
|
-
children: [
|
|
553
|
-
/* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx(CardTitle, { className: "text-base", children: groupLabels[group] ?? group }) }),
|
|
554
|
-
/* @__PURE__ */ jsx(CardContent, { className: "grid gap-3 sm:grid-cols-2", children: tokens.filter((t) => t.group === group).map((t) => colorRow(t.key, t.label)) })
|
|
555
|
-
]
|
|
556
|
-
},
|
|
557
|
-
group
|
|
558
|
-
)),
|
|
559
|
-
/* @__PURE__ */ jsxs(Card, { variant: "elevated", className: "rounded-xl", children: [
|
|
560
|
-
/* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx(CardTitle, { className: "text-base", children: "Typography & shape" }) }),
|
|
561
|
-
/* @__PURE__ */ jsx(CardContent, { children: Typography })
|
|
562
|
-
] }),
|
|
563
|
-
SaveBar
|
|
564
|
-
] }),
|
|
565
|
-
/* @__PURE__ */ jsx("div", { className: "lg:sticky lg:top-4 lg:self-start", children: Preview })
|
|
566
|
-
] });
|
|
567
213
|
}
|
|
568
|
-
var ConnectionContext = createContext(null);
|
|
569
214
|
function ConnectionProvider({
|
|
570
215
|
config,
|
|
571
216
|
children
|
|
@@ -598,10 +243,12 @@ function ConnectionProvider({
|
|
|
598
243
|
await arbi.login(email, password);
|
|
599
244
|
const workspaces = await arbi.workspaces.list();
|
|
600
245
|
if (workspaces?.length) {
|
|
601
|
-
const
|
|
246
|
+
const persisted = readPersistedWorkspace(config.apiUrl);
|
|
247
|
+
const preferred = persisted ?? config.workspaceId;
|
|
602
248
|
const target = (preferred ? workspaces.find((w) => w.external_id === preferred) : void 0) ?? workspaces[0];
|
|
603
249
|
await arbi.selectWorkspace(target.external_id);
|
|
604
250
|
setWorkspaceId(target.external_id);
|
|
251
|
+
persistWorkspace(config.apiUrl, target.external_id);
|
|
605
252
|
}
|
|
606
253
|
let resolved = { name: email.split("@")[0], email };
|
|
607
254
|
try {
|
|
@@ -628,7 +275,7 @@ function ConnectionProvider({
|
|
|
628
275
|
setStatus("error");
|
|
629
276
|
}
|
|
630
277
|
},
|
|
631
|
-
[arbi, enterDemo, isLiveConfigured, config.workspaceId]
|
|
278
|
+
[arbi, enterDemo, isLiveConfigured, config.workspaceId, config.apiUrl]
|
|
632
279
|
);
|
|
633
280
|
const logout = useCallback(() => {
|
|
634
281
|
if (mode === "live") {
|
|
@@ -636,10 +283,25 @@ function ConnectionProvider({
|
|
|
636
283
|
}
|
|
637
284
|
setUser(null);
|
|
638
285
|
setWorkspaceId(null);
|
|
286
|
+
persistWorkspace(config.apiUrl, null);
|
|
639
287
|
setStatus("disconnected");
|
|
640
288
|
setError(null);
|
|
641
|
-
}, [arbi, mode]);
|
|
642
|
-
const setWorkspace = useCallback(
|
|
289
|
+
}, [arbi, mode, config.apiUrl]);
|
|
290
|
+
const setWorkspace = useCallback(
|
|
291
|
+
async (id) => {
|
|
292
|
+
if (mode === "live" && arbi.isLoggedIn) {
|
|
293
|
+
await arbi.selectWorkspace(id);
|
|
294
|
+
}
|
|
295
|
+
setWorkspaceId(id);
|
|
296
|
+
persistWorkspace(config.apiUrl, id);
|
|
297
|
+
},
|
|
298
|
+
[arbi, mode, config.apiUrl]
|
|
299
|
+
);
|
|
300
|
+
const ensureWorkspaceOpen = useCallback(async () => {
|
|
301
|
+
if (mode !== "live" || !arbi.isLoggedIn) return;
|
|
302
|
+
const id = workspaceId ?? readPersistedWorkspace(config.apiUrl) ?? config.workspaceId;
|
|
303
|
+
if (id) await arbi.selectWorkspace(id);
|
|
304
|
+
}, [arbi, mode, workspaceId, config.apiUrl, config.workspaceId]);
|
|
643
305
|
const value = useMemo(
|
|
644
306
|
() => ({
|
|
645
307
|
mode,
|
|
@@ -654,7 +316,8 @@ function ConnectionProvider({
|
|
|
654
316
|
login,
|
|
655
317
|
enterDemo,
|
|
656
318
|
logout,
|
|
657
|
-
setWorkspace
|
|
319
|
+
setWorkspace,
|
|
320
|
+
ensureWorkspaceOpen
|
|
658
321
|
}),
|
|
659
322
|
[
|
|
660
323
|
mode,
|
|
@@ -669,7 +332,8 @@ function ConnectionProvider({
|
|
|
669
332
|
login,
|
|
670
333
|
enterDemo,
|
|
671
334
|
logout,
|
|
672
|
-
setWorkspace
|
|
335
|
+
setWorkspace,
|
|
336
|
+
ensureWorkspaceOpen
|
|
673
337
|
]
|
|
674
338
|
);
|
|
675
339
|
return /* @__PURE__ */ jsx(ConnectionContext.Provider, { value, children });
|
|
@@ -714,100 +378,6 @@ function useSemanticSearch() {
|
|
|
714
378
|
const { docIds } = useWorkspaceDocs();
|
|
715
379
|
return useSemanticSearch$1(docIds);
|
|
716
380
|
}
|
|
717
|
-
|
|
718
|
-
// src/lib/testid.ts
|
|
719
|
-
function tid(...parts) {
|
|
720
|
-
return parts.filter((p) => p !== void 0 && p !== false && p !== "").map(
|
|
721
|
-
(p) => String(p).trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "")
|
|
722
|
-
).join("-");
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
// src/lib/format.ts
|
|
726
|
-
function gbp(value, compact = false) {
|
|
727
|
-
return new Intl.NumberFormat("en-GB", {
|
|
728
|
-
style: "currency",
|
|
729
|
-
currency: "GBP",
|
|
730
|
-
maximumFractionDigits: compact && Math.abs(value) >= 1e3 ? 1 : 0,
|
|
731
|
-
notation: compact ? "compact" : "standard"
|
|
732
|
-
}).format(value);
|
|
733
|
-
}
|
|
734
|
-
function initials(name) {
|
|
735
|
-
const parts = name.trim().split(/\s+/);
|
|
736
|
-
if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
|
|
737
|
-
return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
|
|
738
|
-
}
|
|
739
|
-
function parseIso(iso) {
|
|
740
|
-
const dateOnly = /^\d{4}-\d{2}-\d{2}$/.test(iso);
|
|
741
|
-
const d = new Date(dateOnly ? `${iso}T00:00:00` : iso);
|
|
742
|
-
if (Number.isNaN(d.getTime())) throw new Error(`Invalid ISO date: ${iso}`);
|
|
743
|
-
return d;
|
|
744
|
-
}
|
|
745
|
-
function fmtDate(iso) {
|
|
746
|
-
try {
|
|
747
|
-
return new Intl.DateTimeFormat("en-GB", {
|
|
748
|
-
day: "numeric",
|
|
749
|
-
month: "short",
|
|
750
|
-
year: "numeric"
|
|
751
|
-
}).format(parseIso(iso));
|
|
752
|
-
} catch {
|
|
753
|
-
return iso;
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
|
-
function fmtDateTime(iso) {
|
|
757
|
-
try {
|
|
758
|
-
return new Intl.DateTimeFormat("en-GB", {
|
|
759
|
-
day: "numeric",
|
|
760
|
-
month: "short",
|
|
761
|
-
year: "numeric",
|
|
762
|
-
hour: "2-digit",
|
|
763
|
-
minute: "2-digit",
|
|
764
|
-
hour12: false
|
|
765
|
-
}).format(parseIso(iso));
|
|
766
|
-
} catch {
|
|
767
|
-
return iso;
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
var RELATIVE_UNITS = [
|
|
771
|
-
["year", 31536e3],
|
|
772
|
-
["month", 2592e3],
|
|
773
|
-
["week", 604800],
|
|
774
|
-
["day", 86400],
|
|
775
|
-
["hour", 3600],
|
|
776
|
-
["minute", 60],
|
|
777
|
-
["second", 1]
|
|
778
|
-
];
|
|
779
|
-
function fromNow(iso, from = /* @__PURE__ */ new Date()) {
|
|
780
|
-
try {
|
|
781
|
-
const diffSeconds = (parseIso(iso).getTime() - from.getTime()) / 1e3;
|
|
782
|
-
const abs = Math.abs(diffSeconds);
|
|
783
|
-
const rtf = new Intl.RelativeTimeFormat("en-GB", { numeric: "always" });
|
|
784
|
-
for (const [unit, secs] of RELATIVE_UNITS) {
|
|
785
|
-
if (abs >= secs || unit === "second") {
|
|
786
|
-
const value = Math.round(diffSeconds / secs);
|
|
787
|
-
return rtf.format(value, unit);
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
return rtf.format(0, "second");
|
|
791
|
-
} catch {
|
|
792
|
-
return iso;
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
function daysUntil(iso, from = /* @__PURE__ */ new Date()) {
|
|
796
|
-
try {
|
|
797
|
-
const target = parseIso(iso);
|
|
798
|
-
const a = Date.UTC(target.getFullYear(), target.getMonth(), target.getDate());
|
|
799
|
-
const b = Date.UTC(from.getFullYear(), from.getMonth(), from.getDate());
|
|
800
|
-
return Math.round((a - b) / 864e5);
|
|
801
|
-
} catch {
|
|
802
|
-
return 0;
|
|
803
|
-
}
|
|
804
|
-
}
|
|
805
|
-
function hrs(n) {
|
|
806
|
-
return `${n.toFixed(1)}h`;
|
|
807
|
-
}
|
|
808
|
-
function pct(n) {
|
|
809
|
-
return `${Math.round(n)}%`;
|
|
810
|
-
}
|
|
811
381
|
function EmptyState({
|
|
812
382
|
icon: Icon,
|
|
813
383
|
title,
|
|
@@ -1300,1020 +870,289 @@ function GridView({
|
|
|
1300
870
|
onCellValueChanged,
|
|
1301
871
|
onRowClicked: handleRowClicked,
|
|
1302
872
|
onStateUpdated: handleStateUpdated,
|
|
1303
|
-
...combinedOptions
|
|
1304
|
-
}
|
|
1305
|
-
) });
|
|
1306
|
-
}
|
|
1307
|
-
function PageHeader({
|
|
1308
|
-
title,
|
|
1309
|
-
eyebrow,
|
|
1310
|
-
description,
|
|
1311
|
-
actions,
|
|
1312
|
-
className,
|
|
1313
|
-
testId
|
|
1314
|
-
}) {
|
|
1315
|
-
return /* @__PURE__ */ jsxs(
|
|
1316
|
-
"div",
|
|
1317
|
-
{
|
|
1318
|
-
className: cn("flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between", className),
|
|
1319
|
-
"data-testid": testId,
|
|
1320
|
-
children: [
|
|
1321
|
-
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
1322
|
-
eyebrow && /* @__PURE__ */ jsx("p", { className: "mb-1 text-xs font-semibold uppercase tracking-wider text-muted-foreground", children: eyebrow }),
|
|
1323
|
-
/* @__PURE__ */ jsx("h1", { className: "font-display text-2xl font-semibold tracking-tight text-foreground", children: title }),
|
|
1324
|
-
description && /* @__PURE__ */ jsx("p", { className: "mt-1 max-w-2xl text-sm text-muted-foreground", children: description })
|
|
1325
|
-
] }),
|
|
1326
|
-
actions && /* @__PURE__ */ jsx("div", { className: "flex shrink-0 items-center gap-2", children: actions })
|
|
1327
|
-
]
|
|
1328
|
-
}
|
|
1329
|
-
);
|
|
1330
|
-
}
|
|
1331
|
-
function SectionHeading({
|
|
1332
|
-
eyebrow,
|
|
1333
|
-
title,
|
|
1334
|
-
lead,
|
|
1335
|
-
align = "left",
|
|
1336
|
-
className,
|
|
1337
|
-
invert,
|
|
1338
|
-
eyebrowClassName
|
|
1339
|
-
}) {
|
|
1340
|
-
return /* @__PURE__ */ jsxs("div", { className: cn("max-w-3xl", align === "center" && "mx-auto text-center", className), children: [
|
|
1341
|
-
eyebrow && /* @__PURE__ */ jsx(
|
|
1342
|
-
"p",
|
|
1343
|
-
{
|
|
1344
|
-
className: cn(
|
|
1345
|
-
"mb-3 text-xs font-semibold uppercase tracking-wider",
|
|
1346
|
-
eyebrowClassName ?? (invert ? "text-background/60" : "text-muted-foreground")
|
|
1347
|
-
),
|
|
1348
|
-
children: eyebrow
|
|
1349
|
-
}
|
|
1350
|
-
),
|
|
1351
|
-
/* @__PURE__ */ jsx(
|
|
1352
|
-
"h2",
|
|
1353
|
-
{
|
|
1354
|
-
className: cn(
|
|
1355
|
-
"font-display text-3xl font-semibold tracking-tight text-balance sm:text-4xl",
|
|
1356
|
-
invert ? "text-background" : "text-foreground"
|
|
1357
|
-
),
|
|
1358
|
-
children: title
|
|
1359
|
-
}
|
|
1360
|
-
),
|
|
1361
|
-
lead && /* @__PURE__ */ jsx(
|
|
1362
|
-
"p",
|
|
1363
|
-
{
|
|
1364
|
-
className: cn(
|
|
1365
|
-
"mt-4 text-lg leading-relaxed",
|
|
1366
|
-
invert ? "text-background/70" : "text-muted-foreground"
|
|
1367
|
-
),
|
|
1368
|
-
children: lead
|
|
1369
|
-
}
|
|
1370
|
-
)
|
|
1371
|
-
] });
|
|
1372
|
-
}
|
|
1373
|
-
function Toolbar({
|
|
1374
|
-
search,
|
|
1375
|
-
onSearch,
|
|
1376
|
-
searchPlaceholder = "Search\u2026",
|
|
1377
|
-
filters,
|
|
1378
|
-
actions,
|
|
1379
|
-
className,
|
|
1380
|
-
testId
|
|
1381
|
-
}) {
|
|
1382
|
-
return /* @__PURE__ */ jsxs(
|
|
1383
|
-
"div",
|
|
1384
|
-
{
|
|
1385
|
-
className: cn(
|
|
1386
|
-
"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between",
|
|
1387
|
-
className
|
|
1388
|
-
),
|
|
1389
|
-
"data-testid": testId,
|
|
1390
|
-
children: [
|
|
1391
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-wrap items-center gap-2", children: [
|
|
1392
|
-
onSearch && /* @__PURE__ */ jsxs("div", { className: "relative w-full max-w-xs", children: [
|
|
1393
|
-
/* @__PURE__ */ jsx(Search, { className: "pointer-events-none absolute left-2.5 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" }),
|
|
1394
|
-
/* @__PURE__ */ jsx(
|
|
1395
|
-
Input,
|
|
1396
|
-
{
|
|
1397
|
-
value: search,
|
|
1398
|
-
onChange: (e) => onSearch(e.target.value),
|
|
1399
|
-
placeholder: searchPlaceholder,
|
|
1400
|
-
className: "bg-card text-sm placeholder:text-muted-foreground/70 focus-visible:border-ring/60 focus-visible:ring-2 focus-visible:ring-ring/50 pl-8",
|
|
1401
|
-
"data-testid": testId ? `${testId}-search` : "toolbar-search"
|
|
1402
|
-
}
|
|
1403
|
-
)
|
|
1404
|
-
] }),
|
|
1405
|
-
filters
|
|
1406
|
-
] }),
|
|
1407
|
-
actions && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: actions })
|
|
1408
|
-
]
|
|
1409
|
-
}
|
|
1410
|
-
);
|
|
1411
|
-
}
|
|
1412
|
-
function MetricCard({
|
|
1413
|
-
label,
|
|
1414
|
-
value,
|
|
1415
|
-
icon: Icon,
|
|
1416
|
-
hint,
|
|
1417
|
-
delta,
|
|
1418
|
-
accent = "default",
|
|
1419
|
-
testId
|
|
1420
|
-
}) {
|
|
1421
|
-
const accentStyle = accent && accent !== "default" ? { color: `var(--color-${accent})` } : void 0;
|
|
1422
|
-
const deltaGood = delta?.good ?? delta?.direction === "up";
|
|
1423
|
-
return /* @__PURE__ */ jsxs(Card, { variant: "elevated", className: "card-hover rounded-xl p-5", "data-testid": testId, children: [
|
|
1424
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
|
|
1425
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs font-medium uppercase tracking-wide text-muted-foreground", children: label }),
|
|
1426
|
-
Icon && /* @__PURE__ */ jsx(Icon, { className: "size-4 shrink-0", style: accentStyle })
|
|
1427
|
-
] }),
|
|
1428
|
-
/* @__PURE__ */ jsx(
|
|
1429
|
-
"p",
|
|
1430
|
-
{
|
|
1431
|
-
className: "mt-2 font-display text-2xl font-semibold tracking-tight",
|
|
1432
|
-
"data-testid": testId && `${testId}-value`,
|
|
1433
|
-
children: value
|
|
1434
|
-
}
|
|
1435
|
-
),
|
|
1436
|
-
/* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-center gap-2", children: [
|
|
1437
|
-
delta && /* @__PURE__ */ jsxs(
|
|
1438
|
-
"span",
|
|
1439
|
-
{
|
|
1440
|
-
className: cn(
|
|
1441
|
-
"inline-flex items-center gap-0.5 text-xs font-medium",
|
|
1442
|
-
deltaGood ? "text-success" : "text-destructive"
|
|
1443
|
-
),
|
|
1444
|
-
children: [
|
|
1445
|
-
delta.direction === "up" ? /* @__PURE__ */ jsx(ArrowUpRight, { className: "size-3" }) : /* @__PURE__ */ jsx(ArrowDownRight, { className: "size-3" }),
|
|
1446
|
-
delta.value
|
|
1447
|
-
]
|
|
1448
|
-
}
|
|
1449
|
-
),
|
|
1450
|
-
hint && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: hint })
|
|
1451
|
-
] })
|
|
1452
|
-
] });
|
|
1453
|
-
}
|
|
1454
|
-
var ASSET_REF_PREFIX = "asset:";
|
|
1455
|
-
function asAssetRef(docId) {
|
|
1456
|
-
return `${ASSET_REF_PREFIX}${docId}`;
|
|
1457
|
-
}
|
|
1458
|
-
function assetRefId(src) {
|
|
1459
|
-
return src.slice(ASSET_REF_PREFIX.length);
|
|
1460
|
-
}
|
|
1461
|
-
var AssetResolverContext = createContext(false);
|
|
1462
|
-
function AssetResolverProvider({ children }) {
|
|
1463
|
-
return /* @__PURE__ */ jsx(AssetResolverContext.Provider, { value: true, children });
|
|
1464
|
-
}
|
|
1465
|
-
function useAssetResolverActive() {
|
|
1466
|
-
return useContext(AssetResolverContext);
|
|
1467
|
-
}
|
|
1468
|
-
function isAssetRef(src) {
|
|
1469
|
-
return !!src && src.startsWith(ASSET_REF_PREFIX);
|
|
1470
|
-
}
|
|
1471
|
-
function useAssetImage(docId) {
|
|
1472
|
-
const arbi = useArbi();
|
|
1473
|
-
const { data: thumbs } = useThumbnails([docId]);
|
|
1474
|
-
const thumb = thumbs?.[docId];
|
|
1475
|
-
const { data: objectUrl } = useQuery({
|
|
1476
|
-
queryKey: ["arbi", "asset-image", docId],
|
|
1477
|
-
queryFn: async () => {
|
|
1478
|
-
const res = await arbi.documents.download(docId);
|
|
1479
|
-
const blob = await res.blob();
|
|
1480
|
-
return URL.createObjectURL(blob);
|
|
1481
|
-
},
|
|
1482
|
-
// Only download when the thumbnail is genuinely absent (not merely loading).
|
|
1483
|
-
enabled: !!docId && thumbs != null && !thumb && arbi.hasWorkspace,
|
|
1484
|
-
staleTime: 10 * 6e4
|
|
1485
|
-
});
|
|
1486
|
-
useEffect(() => {
|
|
1487
|
-
return () => {
|
|
1488
|
-
if (objectUrl) URL.revokeObjectURL(objectUrl);
|
|
1489
|
-
};
|
|
1490
|
-
}, [objectUrl]);
|
|
1491
|
-
return thumb ?? objectUrl;
|
|
1492
|
-
}
|
|
1493
|
-
function AssetThumb({
|
|
1494
|
-
docId,
|
|
1495
|
-
alt,
|
|
1496
|
-
className,
|
|
1497
|
-
testId
|
|
1498
|
-
}) {
|
|
1499
|
-
const src = useAssetImage(docId);
|
|
1500
|
-
return /* @__PURE__ */ jsx("img", { src: src ?? void 0, alt: alt ?? "", className, "data-testid": testId });
|
|
1501
|
-
}
|
|
1502
|
-
var ASPECT = {
|
|
1503
|
-
"16:9": "aspect-video",
|
|
1504
|
-
"4:3": "aspect-[4/3]",
|
|
1505
|
-
"1:1": "aspect-square",
|
|
1506
|
-
"21:9": "aspect-[21/9]",
|
|
1507
|
-
"4:5": "aspect-[4/5]"
|
|
1508
|
-
};
|
|
1509
|
-
var ROUNDED = {
|
|
1510
|
-
none: "rounded-none",
|
|
1511
|
-
md: "rounded-md",
|
|
1512
|
-
lg: "rounded-xl",
|
|
1513
|
-
full: "rounded-full"
|
|
1514
|
-
};
|
|
1515
|
-
function BlockImage({
|
|
1516
|
-
src,
|
|
1517
|
-
alt = "",
|
|
1518
|
-
aspect = "16:9",
|
|
1519
|
-
rounded = "lg",
|
|
1520
|
-
framed,
|
|
1521
|
-
className,
|
|
1522
|
-
testId
|
|
1523
|
-
}) {
|
|
1524
|
-
const shape = cn(
|
|
1525
|
-
ASPECT[aspect] ?? ASPECT["16:9"],
|
|
1526
|
-
ROUNDED[rounded] ?? ROUNDED.lg,
|
|
1527
|
-
framed && "ring-1 ring-border shadow-xl"
|
|
1528
|
-
);
|
|
1529
|
-
const canResolve = useAssetResolverActive();
|
|
1530
|
-
if (canResolve && isAssetRef(src)) {
|
|
1531
|
-
return /* @__PURE__ */ jsx(
|
|
1532
|
-
AssetThumb,
|
|
1533
|
-
{
|
|
1534
|
-
docId: assetRefId(src),
|
|
1535
|
-
alt,
|
|
1536
|
-
className: cn("w-full object-cover", shape, className),
|
|
1537
|
-
testId
|
|
1538
|
-
}
|
|
1539
|
-
);
|
|
1540
|
-
}
|
|
1541
|
-
if (src && !isAssetRef(src)) {
|
|
1542
|
-
return /* @__PURE__ */ jsx(
|
|
1543
|
-
"img",
|
|
1544
|
-
{
|
|
1545
|
-
src,
|
|
1546
|
-
alt,
|
|
1547
|
-
className: cn("w-full object-cover", shape, className),
|
|
1548
|
-
"data-testid": testId
|
|
1549
|
-
}
|
|
1550
|
-
);
|
|
1551
|
-
}
|
|
1552
|
-
return /* @__PURE__ */ jsx(
|
|
1553
|
-
"div",
|
|
1554
|
-
{
|
|
1555
|
-
className: cn(
|
|
1556
|
-
"flex w-full items-center justify-center overflow-hidden border border-border",
|
|
1557
|
-
"bg-gradient-to-br from-muted via-card to-accent text-muted-foreground",
|
|
1558
|
-
shape,
|
|
1559
|
-
className
|
|
1560
|
-
),
|
|
1561
|
-
"data-testid": testId,
|
|
1562
|
-
"aria-label": alt || "Image placeholder",
|
|
1563
|
-
role: "img",
|
|
1564
|
-
children: /* @__PURE__ */ jsx(ImageIcon, { className: "size-8 opacity-60" })
|
|
1565
|
-
}
|
|
1566
|
-
);
|
|
1567
|
-
}
|
|
1568
|
-
var TONE_SURFACE = {
|
|
1569
|
-
default: "bg-background text-foreground",
|
|
1570
|
-
muted: "bg-muted text-foreground",
|
|
1571
|
-
ink: "bg-foreground text-background"
|
|
1572
|
-
};
|
|
1573
|
-
function renderTitle(title, emphasis) {
|
|
1574
|
-
if (!emphasis || !title.includes(emphasis)) return title;
|
|
1575
|
-
const parts = title.split(emphasis);
|
|
1576
|
-
return parts.map((part, i) => /* @__PURE__ */ jsxs("span", { children: [
|
|
1577
|
-
part,
|
|
1578
|
-
i < parts.length - 1 && /* @__PURE__ */ jsx("span", { className: "text-primary", children: emphasis })
|
|
1579
|
-
] }, i));
|
|
1580
|
-
}
|
|
1581
|
-
function Hero({
|
|
1582
|
-
eyebrow,
|
|
1583
|
-
title,
|
|
1584
|
-
emphasis,
|
|
1585
|
-
subtitle,
|
|
1586
|
-
primaryCta,
|
|
1587
|
-
secondaryCta,
|
|
1588
|
-
align = "left",
|
|
1589
|
-
tone = "default",
|
|
1590
|
-
imageUrl,
|
|
1591
|
-
backgroundImage,
|
|
1592
|
-
overlay = true,
|
|
1593
|
-
eyebrowClassName,
|
|
1594
|
-
testId
|
|
1595
|
-
}) {
|
|
1596
|
-
const onDark = Boolean(backgroundImage) || tone === "ink";
|
|
1597
|
-
const subtle = onDark ? "text-background/70" : "text-muted-foreground";
|
|
1598
|
-
const eyebrowClass = eyebrowClassName ?? (onDark ? "text-background/60" : "text-muted-foreground");
|
|
1599
|
-
const centered = align === "center" || Boolean(backgroundImage);
|
|
1600
|
-
const heading = renderTitle(title, emphasis);
|
|
1601
|
-
const copy = /* @__PURE__ */ jsxs(
|
|
1602
|
-
"div",
|
|
1603
|
-
{
|
|
1604
|
-
className: cn(
|
|
1605
|
-
"max-w-2xl",
|
|
1606
|
-
centered && "mx-auto text-center",
|
|
1607
|
-
backgroundImage && "text-background"
|
|
1608
|
-
),
|
|
1609
|
-
children: [
|
|
1610
|
-
eyebrow && /* @__PURE__ */ jsx("p", { className: cn("mb-4 text-sm font-semibold uppercase tracking-wider", eyebrowClass), children: eyebrow }),
|
|
1611
|
-
/* @__PURE__ */ jsx("h1", { className: "text-4xl font-semibold tracking-tight text-balance sm:text-5xl", children: heading }),
|
|
1612
|
-
subtitle && /* @__PURE__ */ jsx("p", { className: cn("mt-6 text-lg leading-relaxed", subtle), children: subtitle }),
|
|
1613
|
-
(primaryCta?.label || secondaryCta?.label) && /* @__PURE__ */ jsxs(
|
|
1614
|
-
"div",
|
|
1615
|
-
{
|
|
1616
|
-
className: cn("mt-8 flex flex-col gap-3 sm:flex-row", centered && "sm:justify-center"),
|
|
1617
|
-
children: [
|
|
1618
|
-
primaryCta?.label && /* @__PURE__ */ jsx(Button, { asChild: true, size: "lg", children: /* @__PURE__ */ jsxs("a", { href: primaryCta.href || "#", children: [
|
|
1619
|
-
primaryCta.label,
|
|
1620
|
-
/* @__PURE__ */ jsx(ArrowRight, { className: "size-4" })
|
|
1621
|
-
] }) }),
|
|
1622
|
-
secondaryCta?.label && /* @__PURE__ */ jsx(Button, { asChild: true, size: "lg", variant: "outline", children: /* @__PURE__ */ jsx("a", { href: secondaryCta.href || "#", children: secondaryCta.label }) })
|
|
1623
|
-
]
|
|
1624
|
-
}
|
|
1625
|
-
)
|
|
1626
|
-
]
|
|
1627
|
-
}
|
|
1628
|
-
);
|
|
1629
|
-
if (backgroundImage) {
|
|
1630
|
-
const bgStyle = {
|
|
1631
|
-
backgroundImage: `url("${backgroundImage}")`,
|
|
1632
|
-
backgroundSize: "cover",
|
|
1633
|
-
backgroundPosition: "center"
|
|
1634
|
-
};
|
|
1635
|
-
return /* @__PURE__ */ jsxs(
|
|
1636
|
-
"section",
|
|
1637
|
-
{
|
|
1638
|
-
className: "relative isolate overflow-hidden",
|
|
1639
|
-
style: bgStyle,
|
|
1640
|
-
"data-testid": testId,
|
|
1641
|
-
"data-bg": testId && `${testId}-bg`,
|
|
1642
|
-
children: [
|
|
1643
|
-
overlay && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-black/55", "aria-hidden": true }),
|
|
1644
|
-
/* @__PURE__ */ jsx("div", { className: "relative mx-auto max-w-7xl px-5 py-28 lg:px-8 lg:py-36", children: copy })
|
|
1645
|
-
]
|
|
1646
|
-
}
|
|
1647
|
-
);
|
|
1648
|
-
}
|
|
1649
|
-
return /* @__PURE__ */ jsx("section", { className: cn(TONE_SURFACE[tone] ?? TONE_SURFACE.default), "data-testid": testId, children: /* @__PURE__ */ jsx("div", { className: "mx-auto max-w-7xl px-5 py-20 lg:px-8 lg:py-28", children: centered ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-12", children: [
|
|
1650
|
-
copy,
|
|
1651
|
-
imageUrl && /* @__PURE__ */ jsx(
|
|
1652
|
-
BlockImage,
|
|
1653
|
-
{
|
|
1654
|
-
src: imageUrl,
|
|
1655
|
-
aspect: "16:9",
|
|
1656
|
-
rounded: "lg",
|
|
1657
|
-
className: "w-full max-w-4xl",
|
|
1658
|
-
testId: testId && `${testId}-image`
|
|
1659
|
-
}
|
|
1660
|
-
)
|
|
1661
|
-
] }) : /* @__PURE__ */ jsxs("div", { className: "grid items-center gap-12 lg:grid-cols-2", children: [
|
|
1662
|
-
copy,
|
|
1663
|
-
/* @__PURE__ */ jsx(
|
|
1664
|
-
BlockImage,
|
|
1665
|
-
{
|
|
1666
|
-
src: imageUrl,
|
|
1667
|
-
aspect: "4:5",
|
|
1668
|
-
rounded: "lg",
|
|
1669
|
-
testId: testId && `${testId}-image`
|
|
1670
|
-
}
|
|
1671
|
-
)
|
|
1672
|
-
] }) }) });
|
|
1673
|
-
}
|
|
1674
|
-
var COLS = {
|
|
1675
|
-
"2": "sm:grid-cols-2",
|
|
1676
|
-
"3": "sm:grid-cols-2 lg:grid-cols-3"
|
|
1677
|
-
};
|
|
1678
|
-
function FeatureGrid({ columns = "3", items, testId }) {
|
|
1679
|
-
return /* @__PURE__ */ jsx("div", { className: cn("grid gap-5", COLS[columns] ?? COLS["3"]), "data-testid": testId, children: (items ?? []).map((item, i) => {
|
|
1680
|
-
const Icon = item.icon;
|
|
1681
|
-
return /* @__PURE__ */ jsxs(
|
|
1682
|
-
Card,
|
|
1683
|
-
{
|
|
1684
|
-
variant: "outline",
|
|
1685
|
-
className: "h-full p-6",
|
|
1686
|
-
"data-testid": testId && `${testId}-item-${i}`,
|
|
1687
|
-
children: [
|
|
1688
|
-
Icon && /* @__PURE__ */ jsx("span", { className: "mb-4 inline-flex size-10 items-center justify-center rounded-lg bg-primary/10 text-primary", children: /* @__PURE__ */ jsx(Icon, { className: "size-5" }) }),
|
|
1689
|
-
/* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold tracking-tight", children: item.title }),
|
|
1690
|
-
item.description && /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm leading-relaxed text-muted-foreground", children: item.description })
|
|
1691
|
-
]
|
|
1692
|
-
},
|
|
1693
|
-
i
|
|
1694
|
-
);
|
|
1695
|
-
}) });
|
|
1696
|
-
}
|
|
1697
|
-
var GRID = {
|
|
1698
|
-
1: "grid-cols-1",
|
|
1699
|
-
2: "grid-cols-2",
|
|
1700
|
-
3: "grid-cols-2 sm:grid-cols-3",
|
|
1701
|
-
4: "grid-cols-2 lg:grid-cols-4"
|
|
1702
|
-
};
|
|
1703
|
-
function StatGroup({ items, testId }) {
|
|
1704
|
-
const list = items ?? [];
|
|
1705
|
-
const cols = GRID[Math.min(list.length, 4)] ?? GRID[4];
|
|
1706
|
-
return /* @__PURE__ */ jsx("dl", { className: cn("grid gap-8", cols), "data-testid": testId, children: list.map((item, i) => /* @__PURE__ */ jsxs("div", { className: "text-center", "data-testid": testId && `${testId}-item-${i}`, children: [
|
|
1707
|
-
/* @__PURE__ */ jsx("dt", { className: "sr-only", children: item.label }),
|
|
1708
|
-
/* @__PURE__ */ jsx("dd", { className: "text-4xl font-semibold tracking-tight sm:text-5xl", children: item.value }),
|
|
1709
|
-
/* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: item.label })
|
|
1710
|
-
] }, i)) });
|
|
1711
|
-
}
|
|
1712
|
-
function Testimonial({ quote, author, role, avatarUrl, testId }) {
|
|
1713
|
-
return /* @__PURE__ */ jsxs(Card, { variant: "outline", className: "mx-auto max-w-3xl p-8 text-center", "data-testid": testId, children: [
|
|
1714
|
-
/* @__PURE__ */ jsx(Quote, { className: "mx-auto size-8 text-primary/40", "aria-hidden": true }),
|
|
1715
|
-
/* @__PURE__ */ jsx("blockquote", { className: "mt-4 text-xl font-medium leading-relaxed text-balance", children: quote }),
|
|
1716
|
-
(author || avatarUrl) && /* @__PURE__ */ jsxs("div", { className: "mt-6 flex items-center justify-center gap-3", children: [
|
|
1717
|
-
(avatarUrl || author) && /* @__PURE__ */ jsxs(Avatar, { children: [
|
|
1718
|
-
avatarUrl && /* @__PURE__ */ jsx(AvatarImage, { src: avatarUrl, alt: author ?? "" }),
|
|
1719
|
-
/* @__PURE__ */ jsx(AvatarFallback, { children: initials(author || "?") })
|
|
1720
|
-
] }),
|
|
1721
|
-
/* @__PURE__ */ jsxs("div", { className: "text-left", children: [
|
|
1722
|
-
author && /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold", children: author }),
|
|
1723
|
-
role && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: role })
|
|
1724
|
-
] })
|
|
1725
|
-
] })
|
|
1726
|
-
] });
|
|
1727
|
-
}
|
|
1728
|
-
var TONE_SURFACE2 = {
|
|
1729
|
-
default: "bg-primary text-primary-foreground",
|
|
1730
|
-
muted: "bg-muted text-foreground",
|
|
1731
|
-
ink: "bg-foreground text-background"
|
|
1732
|
-
};
|
|
1733
|
-
function CTABanner({
|
|
1734
|
-
title,
|
|
1735
|
-
subtitle,
|
|
1736
|
-
cta,
|
|
1737
|
-
tone = "default",
|
|
1738
|
-
backgroundImage,
|
|
1739
|
-
overlay = true,
|
|
1740
|
-
testId
|
|
1741
|
-
}) {
|
|
1742
|
-
const onImage = Boolean(backgroundImage);
|
|
1743
|
-
const subtle = onImage ? "text-white/80" : tone === "default" ? "text-primary-foreground/80" : tone === "ink" ? "text-background/70" : "text-muted-foreground";
|
|
1744
|
-
const bgStyle = backgroundImage ? {
|
|
1745
|
-
backgroundImage: `url("${backgroundImage}")`,
|
|
1746
|
-
backgroundSize: "cover",
|
|
1747
|
-
backgroundPosition: "center"
|
|
1748
|
-
} : void 0;
|
|
1749
|
-
return /* @__PURE__ */ jsxs(
|
|
1750
|
-
"div",
|
|
1751
|
-
{
|
|
1752
|
-
className: cn(
|
|
1753
|
-
"relative isolate overflow-hidden rounded-2xl px-8 py-14 text-center",
|
|
1754
|
-
onImage ? "text-white" : TONE_SURFACE2[tone] ?? TONE_SURFACE2.default
|
|
1755
|
-
),
|
|
1756
|
-
style: bgStyle,
|
|
1757
|
-
"data-testid": testId,
|
|
1758
|
-
children: [
|
|
1759
|
-
onImage && overlay && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-black/55", "aria-hidden": true }),
|
|
1760
|
-
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
1761
|
-
/* @__PURE__ */ jsx("h2", { className: "text-3xl font-semibold tracking-tight text-balance sm:text-4xl", children: title }),
|
|
1762
|
-
subtitle && /* @__PURE__ */ jsx("p", { className: cn("mx-auto mt-4 max-w-2xl text-lg", subtle), children: subtitle }),
|
|
1763
|
-
cta?.label && /* @__PURE__ */ jsx("div", { className: "mt-8", children: /* @__PURE__ */ jsx(
|
|
1764
|
-
Button,
|
|
1765
|
-
{
|
|
1766
|
-
asChild: true,
|
|
1767
|
-
size: "lg",
|
|
1768
|
-
variant: tone === "default" && !onImage ? "secondary" : "default",
|
|
1769
|
-
children: /* @__PURE__ */ jsxs("a", { href: cta.href || "#", children: [
|
|
1770
|
-
cta.label,
|
|
1771
|
-
/* @__PURE__ */ jsx(ArrowRight, { className: "size-4" })
|
|
1772
|
-
] })
|
|
1773
|
-
}
|
|
1774
|
-
) })
|
|
1775
|
-
] })
|
|
1776
|
-
]
|
|
1777
|
-
}
|
|
1778
|
-
);
|
|
1779
|
-
}
|
|
1780
|
-
function LogoCloud({ items, testId }) {
|
|
1781
|
-
return /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center justify-center gap-4", "data-testid": testId, children: (items ?? []).map((item, i) => /* @__PURE__ */ jsx(
|
|
1782
|
-
"span",
|
|
1783
|
-
{
|
|
1784
|
-
className: "rounded-md border border-border bg-muted px-5 py-2.5 text-sm font-semibold uppercase tracking-wide text-muted-foreground",
|
|
1785
|
-
"data-testid": testId && `${testId}-item-${i}`,
|
|
1786
|
-
children: item.label
|
|
1787
|
-
},
|
|
1788
|
-
i
|
|
1789
|
-
)) });
|
|
1790
|
-
}
|
|
1791
|
-
function FAQ({ items, testId }) {
|
|
1792
|
-
return /* @__PURE__ */ jsx("div", { className: "mx-auto max-w-3xl divide-y divide-border", "data-testid": testId, children: (items ?? []).map((item, i) => /* @__PURE__ */ jsxs("details", { className: "group py-4", "data-testid": testId && `${testId}-item-${i}`, children: [
|
|
1793
|
-
/* @__PURE__ */ jsxs("summary", { className: "flex cursor-pointer list-none items-center justify-between gap-4 text-left text-base font-medium", children: [
|
|
1794
|
-
item.question,
|
|
1795
|
-
/* @__PURE__ */ jsx(ChevronDown, { className: "size-4 shrink-0 text-muted-foreground transition-transform group-open:rotate-180" })
|
|
1796
|
-
] }),
|
|
1797
|
-
item.answer && /* @__PURE__ */ jsx("p", { className: "mt-3 text-sm leading-relaxed text-muted-foreground", children: item.answer })
|
|
1798
|
-
] }, i)) });
|
|
1799
|
-
}
|
|
1800
|
-
function RichTextBlock({ content, testId }) {
|
|
1801
|
-
return /* @__PURE__ */ jsx("div", { className: "mx-auto max-w-3xl", "data-testid": testId, children: /* @__PURE__ */ jsx(AiMarkdown, { children: content ?? "" }) });
|
|
1802
|
-
}
|
|
1803
|
-
var STYLES = {
|
|
1804
|
-
info: { wrap: "border-primary/30 bg-primary/5", icon: "text-primary", Icon: Info },
|
|
1805
|
-
success: { wrap: "border-success/30 bg-success/10", icon: "text-success", Icon: CheckCircle2 },
|
|
1806
|
-
warning: { wrap: "border-warning/40 bg-warning/10", icon: "text-warning", Icon: AlertTriangle },
|
|
1807
|
-
danger: {
|
|
1808
|
-
wrap: "border-destructive/30 bg-destructive/10",
|
|
1809
|
-
icon: "text-destructive",
|
|
1810
|
-
Icon: XCircle
|
|
1811
|
-
}
|
|
1812
|
-
};
|
|
1813
|
-
function Callout({ variant = "info", title, body, testId }) {
|
|
1814
|
-
const style = STYLES[variant] ?? STYLES.info;
|
|
1815
|
-
const Icon = style.Icon;
|
|
1816
|
-
return /* @__PURE__ */ jsxs(
|
|
1817
|
-
"div",
|
|
1818
|
-
{
|
|
1819
|
-
className: cn("flex gap-3 rounded-lg border p-4 text-foreground", style.wrap),
|
|
1820
|
-
"data-testid": testId,
|
|
1821
|
-
role: "note",
|
|
1822
|
-
children: [
|
|
1823
|
-
/* @__PURE__ */ jsx(Icon, { className: cn("mt-0.5 size-5 shrink-0", style.icon), "aria-hidden": true }),
|
|
1824
|
-
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
1825
|
-
title && /* @__PURE__ */ jsx("p", { className: "font-semibold", children: title }),
|
|
1826
|
-
body && /* @__PURE__ */ jsx("p", { className: "text-sm leading-relaxed text-muted-foreground", children: body })
|
|
1827
|
-
] })
|
|
1828
|
-
]
|
|
1829
|
-
}
|
|
1830
|
-
);
|
|
1831
|
-
}
|
|
1832
|
-
var SIZE = {
|
|
1833
|
-
sm: "size-8 text-xs",
|
|
1834
|
-
md: "size-10 text-sm",
|
|
1835
|
-
lg: "size-14 text-base",
|
|
1836
|
-
xl: "size-20 text-xl"
|
|
1837
|
-
};
|
|
1838
|
-
function AvatarBlock({ src, name = "", size = "md", testId }) {
|
|
1839
|
-
return /* @__PURE__ */ jsxs(Avatar, { className: cn(SIZE[size] ?? SIZE.md), "data-testid": testId, children: [
|
|
1840
|
-
src && /* @__PURE__ */ jsx(AvatarImage, { src, alt: name }),
|
|
1841
|
-
/* @__PURE__ */ jsx(AvatarFallback, { className: "font-semibold", children: initials(name || "?") })
|
|
1842
|
-
] });
|
|
1843
|
-
}
|
|
1844
|
-
function Navbar({ brand, links, cta, testId }) {
|
|
1845
|
-
return /* @__PURE__ */ jsx("header", { className: "border-b border-border bg-background", "data-testid": testId, children: /* @__PURE__ */ jsxs("nav", { className: "mx-auto flex max-w-7xl items-center justify-between gap-6 px-5 py-4 lg:px-8", children: [
|
|
1846
|
-
/* @__PURE__ */ jsx("span", { className: "text-lg font-semibold tracking-tight", children: brand }),
|
|
1847
|
-
/* @__PURE__ */ jsx("div", { className: "hidden items-center gap-6 md:flex", children: (links ?? []).map((link, i) => /* @__PURE__ */ jsx(
|
|
1848
|
-
"a",
|
|
1849
|
-
{
|
|
1850
|
-
href: link.href || "#",
|
|
1851
|
-
className: "text-sm font-medium text-muted-foreground transition-colors hover:text-foreground",
|
|
1852
|
-
"data-testid": testId && `${testId}-link-${i}`,
|
|
1853
|
-
children: link.label
|
|
1854
|
-
},
|
|
1855
|
-
i
|
|
1856
|
-
)) }),
|
|
1857
|
-
cta?.label && /* @__PURE__ */ jsx(Button, { asChild: true, size: "sm", children: /* @__PURE__ */ jsx("a", { href: cta.href || "#", children: cta.label }) })
|
|
1858
|
-
] }) });
|
|
1859
|
-
}
|
|
1860
|
-
function Footer({ columns, copyright, testId }) {
|
|
1861
|
-
return /* @__PURE__ */ jsx("footer", { className: "border-t border-border bg-muted text-foreground", "data-testid": testId, children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-7xl px-5 py-14 lg:px-8", children: [
|
|
1862
|
-
/* @__PURE__ */ jsx("div", { className: "grid gap-8 sm:grid-cols-2 lg:grid-cols-4", children: (columns ?? []).map((col, i) => /* @__PURE__ */ jsxs("div", { "data-testid": testId && `${testId}-col-${i}`, children: [
|
|
1863
|
-
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold tracking-tight", children: col.heading }),
|
|
1864
|
-
/* @__PURE__ */ jsx("ul", { className: "mt-4 space-y-2", children: (col.links ?? []).map((link, j) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
|
|
1865
|
-
"a",
|
|
1866
|
-
{
|
|
1867
|
-
href: link.href || "#",
|
|
1868
|
-
className: "text-sm text-muted-foreground transition-colors hover:text-foreground",
|
|
1869
|
-
children: link.label
|
|
1870
|
-
}
|
|
1871
|
-
) }, j)) })
|
|
1872
|
-
] }, i)) }),
|
|
1873
|
-
copyright && /* @__PURE__ */ jsx("p", { className: "mt-12 border-t border-border pt-6 text-sm text-muted-foreground", children: copyright })
|
|
1874
|
-
] }) });
|
|
1875
|
-
}
|
|
1876
|
-
function ListBlock({ ordered = false, items, testId }) {
|
|
1877
|
-
const list = items ?? [];
|
|
1878
|
-
const className = cn(
|
|
1879
|
-
"mx-auto max-w-3xl space-y-2 pl-5 text-foreground",
|
|
1880
|
-
ordered ? "list-decimal" : "list-disc"
|
|
1881
|
-
);
|
|
1882
|
-
const content = list.map((item, i) => /* @__PURE__ */ jsx("li", { className: "leading-relaxed marker:text-muted-foreground", children: item.text }, i));
|
|
1883
|
-
return ordered ? /* @__PURE__ */ jsx("ol", { className, "data-testid": testId, children: content }) : /* @__PURE__ */ jsx("ul", { className, "data-testid": testId, children: content });
|
|
1884
|
-
}
|
|
1885
|
-
var GRID2 = {
|
|
1886
|
-
2: "sm:grid-cols-2",
|
|
1887
|
-
3: "sm:grid-cols-2 lg:grid-cols-3",
|
|
1888
|
-
4: "sm:grid-cols-2 lg:grid-cols-4"
|
|
1889
|
-
};
|
|
1890
|
-
var GAP = {
|
|
1891
|
-
sm: "gap-3",
|
|
1892
|
-
md: "gap-6",
|
|
1893
|
-
lg: "gap-10"
|
|
1894
|
-
};
|
|
1895
|
-
function Columns({ count = 3, gap = "md", columns, testId }) {
|
|
1896
|
-
return /* @__PURE__ */ jsx(
|
|
1897
|
-
"div",
|
|
1898
|
-
{
|
|
1899
|
-
className: cn("grid grid-cols-1", GRID2[count] ?? GRID2[3], GAP[gap] ?? GAP.md),
|
|
1900
|
-
"data-testid": testId,
|
|
1901
|
-
children: columns.map((col, i) => /* @__PURE__ */ jsx("div", { "data-testid": testId && `${testId}-col-${i}`, children: col }, i))
|
|
1902
|
-
}
|
|
1903
|
-
);
|
|
1904
|
-
}
|
|
1905
|
-
var SIZE2 = {
|
|
1906
|
-
sm: "h-4",
|
|
1907
|
-
md: "h-8",
|
|
1908
|
-
lg: "h-16",
|
|
1909
|
-
xl: "h-24"
|
|
1910
|
-
};
|
|
1911
|
-
function Spacer({ size = "md", testId }) {
|
|
1912
|
-
return /* @__PURE__ */ jsx("div", { className: cn("w-full", SIZE2[size] ?? SIZE2.md), "data-testid": testId, "aria-hidden": true });
|
|
1913
|
-
}
|
|
1914
|
-
var WIDTH = {
|
|
1915
|
-
narrow: "max-w-3xl",
|
|
1916
|
-
default: "max-w-5xl",
|
|
1917
|
-
wide: "max-w-7xl",
|
|
1918
|
-
full: "max-w-none"
|
|
1919
|
-
};
|
|
1920
|
-
var PADDING = {
|
|
1921
|
-
none: "px-0 py-0",
|
|
1922
|
-
sm: "px-4 py-6",
|
|
1923
|
-
md: "px-5 py-12 lg:px-8",
|
|
1924
|
-
lg: "px-5 py-20 lg:px-8"
|
|
1925
|
-
};
|
|
1926
|
-
function Container({ width = "default", padding = "md", children, testId }) {
|
|
1927
|
-
return /* @__PURE__ */ jsx(
|
|
1928
|
-
"div",
|
|
1929
|
-
{
|
|
1930
|
-
className: cn(
|
|
1931
|
-
"mx-auto w-full",
|
|
1932
|
-
WIDTH[width] ?? WIDTH.default,
|
|
1933
|
-
PADDING[padding] ?? PADDING.md
|
|
1934
|
-
),
|
|
1935
|
-
"data-testid": testId,
|
|
1936
|
-
children
|
|
1937
|
-
}
|
|
1938
|
-
);
|
|
1939
|
-
}
|
|
1940
|
-
function PricingTable({ plans, testId }) {
|
|
1941
|
-
return /* @__PURE__ */ jsx(
|
|
1942
|
-
"div",
|
|
1943
|
-
{
|
|
1944
|
-
className: cn("grid gap-6", (plans?.length ?? 0) >= 3 ? "md:grid-cols-3" : "sm:grid-cols-2"),
|
|
1945
|
-
"data-testid": testId,
|
|
1946
|
-
children: (plans ?? []).map((plan, i) => /* @__PURE__ */ jsxs(
|
|
1947
|
-
Card,
|
|
1948
|
-
{
|
|
1949
|
-
variant: plan.featured ? "elevated" : "outline",
|
|
1950
|
-
className: cn("flex h-full flex-col p-6", plan.featured && "ring-2 ring-primary"),
|
|
1951
|
-
"data-testid": testId && `${testId}-item-${i}`,
|
|
1952
|
-
children: [
|
|
1953
|
-
/* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold tracking-tight", children: plan.name }),
|
|
1954
|
-
/* @__PURE__ */ jsxs("div", { className: "mt-3 flex items-baseline gap-1", children: [
|
|
1955
|
-
/* @__PURE__ */ jsx("span", { className: "text-3xl font-semibold tracking-tight", children: plan.price }),
|
|
1956
|
-
plan.period && /* @__PURE__ */ jsxs("span", { className: "text-sm text-muted-foreground", children: [
|
|
1957
|
-
"/",
|
|
1958
|
-
plan.period
|
|
1959
|
-
] })
|
|
1960
|
-
] }),
|
|
1961
|
-
plan.description && /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm leading-relaxed text-muted-foreground", children: plan.description }),
|
|
1962
|
-
plan.features && plan.features.length > 0 && /* @__PURE__ */ jsx("ul", { className: "mt-5 flex-1 space-y-2", children: plan.features.map((f, j) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-2 text-sm", children: [
|
|
1963
|
-
/* @__PURE__ */ jsx(Check, { className: "mt-0.5 size-4 shrink-0 text-primary" }),
|
|
1964
|
-
/* @__PURE__ */ jsx("span", { children: f })
|
|
1965
|
-
] }, j)) }),
|
|
1966
|
-
plan.cta?.label && /* @__PURE__ */ jsx(Button, { asChild: true, className: "mt-6 w-full", variant: plan.featured ? "default" : "outline", children: /* @__PURE__ */ jsx("a", { href: plan.cta.href || "#", children: plan.cta.label }) })
|
|
1967
|
-
]
|
|
1968
|
-
},
|
|
1969
|
-
i
|
|
1970
|
-
))
|
|
1971
|
-
}
|
|
1972
|
-
);
|
|
1973
|
-
}
|
|
1974
|
-
function Tabs({ items, testId }) {
|
|
1975
|
-
const [active, setActive] = useState(0);
|
|
1976
|
-
const list = items ?? [];
|
|
1977
|
-
const current = list[Math.min(active, Math.max(list.length - 1, 0))];
|
|
1978
|
-
return /* @__PURE__ */ jsxs("div", { "data-testid": testId, children: [
|
|
1979
|
-
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1 border-b border-border", role: "tablist", children: list.map((t, i) => {
|
|
1980
|
-
const selected = i === active;
|
|
1981
|
-
return /* @__PURE__ */ jsx(
|
|
1982
|
-
"button",
|
|
1983
|
-
{
|
|
1984
|
-
type: "button",
|
|
1985
|
-
role: "tab",
|
|
1986
|
-
"aria-selected": selected,
|
|
1987
|
-
onClick: () => setActive(i),
|
|
1988
|
-
className: cn(
|
|
1989
|
-
"-mb-px border-b-2 px-4 py-2 text-sm font-medium transition-colors",
|
|
1990
|
-
selected ? "border-primary text-foreground" : "border-transparent text-muted-foreground hover:text-foreground"
|
|
1991
|
-
),
|
|
1992
|
-
"data-testid": testId && `${testId}-tab-${i}`,
|
|
1993
|
-
children: t.label
|
|
1994
|
-
},
|
|
1995
|
-
i
|
|
1996
|
-
);
|
|
1997
|
-
}) }),
|
|
1998
|
-
current && /* @__PURE__ */ jsx(
|
|
1999
|
-
"div",
|
|
2000
|
-
{
|
|
2001
|
-
role: "tabpanel",
|
|
2002
|
-
className: "pt-5 text-sm leading-relaxed text-muted-foreground",
|
|
2003
|
-
"data-testid": testId && `${testId}-panel`,
|
|
2004
|
-
children: current.content
|
|
2005
|
-
}
|
|
2006
|
-
)
|
|
2007
|
-
] });
|
|
2008
|
-
}
|
|
2009
|
-
function Accordion({ items, allowMultiple = false, testId }) {
|
|
2010
|
-
const [open, setOpen] = useState([]);
|
|
2011
|
-
const toggle2 = (i) => setOpen(
|
|
2012
|
-
(prev) => prev.includes(i) ? prev.filter((n) => n !== i) : allowMultiple ? [...prev, i] : [i]
|
|
2013
|
-
);
|
|
2014
|
-
return /* @__PURE__ */ jsx("div", { className: "divide-y divide-border border-y border-border", "data-testid": testId, children: (items ?? []).map((item, i) => {
|
|
2015
|
-
const isOpen = open.includes(i);
|
|
2016
|
-
return /* @__PURE__ */ jsxs("div", { "data-testid": testId && `${testId}-item-${i}`, children: [
|
|
2017
|
-
/* @__PURE__ */ jsxs(
|
|
2018
|
-
"button",
|
|
2019
|
-
{
|
|
2020
|
-
type: "button",
|
|
2021
|
-
"aria-expanded": isOpen,
|
|
2022
|
-
onClick: () => toggle2(i),
|
|
2023
|
-
className: "flex w-full items-center justify-between gap-4 py-4 text-left text-base font-medium",
|
|
2024
|
-
"data-testid": testId && `${testId}-trigger-${i}`,
|
|
2025
|
-
children: [
|
|
2026
|
-
item.title,
|
|
2027
|
-
/* @__PURE__ */ jsx(
|
|
2028
|
-
ChevronDown,
|
|
2029
|
-
{
|
|
2030
|
-
className: cn("size-4 shrink-0 transition-transform", isOpen && "rotate-180")
|
|
2031
|
-
}
|
|
2032
|
-
)
|
|
2033
|
-
]
|
|
2034
|
-
}
|
|
2035
|
-
),
|
|
2036
|
-
isOpen && /* @__PURE__ */ jsx(
|
|
2037
|
-
"p",
|
|
2038
|
-
{
|
|
2039
|
-
className: "pb-4 text-sm leading-relaxed text-muted-foreground",
|
|
2040
|
-
"data-testid": testId && `${testId}-content-${i}`,
|
|
2041
|
-
children: item.content
|
|
2042
|
-
}
|
|
2043
|
-
)
|
|
2044
|
-
] }, i);
|
|
2045
|
-
}) });
|
|
2046
|
-
}
|
|
2047
|
-
var COLS2 = {
|
|
2048
|
-
"2": "grid-cols-2",
|
|
2049
|
-
"3": "grid-cols-2 sm:grid-cols-3",
|
|
2050
|
-
"4": "grid-cols-2 sm:grid-cols-4"
|
|
2051
|
-
};
|
|
2052
|
-
function Gallery({
|
|
2053
|
-
images,
|
|
2054
|
-
columns = "3",
|
|
2055
|
-
aspect = "1:1",
|
|
2056
|
-
rounded = "lg",
|
|
2057
|
-
testId
|
|
2058
|
-
}) {
|
|
2059
|
-
return /* @__PURE__ */ jsx("div", { className: cn("grid gap-4", COLS2[columns] ?? COLS2["3"]), "data-testid": testId, children: (images ?? []).map((img, i) => /* @__PURE__ */ jsxs("figure", { "data-testid": testId && `${testId}-item-${i}`, children: [
|
|
2060
|
-
/* @__PURE__ */ jsx(
|
|
2061
|
-
BlockImage,
|
|
2062
|
-
{
|
|
2063
|
-
src: img.src,
|
|
2064
|
-
alt: img.alt,
|
|
2065
|
-
aspect,
|
|
2066
|
-
rounded,
|
|
2067
|
-
testId: testId && `${testId}-item-${i}-image`
|
|
2068
|
-
}
|
|
2069
|
-
),
|
|
2070
|
-
img.caption && /* @__PURE__ */ jsx("figcaption", { className: "mt-1.5 text-xs text-muted-foreground", children: img.caption })
|
|
2071
|
-
] }, i)) });
|
|
2072
|
-
}
|
|
2073
|
-
var ASPECT2 = {
|
|
2074
|
-
"16:9": "aspect-video",
|
|
2075
|
-
"4:3": "aspect-[4/3]",
|
|
2076
|
-
"1:1": "aspect-square"
|
|
2077
|
-
};
|
|
2078
|
-
function toEmbedUrl(url) {
|
|
2079
|
-
if (!url) return null;
|
|
2080
|
-
const yt = url.match(/(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/)([\w-]{11})/);
|
|
2081
|
-
if (yt) return `https://www.youtube.com/embed/${yt[1]}`;
|
|
2082
|
-
const vimeo = url.match(/vimeo\.com\/(?:video\/)?(\d+)/);
|
|
2083
|
-
if (vimeo) return `https://player.vimeo.com/video/${vimeo[1]}`;
|
|
2084
|
-
const loom = url.match(/loom\.com\/(?:share|embed)\/([\w-]+)/);
|
|
2085
|
-
if (loom) return `https://www.loom.com/embed/${loom[1]}`;
|
|
2086
|
-
return null;
|
|
2087
|
-
}
|
|
2088
|
-
function VideoEmbed({
|
|
2089
|
-
url,
|
|
2090
|
-
title,
|
|
2091
|
-
aspect = "16:9",
|
|
2092
|
-
rounded = true,
|
|
2093
|
-
testId
|
|
2094
|
-
}) {
|
|
2095
|
-
const embed = toEmbedUrl(url);
|
|
2096
|
-
const frame = cn(
|
|
2097
|
-
"w-full overflow-hidden border border-border bg-muted",
|
|
2098
|
-
ASPECT2[aspect] ?? ASPECT2["16:9"],
|
|
2099
|
-
rounded && "rounded-lg"
|
|
2100
|
-
);
|
|
2101
|
-
return /* @__PURE__ */ jsx("div", { className: frame, "data-testid": testId, children: embed ? /* @__PURE__ */ jsx(
|
|
2102
|
-
"iframe",
|
|
2103
|
-
{
|
|
2104
|
-
src: embed,
|
|
2105
|
-
title: title || "Embedded video",
|
|
2106
|
-
className: "size-full",
|
|
2107
|
-
allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",
|
|
2108
|
-
allowFullScreen: true,
|
|
2109
|
-
"data-testid": testId && `${testId}-iframe`
|
|
873
|
+
...combinedOptions
|
|
2110
874
|
}
|
|
2111
|
-
)
|
|
875
|
+
) });
|
|
2112
876
|
}
|
|
2113
|
-
function
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
877
|
+
function UploadDropzone({
|
|
878
|
+
onFiles,
|
|
879
|
+
accept,
|
|
880
|
+
multiple = true,
|
|
881
|
+
disabled = false,
|
|
882
|
+
uploading = false,
|
|
883
|
+
title = "Drag files here",
|
|
884
|
+
description = "or click to browse",
|
|
885
|
+
hint,
|
|
886
|
+
uploadingLabel = "Uploading\u2026",
|
|
887
|
+
icon: Icon = UploadCloud,
|
|
888
|
+
testId,
|
|
889
|
+
className
|
|
2119
890
|
}) {
|
|
2120
|
-
const
|
|
2121
|
-
const
|
|
2122
|
-
const
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
891
|
+
const inputRef = useRef(null);
|
|
892
|
+
const [dragOver, setDragOver] = useState(false);
|
|
893
|
+
const inert = disabled || uploading;
|
|
894
|
+
const pick = (files) => {
|
|
895
|
+
if (!files?.length) return;
|
|
896
|
+
onFiles(Array.from(files));
|
|
897
|
+
};
|
|
898
|
+
const onDrop = (e) => {
|
|
899
|
+
e.preventDefault();
|
|
900
|
+
setDragOver(false);
|
|
901
|
+
if (inert) return;
|
|
902
|
+
pick(e.dataTransfer.files);
|
|
903
|
+
};
|
|
904
|
+
const onDragOver = (e) => {
|
|
905
|
+
e.preventDefault();
|
|
906
|
+
if (!inert) setDragOver(true);
|
|
2127
907
|
};
|
|
2128
|
-
if (sent) {
|
|
2129
|
-
return /* @__PURE__ */ jsx(
|
|
2130
|
-
"p",
|
|
2131
|
-
{
|
|
2132
|
-
className: "rounded-lg border border-border bg-muted p-6 text-center text-sm text-foreground",
|
|
2133
|
-
role: "status",
|
|
2134
|
-
"data-testid": testId && `${testId}-success`,
|
|
2135
|
-
children: successMessage
|
|
2136
|
-
}
|
|
2137
|
-
);
|
|
2138
|
-
}
|
|
2139
908
|
return /* @__PURE__ */ jsxs(
|
|
2140
|
-
"
|
|
909
|
+
"button",
|
|
2141
910
|
{
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
911
|
+
type: "button",
|
|
912
|
+
onClick: () => !inert && inputRef.current?.click(),
|
|
913
|
+
onDrop,
|
|
914
|
+
onDragOver,
|
|
915
|
+
onDragLeave: () => setDragOver(false),
|
|
916
|
+
disabled: inert,
|
|
2146
917
|
"data-testid": testId,
|
|
918
|
+
className: cn(
|
|
919
|
+
"flex w-full flex-col items-center justify-center gap-3 rounded-xl border-2 border-dashed border-border bg-muted/30 px-6 py-12 text-center transition-colors",
|
|
920
|
+
"hover:border-primary/50 hover:bg-muted/50",
|
|
921
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
922
|
+
dragOver && "border-primary bg-primary/5",
|
|
923
|
+
inert && "cursor-not-allowed opacity-60 hover:border-border hover:bg-muted/30",
|
|
924
|
+
className
|
|
925
|
+
),
|
|
2147
926
|
children: [
|
|
2148
|
-
list.map((f, i) => {
|
|
2149
|
-
const inputClass = "w-full rounded-md border border-border bg-card px-3 py-2 text-sm text-foreground outline-none focus:border-primary";
|
|
2150
|
-
return /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1.5 text-left", children: [
|
|
2151
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: f.label }),
|
|
2152
|
-
f.type === "textarea" ? /* @__PURE__ */ jsx(
|
|
2153
|
-
"textarea",
|
|
2154
|
-
{
|
|
2155
|
-
name: f.name,
|
|
2156
|
-
required: f.required,
|
|
2157
|
-
rows: 4,
|
|
2158
|
-
className: inputClass,
|
|
2159
|
-
"data-testid": testId && `${testId}-field-${f.name}`
|
|
2160
|
-
}
|
|
2161
|
-
) : /* @__PURE__ */ jsx(
|
|
2162
|
-
"input",
|
|
2163
|
-
{
|
|
2164
|
-
name: f.name,
|
|
2165
|
-
type: f.type || "text",
|
|
2166
|
-
required: f.required,
|
|
2167
|
-
className: inputClass,
|
|
2168
|
-
"data-testid": testId && `${testId}-field-${f.name}`
|
|
2169
|
-
}
|
|
2170
|
-
)
|
|
2171
|
-
] }, i);
|
|
2172
|
-
}),
|
|
2173
927
|
/* @__PURE__ */ jsx(
|
|
2174
|
-
|
|
928
|
+
"input",
|
|
2175
929
|
{
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
930
|
+
ref: inputRef,
|
|
931
|
+
type: "file",
|
|
932
|
+
accept,
|
|
933
|
+
multiple,
|
|
934
|
+
className: "hidden",
|
|
935
|
+
onChange: (e) => {
|
|
936
|
+
pick(e.target.files);
|
|
937
|
+
if (inputRef.current) inputRef.current.value = "";
|
|
938
|
+
},
|
|
939
|
+
"data-testid": testId ? `${testId}-input` : void 0
|
|
2180
940
|
}
|
|
2181
|
-
)
|
|
941
|
+
),
|
|
942
|
+
/* @__PURE__ */ jsx("div", { className: "flex size-12 items-center justify-center rounded-full bg-primary/10 text-primary", children: uploading ? /* @__PURE__ */ jsx(Loader2, { className: "size-6 animate-spin" }) : /* @__PURE__ */ jsx(Icon, { className: "size-6" }) }),
|
|
943
|
+
uploading ? /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-foreground", children: uploadingLabel }) : /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
944
|
+
/* @__PURE__ */ jsxs("p", { className: "text-sm font-medium text-foreground", children: [
|
|
945
|
+
title,
|
|
946
|
+
" ",
|
|
947
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: description })
|
|
948
|
+
] }),
|
|
949
|
+
hint && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: hint })
|
|
950
|
+
] })
|
|
2182
951
|
]
|
|
2183
952
|
}
|
|
2184
953
|
);
|
|
2185
954
|
}
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
955
|
+
function PageHeader({
|
|
956
|
+
title,
|
|
957
|
+
eyebrow,
|
|
958
|
+
description,
|
|
959
|
+
actions,
|
|
960
|
+
className,
|
|
961
|
+
testId
|
|
962
|
+
}) {
|
|
2192
963
|
return /* @__PURE__ */ jsxs(
|
|
2193
964
|
"div",
|
|
2194
965
|
{
|
|
2195
|
-
className: cn("
|
|
966
|
+
className: cn("flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between", className),
|
|
2196
967
|
"data-testid": testId,
|
|
2197
968
|
children: [
|
|
2198
|
-
/* @__PURE__ */
|
|
2199
|
-
|
|
2200
|
-
"
|
|
2201
|
-
{
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
"data-testid": testId && `${testId}-cta`,
|
|
2205
|
-
children: [
|
|
2206
|
-
cta.label,
|
|
2207
|
-
/* @__PURE__ */ jsx(ArrowRight, { className: "size-3.5" })
|
|
2208
|
-
]
|
|
2209
|
-
}
|
|
2210
|
-
)
|
|
969
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
970
|
+
eyebrow && /* @__PURE__ */ jsx("p", { className: "mb-1 text-xs font-semibold uppercase tracking-wider text-muted-foreground", children: eyebrow }),
|
|
971
|
+
/* @__PURE__ */ jsx("h1", { className: "font-display text-2xl font-semibold tracking-tight text-foreground", children: title }),
|
|
972
|
+
description && /* @__PURE__ */ jsx("p", { className: "mt-1 max-w-2xl text-sm text-muted-foreground", children: description })
|
|
973
|
+
] }),
|
|
974
|
+
actions && /* @__PURE__ */ jsx("div", { className: "flex shrink-0 items-center gap-2", children: actions })
|
|
2211
975
|
]
|
|
2212
976
|
}
|
|
2213
977
|
);
|
|
2214
978
|
}
|
|
2215
|
-
function
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
979
|
+
function Toolbar({
|
|
980
|
+
search,
|
|
981
|
+
onSearch,
|
|
982
|
+
searchPlaceholder = "Search\u2026",
|
|
983
|
+
filters,
|
|
984
|
+
actions,
|
|
985
|
+
className,
|
|
2222
986
|
testId
|
|
2223
987
|
}) {
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
eyebrow && /* @__PURE__ */ jsx("p", { className: "mb-3 text-xs font-semibold uppercase tracking-wider text-muted-foreground", children: eyebrow }),
|
|
2227
|
-
/* @__PURE__ */ jsx("h2", { className: "text-3xl font-semibold tracking-tight text-balance", children: title }),
|
|
2228
|
-
body && /* @__PURE__ */ jsx("p", { className: "mt-4 text-lg leading-relaxed text-muted-foreground", children: body }),
|
|
2229
|
-
cta?.label && /* @__PURE__ */ jsx(Button, { asChild: true, className: "mt-6", children: /* @__PURE__ */ jsxs("a", { href: cta.href || "#", children: [
|
|
2230
|
-
cta.label,
|
|
2231
|
-
/* @__PURE__ */ jsx(ArrowRight, { className: "size-4" })
|
|
2232
|
-
] }) })
|
|
2233
|
-
] });
|
|
2234
|
-
return /* @__PURE__ */ jsx("div", { className: "grid items-center gap-10 lg:grid-cols-2", "data-testid": testId, children: mediaSide === "right" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2235
|
-
copy,
|
|
2236
|
-
media
|
|
2237
|
-
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2238
|
-
media,
|
|
2239
|
-
copy
|
|
2240
|
-
] }) });
|
|
2241
|
-
}
|
|
2242
|
-
var COLS3 = {
|
|
2243
|
-
"2": "sm:grid-cols-2",
|
|
2244
|
-
"3": "sm:grid-cols-2 lg:grid-cols-3",
|
|
2245
|
-
"4": "sm:grid-cols-2 lg:grid-cols-4"
|
|
2246
|
-
};
|
|
2247
|
-
function TeamGrid({ members, columns = "3", testId }) {
|
|
2248
|
-
return /* @__PURE__ */ jsx("div", { className: cn("grid gap-6", COLS3[columns] ?? COLS3["3"]), "data-testid": testId, children: (members ?? []).map((m, i) => /* @__PURE__ */ jsxs(
|
|
2249
|
-
Card,
|
|
988
|
+
return /* @__PURE__ */ jsxs(
|
|
989
|
+
"div",
|
|
2250
990
|
{
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
991
|
+
className: cn(
|
|
992
|
+
"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between",
|
|
993
|
+
className
|
|
994
|
+
),
|
|
995
|
+
"data-testid": testId,
|
|
2254
996
|
children: [
|
|
2255
|
-
/* @__PURE__ */ jsxs(
|
|
2256
|
-
|
|
2257
|
-
|
|
997
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-wrap items-center gap-2", children: [
|
|
998
|
+
onSearch && /* @__PURE__ */ jsxs("div", { className: "relative w-full max-w-xs", children: [
|
|
999
|
+
/* @__PURE__ */ jsx(Search, { className: "pointer-events-none absolute left-2.5 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" }),
|
|
1000
|
+
/* @__PURE__ */ jsx(
|
|
1001
|
+
Input,
|
|
1002
|
+
{
|
|
1003
|
+
value: search,
|
|
1004
|
+
onChange: (e) => onSearch(e.target.value),
|
|
1005
|
+
placeholder: searchPlaceholder,
|
|
1006
|
+
className: "bg-card text-sm placeholder:text-muted-foreground/70 focus-visible:border-ring/60 focus-visible:ring-2 focus-visible:ring-ring/50 pl-8",
|
|
1007
|
+
"data-testid": testId ? `${testId}-search` : "toolbar-search"
|
|
1008
|
+
}
|
|
1009
|
+
)
|
|
1010
|
+
] }),
|
|
1011
|
+
filters
|
|
2258
1012
|
] }),
|
|
2259
|
-
/* @__PURE__ */ jsx("
|
|
2260
|
-
m.role && /* @__PURE__ */ jsx("p", { className: "text-sm text-primary", children: m.role }),
|
|
2261
|
-
m.bio && /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm leading-relaxed text-muted-foreground", children: m.bio })
|
|
1013
|
+
actions && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: actions })
|
|
2262
1014
|
]
|
|
2263
|
-
},
|
|
2264
|
-
i
|
|
2265
|
-
)) });
|
|
2266
|
-
}
|
|
2267
|
-
function Steps({ steps, variant = "numbered", testId }) {
|
|
2268
|
-
const list = steps ?? [];
|
|
2269
|
-
if (variant === "timeline") {
|
|
2270
|
-
return /* @__PURE__ */ jsx("ol", { className: "relative ml-3 border-l border-border", "data-testid": testId, children: list.map((s, i) => /* @__PURE__ */ jsxs("li", { className: "mb-8 ml-6 last:mb-0", "data-testid": testId && `${testId}-item-${i}`, children: [
|
|
2271
|
-
/* @__PURE__ */ jsx("span", { className: "absolute -left-3 flex size-6 items-center justify-center rounded-full bg-primary text-xs font-semibold text-primary-foreground", children: i + 1 }),
|
|
2272
|
-
/* @__PURE__ */ jsx("h3", { className: "text-base font-semibold tracking-tight", children: s.title }),
|
|
2273
|
-
s.description && /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm leading-relaxed text-muted-foreground", children: s.description })
|
|
2274
|
-
] }, i)) });
|
|
2275
|
-
}
|
|
2276
|
-
return /* @__PURE__ */ jsx(
|
|
2277
|
-
"div",
|
|
2278
|
-
{
|
|
2279
|
-
className: cn("grid gap-6", list.length >= 4 ? "md:grid-cols-4" : "sm:grid-cols-3"),
|
|
2280
|
-
"data-testid": testId,
|
|
2281
|
-
children: list.map((s, i) => /* @__PURE__ */ jsxs("div", { "data-testid": testId && `${testId}-item-${i}`, children: [
|
|
2282
|
-
/* @__PURE__ */ jsx("span", { className: "flex size-9 items-center justify-center rounded-full bg-primary/10 text-sm font-semibold text-primary", children: i + 1 }),
|
|
2283
|
-
/* @__PURE__ */ jsx("h3", { className: "mt-4 text-base font-semibold tracking-tight", children: s.title }),
|
|
2284
|
-
s.description && /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm leading-relaxed text-muted-foreground", children: s.description })
|
|
2285
|
-
] }, i))
|
|
2286
1015
|
}
|
|
2287
1016
|
);
|
|
2288
1017
|
}
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
1018
|
+
function MetricCard({
|
|
1019
|
+
label,
|
|
1020
|
+
value,
|
|
1021
|
+
icon: Icon,
|
|
1022
|
+
hint,
|
|
1023
|
+
delta,
|
|
1024
|
+
accent = "default",
|
|
1025
|
+
testId
|
|
1026
|
+
}) {
|
|
1027
|
+
const accentStyle = accent && accent !== "default" ? { color: `var(--color-${accent})` } : void 0;
|
|
1028
|
+
const deltaGood = delta?.good ?? delta?.direction === "up";
|
|
1029
|
+
return /* @__PURE__ */ jsxs(Card, { variant: "elevated", className: "card-hover rounded-xl p-5", "data-testid": testId, children: [
|
|
1030
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
|
|
1031
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs font-medium uppercase tracking-wide text-muted-foreground", children: label }),
|
|
1032
|
+
Icon && /* @__PURE__ */ jsx(Icon, { className: "size-4 shrink-0", style: accentStyle })
|
|
1033
|
+
] }),
|
|
1034
|
+
/* @__PURE__ */ jsx(
|
|
1035
|
+
"p",
|
|
1036
|
+
{
|
|
1037
|
+
className: "mt-2 font-display text-2xl font-semibold tracking-tight",
|
|
1038
|
+
"data-testid": testId && `${testId}-value`,
|
|
1039
|
+
children: value
|
|
1040
|
+
}
|
|
1041
|
+
),
|
|
1042
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-center gap-2", children: [
|
|
1043
|
+
delta && /* @__PURE__ */ jsxs(
|
|
1044
|
+
"span",
|
|
1045
|
+
{
|
|
1046
|
+
className: cn(
|
|
1047
|
+
"inline-flex items-center gap-0.5 text-xs font-medium",
|
|
1048
|
+
deltaGood ? "text-success" : "text-destructive"
|
|
1049
|
+
),
|
|
1050
|
+
children: [
|
|
1051
|
+
delta.direction === "up" ? /* @__PURE__ */ jsx(ArrowUpRight, { className: "size-3" }) : /* @__PURE__ */ jsx(ArrowDownRight, { className: "size-3" }),
|
|
1052
|
+
delta.value
|
|
1053
|
+
]
|
|
1054
|
+
}
|
|
1055
|
+
),
|
|
1056
|
+
hint && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: hint })
|
|
1057
|
+
] })
|
|
1058
|
+
] });
|
|
1059
|
+
}
|
|
1060
|
+
var MAX_AVATARS = 4;
|
|
1061
|
+
function WorkspaceCard({
|
|
1062
|
+
name,
|
|
1063
|
+
matterRef,
|
|
1064
|
+
description,
|
|
1065
|
+
docCount,
|
|
1066
|
+
memberCount,
|
|
1067
|
+
members = [],
|
|
1068
|
+
updatedAt,
|
|
1069
|
+
active = false,
|
|
1070
|
+
busy = false,
|
|
1071
|
+
onOpen,
|
|
1072
|
+
icon: Icon = FolderLock,
|
|
1073
|
+
testId,
|
|
1074
|
+
buttonTestId,
|
|
1075
|
+
className
|
|
1076
|
+
}) {
|
|
1077
|
+
const totalMembers = memberCount ?? members.length;
|
|
1078
|
+
const shownMembers = members.slice(0, MAX_AVATARS);
|
|
1079
|
+
const extraMembers = totalMembers - shownMembers.length;
|
|
1080
|
+
const btnTestId = buttonTestId ?? (testId ? `${testId}-open` : void 0);
|
|
1081
|
+
return /* @__PURE__ */ jsxs(
|
|
2295
1082
|
Card,
|
|
2296
1083
|
{
|
|
2297
1084
|
variant: "outline",
|
|
2298
|
-
className: "
|
|
2299
|
-
"data-testid": testId
|
|
1085
|
+
className: cn("card-hover flex flex-col p-5", className),
|
|
1086
|
+
"data-testid": testId,
|
|
2300
1087
|
children: [
|
|
2301
|
-
/* @__PURE__ */
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
1088
|
+
/* @__PURE__ */ jsxs(CardHeader, { className: "p-0", children: [
|
|
1089
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
|
|
1090
|
+
/* @__PURE__ */ jsx("div", { className: "flex size-10 shrink-0 items-center justify-center rounded-md bg-primary/10 text-primary", children: /* @__PURE__ */ jsx(Icon, { className: "size-5" }) }),
|
|
1091
|
+
active ? /* @__PURE__ */ jsxs(Badge, { children: [
|
|
1092
|
+
/* @__PURE__ */ jsx(CheckCircle2, { className: "mr-1 size-3" }),
|
|
1093
|
+
" Active"
|
|
1094
|
+
] }) : /* @__PURE__ */ jsx(Badge, { variant: "secondary", children: "Encrypted" })
|
|
1095
|
+
] }),
|
|
1096
|
+
/* @__PURE__ */ jsx(CardTitle, { className: "mt-3 text-base", children: name }),
|
|
1097
|
+
matterRef && /* @__PURE__ */ jsx(CardDescription, { className: "text-xs font-medium uppercase tracking-wide text-muted-foreground", children: matterRef })
|
|
1098
|
+
] }),
|
|
1099
|
+
/* @__PURE__ */ jsxs(CardContent, { className: "mt-3 flex-1 space-y-4 p-0", children: [
|
|
1100
|
+
description && /* @__PURE__ */ jsx("p", { className: "line-clamp-2 text-sm text-muted-foreground", children: description }),
|
|
1101
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 text-sm", children: [
|
|
1102
|
+
/* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5 text-foreground", children: [
|
|
1103
|
+
/* @__PURE__ */ jsx(FileText, { className: "size-4 text-muted-foreground" }),
|
|
1104
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: docCount.toLocaleString() }),
|
|
1105
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "docs" })
|
|
1106
|
+
] }),
|
|
1107
|
+
/* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5 text-foreground", children: [
|
|
1108
|
+
/* @__PURE__ */ jsx(Users, { className: "size-4 text-muted-foreground" }),
|
|
1109
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: totalMembers }),
|
|
1110
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "members" })
|
|
1111
|
+
] })
|
|
2307
1112
|
] }),
|
|
2308
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
2309
|
-
|
|
2310
|
-
|
|
1113
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
|
|
1114
|
+
/* @__PURE__ */ jsxs("div", { className: "flex -space-x-2", children: [
|
|
1115
|
+
shownMembers.map((m, i) => /* @__PURE__ */ jsxs(Avatar, { className: "size-7 border-2 border-card", title: m.name, children: [
|
|
1116
|
+
m.picture && /* @__PURE__ */ jsx(AvatarImage, { src: m.picture, alt: m.name }),
|
|
1117
|
+
/* @__PURE__ */ jsx(AvatarFallback, { className: "bg-foreground text-[10px] font-medium text-background", children: initials(m.name || "?") })
|
|
1118
|
+
] }, i)),
|
|
1119
|
+
extraMembers > 0 && /* @__PURE__ */ jsx(Avatar, { className: "size-7 border-2 border-card", children: /* @__PURE__ */ jsxs(AvatarFallback, { className: "bg-accent text-[10px] font-medium text-muted-foreground", children: [
|
|
1120
|
+
"+",
|
|
1121
|
+
extraMembers
|
|
1122
|
+
] }) })
|
|
1123
|
+
] }),
|
|
1124
|
+
updatedAt && /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", title: fmtDate(updatedAt), children: [
|
|
1125
|
+
"Updated ",
|
|
1126
|
+
fromNow(updatedAt)
|
|
1127
|
+
] })
|
|
2311
1128
|
] })
|
|
2312
|
-
] })
|
|
1129
|
+
] }),
|
|
1130
|
+
/* @__PURE__ */ jsx(CardFooter, { className: "mt-4 p-0", children: active ? /* @__PURE__ */ jsxs(Button, { variant: "outline", className: "w-full", disabled: true, "data-testid": btnTestId, children: [
|
|
1131
|
+
/* @__PURE__ */ jsx(CheckCircle2, { className: "size-4" }),
|
|
1132
|
+
" Current workspace"
|
|
1133
|
+
] }) : /* @__PURE__ */ jsxs(Button, { className: "w-full", onClick: onOpen, disabled: busy, "data-testid": btnTestId, children: [
|
|
1134
|
+
busy ? /* @__PURE__ */ jsx(Loader2, { className: "size-4 animate-spin" }) : /* @__PURE__ */ jsx(ArrowLeftRight, { className: "size-4" }),
|
|
1135
|
+
"Open"
|
|
1136
|
+
] }) })
|
|
2313
1137
|
]
|
|
2314
|
-
}
|
|
2315
|
-
|
|
2316
|
-
|
|
1138
|
+
}
|
|
1139
|
+
);
|
|
1140
|
+
}
|
|
1141
|
+
var GRID = {
|
|
1142
|
+
1: "grid-cols-1",
|
|
1143
|
+
2: "grid-cols-2",
|
|
1144
|
+
3: "grid-cols-2 sm:grid-cols-3",
|
|
1145
|
+
4: "grid-cols-2 lg:grid-cols-4"
|
|
1146
|
+
};
|
|
1147
|
+
function StatGroup({ items, testId }) {
|
|
1148
|
+
const list = items ?? [];
|
|
1149
|
+
const cols = GRID[Math.min(list.length, 4)] ?? GRID[4];
|
|
1150
|
+
return /* @__PURE__ */ jsx("dl", { className: cn("grid gap-8", cols), "data-testid": testId, children: list.map((item, i) => /* @__PURE__ */ jsxs("div", { className: "text-center", "data-testid": testId && `${testId}-item-${i}`, children: [
|
|
1151
|
+
/* @__PURE__ */ jsx("dt", { className: "sr-only", children: item.label }),
|
|
1152
|
+
/* @__PURE__ */ jsx("dd", { className: "text-4xl font-semibold tracking-tight sm:text-5xl", children: item.value }),
|
|
1153
|
+
/* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: item.label }),
|
|
1154
|
+
item.sub && /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-muted-foreground/80", children: item.sub })
|
|
1155
|
+
] }, i)) });
|
|
2317
1156
|
}
|
|
2318
1157
|
function NavItemLink({ item, onNavigate }) {
|
|
2319
1158
|
return /* @__PURE__ */ jsxs(
|
|
@@ -2386,85 +1225,90 @@ function AppShell({
|
|
|
2386
1225
|
onNavigate
|
|
2387
1226
|
}
|
|
2388
1227
|
);
|
|
2389
|
-
return
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
/* @__PURE__ */ jsx(
|
|
2410
|
-
"div",
|
|
2411
|
-
{
|
|
2412
|
-
className: "absolute inset-0 bg-black/60 backdrop-blur-sm",
|
|
2413
|
-
onClick: () => setOpen(false),
|
|
2414
|
-
"aria-hidden": true
|
|
2415
|
-
}
|
|
2416
|
-
),
|
|
2417
|
-
/* @__PURE__ */ jsxs("aside", { className: "absolute inset-y-0 left-0 flex w-64 max-w-[82%] flex-col border-r border-sidebar-border bg-sidebar shadow-xl", children: [
|
|
2418
|
-
/* @__PURE__ */ jsx(
|
|
2419
|
-
"button",
|
|
2420
|
-
{
|
|
2421
|
-
type: "button",
|
|
2422
|
-
onClick: () => setOpen(false),
|
|
2423
|
-
className: "absolute right-3 top-4 z-10 flex size-8 items-center justify-center rounded-md text-sidebar-foreground/70 hover:bg-sidebar-accent/60 hover:text-sidebar-accent-foreground",
|
|
2424
|
-
"aria-label": "Close menu",
|
|
2425
|
-
"data-testid": `${testIdPrefix}-sidebar-close`,
|
|
2426
|
-
children: /* @__PURE__ */ jsx(X, { className: "size-5" })
|
|
2427
|
-
}
|
|
2428
|
-
),
|
|
2429
|
-
body(() => setOpen(false))
|
|
2430
|
-
] })
|
|
2431
|
-
]
|
|
2432
|
-
}
|
|
2433
|
-
),
|
|
2434
|
-
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [
|
|
2435
|
-
/* @__PURE__ */ jsxs(
|
|
2436
|
-
"header",
|
|
1228
|
+
return (
|
|
1229
|
+
// One TooltipProvider for the whole back office: every kit component that
|
|
1230
|
+
// renders a tooltip (entity pills, document tiles, toolbars) inherits the
|
|
1231
|
+
// same hover delay, and no app has to remember to mount it.
|
|
1232
|
+
/* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(
|
|
1233
|
+
"div",
|
|
1234
|
+
{
|
|
1235
|
+
className: "flex h-screen overflow-hidden bg-background",
|
|
1236
|
+
"data-testid": `${testIdPrefix}-shell`,
|
|
1237
|
+
children: [
|
|
1238
|
+
/* @__PURE__ */ jsx(
|
|
1239
|
+
"aside",
|
|
1240
|
+
{
|
|
1241
|
+
className: "hidden h-full w-64 shrink-0 flex-col border-r border-sidebar-border bg-sidebar lg:flex",
|
|
1242
|
+
"data-testid": `${testIdPrefix}-sidebar`,
|
|
1243
|
+
children: body()
|
|
1244
|
+
}
|
|
1245
|
+
),
|
|
1246
|
+
open && /* @__PURE__ */ jsxs(
|
|
1247
|
+
"div",
|
|
2437
1248
|
{
|
|
2438
|
-
className: "
|
|
2439
|
-
"data-testid": `${testIdPrefix}-
|
|
1249
|
+
className: "fixed inset-0 z-50 lg:hidden",
|
|
1250
|
+
"data-testid": `${testIdPrefix}-sidebar-mobile`,
|
|
2440
1251
|
children: [
|
|
2441
1252
|
/* @__PURE__ */ jsx(
|
|
2442
|
-
"
|
|
1253
|
+
"div",
|
|
2443
1254
|
{
|
|
2444
|
-
|
|
2445
|
-
onClick: () => setOpen(
|
|
2446
|
-
|
|
2447
|
-
"data-testid": `${testIdPrefix}-nav-toggle`,
|
|
2448
|
-
"aria-label": "Open menu",
|
|
2449
|
-
children: /* @__PURE__ */ jsx(Menu, { className: "size-5" })
|
|
1255
|
+
className: "absolute inset-0 bg-black/60 backdrop-blur-sm",
|
|
1256
|
+
onClick: () => setOpen(false),
|
|
1257
|
+
"aria-hidden": true
|
|
2450
1258
|
}
|
|
2451
1259
|
),
|
|
2452
|
-
|
|
1260
|
+
/* @__PURE__ */ jsxs("aside", { className: "absolute inset-y-0 left-0 flex w-64 max-w-[82%] flex-col border-r border-sidebar-border bg-sidebar shadow-xl", children: [
|
|
1261
|
+
/* @__PURE__ */ jsx(
|
|
1262
|
+
"button",
|
|
1263
|
+
{
|
|
1264
|
+
type: "button",
|
|
1265
|
+
onClick: () => setOpen(false),
|
|
1266
|
+
className: "absolute right-3 top-4 z-10 flex size-8 items-center justify-center rounded-md text-sidebar-foreground/70 hover:bg-sidebar-accent/60 hover:text-sidebar-accent-foreground",
|
|
1267
|
+
"aria-label": "Close menu",
|
|
1268
|
+
"data-testid": `${testIdPrefix}-sidebar-close`,
|
|
1269
|
+
children: /* @__PURE__ */ jsx(X, { className: "size-5" })
|
|
1270
|
+
}
|
|
1271
|
+
),
|
|
1272
|
+
body(() => setOpen(false))
|
|
1273
|
+
] })
|
|
2453
1274
|
]
|
|
2454
1275
|
}
|
|
2455
1276
|
),
|
|
2456
|
-
/* @__PURE__ */
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
1277
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [
|
|
1278
|
+
/* @__PURE__ */ jsxs(
|
|
1279
|
+
"header",
|
|
1280
|
+
{
|
|
1281
|
+
className: "flex h-16 shrink-0 items-center gap-4 border-b border-border bg-card/80 px-6 backdrop-blur",
|
|
1282
|
+
"data-testid": `${testIdPrefix}-topbar`,
|
|
1283
|
+
children: [
|
|
1284
|
+
/* @__PURE__ */ jsx(
|
|
1285
|
+
"button",
|
|
1286
|
+
{
|
|
1287
|
+
type: "button",
|
|
1288
|
+
onClick: () => setOpen(true),
|
|
1289
|
+
className: "flex size-9 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-foreground lg:hidden",
|
|
1290
|
+
"data-testid": `${testIdPrefix}-nav-toggle`,
|
|
1291
|
+
"aria-label": "Open menu",
|
|
1292
|
+
children: /* @__PURE__ */ jsx(Menu, { className: "size-5" })
|
|
1293
|
+
}
|
|
1294
|
+
),
|
|
1295
|
+
topbar
|
|
1296
|
+
]
|
|
1297
|
+
}
|
|
1298
|
+
),
|
|
1299
|
+
/* @__PURE__ */ jsx(
|
|
1300
|
+
"main",
|
|
1301
|
+
{
|
|
1302
|
+
className: cn("flex-1 overflow-y-auto", mainClassName),
|
|
1303
|
+
"data-testid": `${testIdPrefix}-main`,
|
|
1304
|
+
children
|
|
1305
|
+
}
|
|
1306
|
+
)
|
|
1307
|
+
] }),
|
|
1308
|
+
rightRail
|
|
1309
|
+
]
|
|
1310
|
+
}
|
|
1311
|
+
) })
|
|
2468
1312
|
);
|
|
2469
1313
|
}
|
|
2470
1314
|
function AppHeader({
|
|
@@ -2699,6 +1543,32 @@ function createLiveWidgets(kit) {
|
|
|
2699
1543
|
LiveMetric: LiveMetricWidget
|
|
2700
1544
|
};
|
|
2701
1545
|
}
|
|
1546
|
+
function useAssetImage(docId) {
|
|
1547
|
+
const arbi = useArbi();
|
|
1548
|
+
const { data: thumbs } = useThumbnails([docId]);
|
|
1549
|
+
const thumb = thumbs?.[docId];
|
|
1550
|
+
const { data: objectUrl } = useQuery({
|
|
1551
|
+
queryKey: ["arbi", "asset-image", docId],
|
|
1552
|
+
queryFn: async () => {
|
|
1553
|
+
const res = await arbi.documents.download(docId);
|
|
1554
|
+
const blob = await res.blob();
|
|
1555
|
+
return URL.createObjectURL(blob);
|
|
1556
|
+
},
|
|
1557
|
+
// Only download when the thumbnail is genuinely absent (not merely loading).
|
|
1558
|
+
enabled: !!docId && thumbs != null && !thumb && arbi.hasWorkspace,
|
|
1559
|
+
staleTime: 10 * 6e4
|
|
1560
|
+
});
|
|
1561
|
+
useEffect(() => {
|
|
1562
|
+
return () => {
|
|
1563
|
+
if (objectUrl) URL.revokeObjectURL(objectUrl);
|
|
1564
|
+
};
|
|
1565
|
+
}, [objectUrl]);
|
|
1566
|
+
return thumb ?? objectUrl;
|
|
1567
|
+
}
|
|
1568
|
+
function AssetThumb({ docId, alt, className, testId }) {
|
|
1569
|
+
const src = useAssetImage(docId);
|
|
1570
|
+
return /* @__PURE__ */ jsx("img", { src: src ?? void 0, alt: alt ?? "", className, "data-testid": testId });
|
|
1571
|
+
}
|
|
2702
1572
|
|
|
2703
1573
|
// src/studio/publish.ts
|
|
2704
1574
|
function blobToDataUrl(blob) {
|
|
@@ -2817,7 +1687,7 @@ function StudioEditor({
|
|
|
2817
1687
|
delete w.__studioResetSlug;
|
|
2818
1688
|
};
|
|
2819
1689
|
}, [resetSeam, arbi, live, persistence]);
|
|
2820
|
-
const
|
|
1690
|
+
const persist3 = useCallback(
|
|
2821
1691
|
async (toSave) => {
|
|
2822
1692
|
setSaving(true);
|
|
2823
1693
|
try {
|
|
@@ -2910,7 +1780,7 @@ function StudioEditor({
|
|
|
2910
1780
|
"button",
|
|
2911
1781
|
{
|
|
2912
1782
|
type: "button",
|
|
2913
|
-
onClick: () => void
|
|
1783
|
+
onClick: () => void persist3(latest.current),
|
|
2914
1784
|
disabled: saving || loading,
|
|
2915
1785
|
className: "inline-flex items-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-60",
|
|
2916
1786
|
"data-testid": `${testIdPrefix}-publish`,
|
|
@@ -2935,7 +1805,7 @@ function StudioEditor({
|
|
|
2935
1805
|
"\u201D\u2026"
|
|
2936
1806
|
]
|
|
2937
1807
|
}
|
|
2938
|
-
) : /* @__PURE__ */ jsx(AssetResolverProvider, { children: /* @__PURE__ */ jsx(
|
|
1808
|
+
) : /* @__PURE__ */ jsx(AssetResolverProvider, { render: AssetThumb, children: /* @__PURE__ */ jsx(
|
|
2939
1809
|
Puck,
|
|
2940
1810
|
{
|
|
2941
1811
|
config,
|
|
@@ -2943,7 +1813,7 @@ function StudioEditor({
|
|
|
2943
1813
|
onChange: (d) => {
|
|
2944
1814
|
latest.current = d;
|
|
2945
1815
|
},
|
|
2946
|
-
onPublish: (d) => void
|
|
1816
|
+
onPublish: (d) => void persist3(d)
|
|
2947
1817
|
},
|
|
2948
1818
|
`${slug}-${rev}`
|
|
2949
1819
|
) }) }),
|
|
@@ -3564,13 +2434,13 @@ var TEXTURE_STYLE = {
|
|
|
3564
2434
|
backgroundSize: "4px 4px",
|
|
3565
2435
|
opacity: 0.04
|
|
3566
2436
|
};
|
|
3567
|
-
var
|
|
2437
|
+
var PADDING = {
|
|
3568
2438
|
none: "",
|
|
3569
2439
|
sm: "py-8 lg:py-10",
|
|
3570
2440
|
md: "py-16 lg:py-20",
|
|
3571
2441
|
lg: "py-24 lg:py-28"
|
|
3572
2442
|
};
|
|
3573
|
-
var
|
|
2443
|
+
var WIDTH = {
|
|
3574
2444
|
narrow: "max-w-3xl",
|
|
3575
2445
|
default: "max-w-7xl",
|
|
3576
2446
|
wide: "max-w-[90rem]",
|
|
@@ -3602,8 +2472,8 @@ function Section({
|
|
|
3602
2472
|
{
|
|
3603
2473
|
className: cn(
|
|
3604
2474
|
"relative mx-auto px-5 lg:px-8",
|
|
3605
|
-
|
|
3606
|
-
|
|
2475
|
+
WIDTH[maxWidth],
|
|
2476
|
+
PADDING[padding],
|
|
3607
2477
|
className
|
|
3608
2478
|
),
|
|
3609
2479
|
children
|
|
@@ -3614,13 +2484,13 @@ function Section({
|
|
|
3614
2484
|
var iconMap = {
|
|
3615
2485
|
FileText: FileText,
|
|
3616
2486
|
Folder,
|
|
3617
|
-
Users,
|
|
2487
|
+
Users: Users,
|
|
3618
2488
|
Briefcase,
|
|
3619
2489
|
Calendar,
|
|
3620
2490
|
Clock,
|
|
3621
2491
|
CheckCircle,
|
|
3622
2492
|
AlertCircle,
|
|
3623
|
-
Info
|
|
2493
|
+
Info,
|
|
3624
2494
|
TrendingUp,
|
|
3625
2495
|
DollarSign,
|
|
3626
2496
|
BarChart3,
|
|
@@ -4374,7 +3244,7 @@ function createSiteBlocks(kit) {
|
|
|
4374
3244
|
{ label: "FAQ", content: "Answers to common questions." }
|
|
4375
3245
|
]
|
|
4376
3246
|
},
|
|
4377
|
-
render: ({ id, items }) => /* @__PURE__ */ jsx(Tabs, { items, testId: blockTestId(id) })
|
|
3247
|
+
render: ({ id, items }) => /* @__PURE__ */ jsx(Tabs$1, { items, testId: blockTestId(id) })
|
|
4378
3248
|
};
|
|
4379
3249
|
const AccordionBlock = {
|
|
4380
3250
|
label: "Accordion",
|
|
@@ -5543,7 +4413,7 @@ function VerticalBuilder({
|
|
|
5543
4413
|
}) {
|
|
5544
4414
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-6", "data-testid": `page-${testIdPrefix}`, children: [
|
|
5545
4415
|
header,
|
|
5546
|
-
/* @__PURE__ */ jsxs(Tabs
|
|
4416
|
+
/* @__PURE__ */ jsxs(Tabs, { defaultValue: "theme", children: [
|
|
5547
4417
|
/* @__PURE__ */ jsxs(TabsList, { "data-testid": `${testIdPrefix}-tabs`, children: [
|
|
5548
4418
|
/* @__PURE__ */ jsxs(TabsTrigger, { value: "theme", "data-testid": `${testIdPrefix}-tab-theme`, children: [
|
|
5549
4419
|
/* @__PURE__ */ jsx(Palette, { className: "size-4" }),
|
|
@@ -5587,6 +4457,6 @@ function VerticalBuilder({
|
|
|
5587
4457
|
] });
|
|
5588
4458
|
}
|
|
5589
4459
|
|
|
5590
|
-
export {
|
|
4460
|
+
export { AgentsPanel, AppHeader, AppShell, AssetThumb, ConnectionProvider, DataTable, DataTableBlock, EmptyState, GridView, LegalArbiProvider, LiveDataProvider, MetricCard, ModuleManager, PageHeader, PageRenderer, Section, StatGroup, StudioEditor, Toolbar, UploadDropzone, VerticalBuilder, WidgetPlaceholder, WorkspaceCard, createAgentSelectionStore, createAiFields, createArbiBlocksConfig, createArbiMaterializer, createBlockKit, createImageField, createLiveWidgets, createModuleRegistry, createModuleStore, createPromptLibrary, createSiteBlocks, createStudioPersistence, createVerticalExport, createWebsiteBlocks, iconMap, isAuthenticated, materializePageData, matterToContext, useAssetImage, useConnection, useFirmAiTask, useImageGen, useLiveDataActive, useSemanticSearch, useWorkspaceDocs };
|
|
5591
4461
|
//# sourceMappingURL=index.js.map
|
|
5592
4462
|
//# sourceMappingURL=index.js.map
|