@melony/react 0.1.28 → 0.1.29

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/index.js CHANGED
@@ -3,24 +3,23 @@ import React11__default, { createContext, useState, useContext, useCallback, use
3
3
  import { NuqsAdapter } from 'nuqs/adapters/react';
4
4
  import { QueryClient, QueryClientProvider, useQueryClient, useQuery, useMutation } from '@tanstack/react-query';
5
5
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
- import { Button as Button$1 } from '@base-ui/react/button';
7
- import { cva } from 'class-variance-authority';
8
6
  import { clsx } from 'clsx';
9
7
  import { twMerge } from 'tailwind-merge';
8
+ import { Dialog as Dialog$1 } from '@base-ui/react/dialog';
9
+ import { Button as Button$1 } from '@base-ui/react/button';
10
+ import { cva } from 'class-variance-authority';
10
11
  import * as ICONS from '@tabler/icons-react';
11
- import { IconBrandGoogle, IconFileText, IconFile, IconX, IconPaperclip, IconChevronDown, IconLoader2, IconArrowUp, IconMessage, IconDotsVertical, IconTrash, IconHistory, IconPlus, IconArrowLeft, IconLayoutSidebarLeftExpand, IconLayoutSidebarLeftCollapse, IconLayoutSidebarRightExpand, IconLayoutSidebarRightCollapse, IconUser, IconLogout, IconDeviceDesktop, IconMoon, IconSun, IconCheck, IconSelector, IconChevronUp } from '@tabler/icons-react';
12
+ import { IconUser, IconLogout, IconX, IconBrandGoogle, IconFileText, IconFile, IconPaperclip, IconChevronDown, IconLoader2, IconArrowUp, IconDotsVertical, IconTrash, IconHistory, IconPlus, IconArrowLeft, IconMessage, IconLayoutSidebarLeftExpand, IconLayoutSidebarLeftCollapse, IconLayoutSidebarRightExpand, IconLayoutSidebarRightCollapse, IconDeviceDesktop, IconMoon, IconSun, IconCheck, IconSelector, IconChevronUp } from '@tabler/icons-react';
13
+ import { Menu } from '@base-ui/react/menu';
14
+ import { Separator as Separator$1 } from '@base-ui/react/separator';
12
15
  import { generateId } from 'melony/client';
13
16
  import { useQueryState, parseAsString } from 'nuqs';
14
17
  import { mergeProps } from '@base-ui/react/merge-props';
15
18
  import { useRender } from '@base-ui/react/use-render';
16
- import { Menu } from '@base-ui/react/menu';
17
- import { Separator as Separator$1 } from '@base-ui/react/separator';
18
- import { Dialog as Dialog$1 } from '@base-ui/react/dialog';
19
19
  import { Input as Input$1 } from '@base-ui/react/input';
20
20
  import { Select as Select$1 } from '@base-ui/react/select';
21
21
  import { createPortal } from 'react-dom';
22
22
  import { useHotkeys } from 'react-hotkeys-hook';
23
- import { AlertDialog as AlertDialog$1 } from '@base-ui/react/alert-dialog';
24
23
 
25
24
  // src/providers/melony-provider.tsx
26
25
 
@@ -167,9 +166,121 @@ var MelonyProvider = ({
167
166
  }
168
167
  ) }) });
169
168
  };
169
+ var useAuth = () => {
170
+ const context = useContext(AuthContext);
171
+ if (context === void 0) {
172
+ throw new Error("useAuth must be used within an AuthProvider");
173
+ }
174
+ return context;
175
+ };
170
176
  function cn(...inputs) {
171
177
  return twMerge(clsx(inputs));
172
178
  }
179
+ function Dialog({ ...props }) {
180
+ return /* @__PURE__ */ jsx(Dialog$1.Root, { "data-slot": "dialog", ...props });
181
+ }
182
+ function DialogTrigger({ ...props }) {
183
+ return /* @__PURE__ */ jsx(Dialog$1.Trigger, { "data-slot": "dialog-trigger", ...props });
184
+ }
185
+ function DialogPortal({ ...props }) {
186
+ return /* @__PURE__ */ jsx(Dialog$1.Portal, { "data-slot": "dialog-portal", ...props });
187
+ }
188
+ function DialogOverlay({
189
+ className,
190
+ ...props
191
+ }) {
192
+ return /* @__PURE__ */ jsx(
193
+ Dialog$1.Backdrop,
194
+ {
195
+ "data-slot": "dialog-overlay",
196
+ className: cn(
197
+ "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/80 duration-200 supports-backdrop-filter:backdrop-blur-sm fixed inset-0 isolate z-50",
198
+ className
199
+ ),
200
+ ...props
201
+ }
202
+ );
203
+ }
204
+ function DialogContent({
205
+ className,
206
+ ...props
207
+ }) {
208
+ return /* @__PURE__ */ jsxs(DialogPortal, { children: [
209
+ /* @__PURE__ */ jsx(DialogOverlay, {}),
210
+ /* @__PURE__ */ jsx(
211
+ Dialog$1.Popup,
212
+ {
213
+ "data-slot": "dialog-content",
214
+ className: cn(
215
+ "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 sm:rounded-lg outline-none",
216
+ className
217
+ ),
218
+ ...props
219
+ }
220
+ )
221
+ ] });
222
+ }
223
+ function DialogClose({
224
+ className,
225
+ ...props
226
+ }) {
227
+ return /* @__PURE__ */ jsx(
228
+ Dialog$1.Close,
229
+ {
230
+ "data-slot": "dialog-close",
231
+ className: cn(
232
+ "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground",
233
+ className
234
+ ),
235
+ ...props
236
+ }
237
+ );
238
+ }
239
+ function DialogHeader({
240
+ className,
241
+ ...props
242
+ }) {
243
+ return /* @__PURE__ */ jsx(
244
+ "div",
245
+ {
246
+ "data-slot": "dialog-header",
247
+ className: cn(
248
+ "flex flex-col space-y-1.5 text-center sm:text-left",
249
+ className
250
+ ),
251
+ ...props
252
+ }
253
+ );
254
+ }
255
+ function DialogTitle({
256
+ className,
257
+ ...props
258
+ }) {
259
+ return /* @__PURE__ */ jsx(
260
+ Dialog$1.Title,
261
+ {
262
+ "data-slot": "dialog-title",
263
+ className: cn(
264
+ "text-lg font-semibold leading-none tracking-tight",
265
+ className
266
+ ),
267
+ ...props
268
+ }
269
+ );
270
+ }
271
+ function DialogDescription({
272
+ className,
273
+ ...props
274
+ }) {
275
+ return /* @__PURE__ */ jsx(
276
+ Dialog$1.Description,
277
+ {
278
+ "data-slot": "dialog-description",
279
+ className: cn("text-sm text-muted-foreground", className),
280
+ ...props
281
+ }
282
+ );
283
+ }
173
284
  var buttonVariants = cva(
174
285
  "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-4xl border border-transparent bg-clip-padding text-sm font-medium focus-visible:ring-[3px] aria-invalid:ring-[3px] [&_svg:not([class*='size-'])]:size-4 inline-flex items-center justify-center whitespace-nowrap transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none group/button select-none",
175
286
  {
@@ -214,12 +325,287 @@ function Button({
214
325
  }
215
326
  );
216
327
  }
217
- var useAuth = () => {
218
- const context = useContext(AuthContext);
219
- if (context === void 0) {
220
- throw new Error("useAuth must be used within an AuthProvider");
328
+ function DropdownMenu({ ...props }) {
329
+ return /* @__PURE__ */ jsx(Menu.Root, { "data-slot": "dropdown-menu", ...props });
330
+ }
331
+ function DropdownMenuTrigger({ ...props }) {
332
+ return /* @__PURE__ */ jsx(Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
333
+ }
334
+ function DropdownMenuContent({
335
+ align = "start",
336
+ alignOffset = 0,
337
+ side = "bottom",
338
+ sideOffset = 4,
339
+ className,
340
+ ...props
341
+ }) {
342
+ return /* @__PURE__ */ jsx(Menu.Portal, { children: /* @__PURE__ */ jsx(
343
+ Menu.Positioner,
344
+ {
345
+ className: "isolate z-50 outline-none",
346
+ align,
347
+ alignOffset,
348
+ side,
349
+ sideOffset,
350
+ children: /* @__PURE__ */ jsx(
351
+ Menu.Popup,
352
+ {
353
+ "data-slot": "dropdown-menu-content",
354
+ className: cn("data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/5 bg-popover text-popover-foreground min-w-48 rounded-2xl p-1 shadow-2xl ring-1 duration-100 z-50 max-h-(--available-height) w-(--anchor-width) origin-(--transform-origin) overflow-x-hidden overflow-y-auto outline-none data-closed:overflow-hidden", className),
355
+ ...props
356
+ }
357
+ )
358
+ }
359
+ ) });
360
+ }
361
+ function DropdownMenuGroup({ ...props }) {
362
+ return /* @__PURE__ */ jsx(Menu.Group, { "data-slot": "dropdown-menu-group", ...props });
363
+ }
364
+ function DropdownMenuLabel({
365
+ className,
366
+ inset,
367
+ ...props
368
+ }) {
369
+ return /* @__PURE__ */ jsx(
370
+ Menu.GroupLabel,
371
+ {
372
+ "data-slot": "dropdown-menu-label",
373
+ "data-inset": inset,
374
+ className: cn("text-muted-foreground px-3 py-2.5 text-xs data-[inset]:pl-8", className),
375
+ ...props
376
+ }
377
+ );
378
+ }
379
+ function DropdownMenuItem({
380
+ className,
381
+ inset,
382
+ variant = "default",
383
+ ...props
384
+ }) {
385
+ return /* @__PURE__ */ jsx(
386
+ Menu.Item,
387
+ {
388
+ "data-slot": "dropdown-menu-item",
389
+ "data-inset": inset,
390
+ "data-variant": variant,
391
+ className: cn(
392
+ "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:text-destructive not-data-[variant=destructive]:focus:**:text-accent-foreground gap-2.5 rounded-xl px-3 py-2 text-sm [&_svg:not([class*='size-'])]:size-4 group/dropdown-menu-item relative flex cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0",
393
+ className
394
+ ),
395
+ ...props
396
+ }
397
+ );
398
+ }
399
+ function DropdownMenuCheckboxItem({
400
+ className,
401
+ children,
402
+ checked,
403
+ ...props
404
+ }) {
405
+ return /* @__PURE__ */ jsxs(
406
+ Menu.CheckboxItem,
407
+ {
408
+ "data-slot": "dropdown-menu-checkbox-item",
409
+ className: cn(
410
+ "focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground gap-2.5 rounded-xl py-2 pr-8 pl-3 text-sm [&_svg:not([class*='size-'])]:size-4 relative flex cursor-default items-center outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
411
+ className
412
+ ),
413
+ checked,
414
+ ...props,
415
+ children: [
416
+ /* @__PURE__ */ jsx(
417
+ "span",
418
+ {
419
+ className: "pointer-events-none absolute right-2 flex items-center justify-center pointer-events-none",
420
+ "data-slot": "dropdown-menu-checkbox-item-indicator",
421
+ children: /* @__PURE__ */ jsx(Menu.CheckboxItemIndicator, { children: /* @__PURE__ */ jsx(
422
+ IconCheck,
423
+ {}
424
+ ) })
425
+ }
426
+ ),
427
+ children
428
+ ]
429
+ }
430
+ );
431
+ }
432
+ function DropdownMenuSeparator({
433
+ className,
434
+ ...props
435
+ }) {
436
+ return /* @__PURE__ */ jsx(
437
+ Menu.Separator,
438
+ {
439
+ "data-slot": "dropdown-menu-separator",
440
+ className: cn("bg-border/50 -mx-1 my-1 h-px", className),
441
+ ...props
442
+ }
443
+ );
444
+ }
445
+ function Separator({
446
+ className,
447
+ orientation = "horizontal",
448
+ ...props
449
+ }) {
450
+ return /* @__PURE__ */ jsx(
451
+ Separator$1,
452
+ {
453
+ "data-slot": "separator",
454
+ orientation,
455
+ className: cn(
456
+ "bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:w-px data-[orientation=vertical]:self-stretch",
457
+ className
458
+ ),
459
+ ...props
460
+ }
461
+ );
462
+ }
463
+ var AccountButton = ({
464
+ className,
465
+ variant = "outline",
466
+ size
467
+ }) => {
468
+ const { isLoading, isAuthenticated, user, login, logout } = useAuth();
469
+ const [open, setOpen] = React11.useState(false);
470
+ const [accountInfoOpen, setAccountInfoOpen] = React11.useState(false);
471
+ const [error, setError] = React11.useState(null);
472
+ const initials = React11.useMemo(() => {
473
+ const name = user?.displayName || user?.name;
474
+ if (!name) return "";
475
+ return name.split(" ").map((n) => n[0]).join("").toUpperCase().slice(0, 2);
476
+ }, [user?.displayName, user?.name]);
477
+ const handleGoogleSignIn = async () => {
478
+ login();
479
+ };
480
+ if (isAuthenticated) {
481
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
482
+ /* @__PURE__ */ jsxs(DropdownMenu, { children: [
483
+ /* @__PURE__ */ jsx(
484
+ DropdownMenuTrigger,
485
+ {
486
+ render: (props) => /* @__PURE__ */ jsx(
487
+ Button,
488
+ {
489
+ variant,
490
+ size: "icon",
491
+ ...props,
492
+ className: cn("rounded-full", className),
493
+ children: user?.picture ? /* @__PURE__ */ jsx(
494
+ "img",
495
+ {
496
+ src: user.picture,
497
+ alt: user.displayName || user.name,
498
+ className: "size-7 rounded-full object-cover"
499
+ }
500
+ ) : /* @__PURE__ */ jsx("div", { className: "flex size-7 items-center justify-center rounded-full bg-muted text-xs font-bold", children: initials || /* @__PURE__ */ jsx(IconUser, { className: "size-4" }) })
501
+ }
502
+ )
503
+ }
504
+ ),
505
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", className: "w-56", children: [
506
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 p-2", children: [
507
+ user?.picture ? /* @__PURE__ */ jsx(
508
+ "img",
509
+ {
510
+ src: user.picture,
511
+ alt: user.displayName || user.name,
512
+ className: "size-8 rounded-full object-cover"
513
+ }
514
+ ) : /* @__PURE__ */ jsx("div", { className: "flex size-8 items-center justify-center rounded-full bg-muted text-xs font-bold", children: initials || /* @__PURE__ */ jsx(IconUser, { className: "size-4" }) }),
515
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col space-y-0.5 overflow-hidden", children: [
516
+ /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-medium", children: user?.displayName || user?.name }),
517
+ /* @__PURE__ */ jsx("p", { className: "truncate text-xs text-muted-foreground", children: user?.email })
518
+ ] })
519
+ ] }),
520
+ /* @__PURE__ */ jsx(Separator, { className: "my-1" }),
521
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: () => setAccountInfoOpen(true), children: [
522
+ /* @__PURE__ */ jsx(IconUser, { className: "mr-2 size-4" }),
523
+ "Account Settings"
524
+ ] }),
525
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: logout, className: "text-destructive", children: [
526
+ /* @__PURE__ */ jsx(IconLogout, { className: "mr-2 size-4" }),
527
+ "Logout"
528
+ ] })
529
+ ] })
530
+ ] }),
531
+ /* @__PURE__ */ jsx(Dialog, { open: accountInfoOpen, onOpenChange: setAccountInfoOpen, children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-md", children: [
532
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [
533
+ /* @__PURE__ */ jsx(DialogTitle, { children: "Account Information" }),
534
+ /* @__PURE__ */ jsx(DialogDescription, { children: "Your account details and settings." })
535
+ ] }),
536
+ /* @__PURE__ */ jsxs(DialogClose, { children: [
537
+ /* @__PURE__ */ jsx(IconX, { className: "size-4" }),
538
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
539
+ ] }),
540
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 py-4", children: [
541
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
542
+ user?.picture ? /* @__PURE__ */ jsx(
543
+ "img",
544
+ {
545
+ src: user.picture,
546
+ alt: user.displayName || user.name,
547
+ className: "size-16 rounded-full object-cover"
548
+ }
549
+ ) : /* @__PURE__ */ jsx("div", { className: "flex size-16 items-center justify-center rounded-full bg-muted text-xl font-bold", children: initials || /* @__PURE__ */ jsx(IconUser, { className: "size-8 text-muted-foreground" }) }),
550
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
551
+ /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold", children: user?.displayName || user?.name }),
552
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: user?.email })
553
+ ] })
554
+ ] }),
555
+ /* @__PURE__ */ jsx(Separator, {}),
556
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
557
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
558
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-muted-foreground", children: "User ID" }),
559
+ /* @__PURE__ */ jsx("p", { className: "font-mono text-xs truncate", children: user?.uid || user?.id })
560
+ ] }),
561
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
562
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-muted-foreground", children: "Created At" }),
563
+ /* @__PURE__ */ jsx("p", { className: "text-xs", children: user?.createdAt || "N/A" })
564
+ ] })
565
+ ] })
566
+ ] })
567
+ ] }) })
568
+ ] });
221
569
  }
222
- return context;
570
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
571
+ /* @__PURE__ */ jsx(
572
+ Button,
573
+ {
574
+ variant,
575
+ size,
576
+ onClick: () => setOpen(true),
577
+ className,
578
+ children: "Sign in"
579
+ }
580
+ ),
581
+ /* @__PURE__ */ jsx(Dialog, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-md", children: [
582
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [
583
+ /* @__PURE__ */ jsx(DialogTitle, { children: "Sign in to continue" }),
584
+ /* @__PURE__ */ jsx(DialogDescription, { children: "Choose your preferred sign-in method to access your account." })
585
+ ] }),
586
+ /* @__PURE__ */ jsxs(DialogClose, { children: [
587
+ /* @__PURE__ */ jsx(IconX, { className: "size-4" }),
588
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
589
+ ] }),
590
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
591
+ error && /* @__PURE__ */ jsx("div", { className: "rounded-lg bg-destructive/10 p-3 text-sm text-destructive", children: error }),
592
+ /* @__PURE__ */ jsxs(
593
+ Button,
594
+ {
595
+ onClick: handleGoogleSignIn,
596
+ disabled: isLoading,
597
+ variant: "outline",
598
+ className: "w-full",
599
+ size: "lg",
600
+ children: [
601
+ /* @__PURE__ */ jsx(IconBrandGoogle, { className: "mr-2 size-5" }),
602
+ isLoading ? "Signing in..." : "Continue with Google"
603
+ ]
604
+ }
605
+ )
606
+ ] })
607
+ ] }) })
608
+ ] });
223
609
  };
224
610
  function WelcomeScreen({
225
611
  title = "Welcome to Melony",
@@ -250,13 +636,6 @@ function WelcomeScreen({
250
636
  imageAlt = "Product screenshot"
251
637
  }) {
252
638
  const { login, isLoading } = useAuth();
253
- const handleLogin = () => {
254
- if (onLoginClick) {
255
- onLoginClick();
256
- } else {
257
- login();
258
- }
259
- };
260
639
  return /* @__PURE__ */ jsxs(
261
640
  "div",
262
641
  {
@@ -293,26 +672,7 @@ function WelcomeScreen({
293
672
  /* @__PURE__ */ jsx("h2", { className: "text-3xl font-bold tracking-tight text-foreground", children: "Get Started" }),
294
673
  /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-lg", children: "Sign in to your account to continue" })
295
674
  ] }),
296
- /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
297
- /* @__PURE__ */ jsxs(
298
- Button,
299
- {
300
- size: "lg",
301
- variant: "outline",
302
- className: "w-full h-16 text-lg shadow-sm hover:shadow-md transition-all flex items-center justify-center gap-3 border-2 font-medium bg-background text-foreground hover:bg-accent",
303
- onClick: handleLogin,
304
- disabled: isLoading,
305
- children: [
306
- /* @__PURE__ */ jsx(IconBrandGoogle, { className: "size-6" }),
307
- isLoading ? "Signing in..." : "Continue with Google"
308
- ]
309
- }
310
- ),
311
- /* @__PURE__ */ jsxs("div", { className: "relative py-4", children: [
312
- /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center", children: /* @__PURE__ */ jsx("span", { className: "w-full border-t border-border" }) }),
313
- /* @__PURE__ */ jsx("div", { className: "relative flex justify-center text-xs uppercase", children: /* @__PURE__ */ jsx("span", { className: "bg-background px-3 text-muted-foreground tracking-widest font-medium", children: "Secure access" }) })
314
- ] })
315
- ] }),
675
+ /* @__PURE__ */ jsx("div", { className: "space-y-4", children: /* @__PURE__ */ jsx(AccountButton, {}) }),
316
676
  /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground leading-relaxed text-center md:text-left", children: [
317
677
  "By continuing, you agree to our ",
318
678
  /* @__PURE__ */ jsx("br", { className: "hidden md:block" }),
@@ -675,175 +1035,58 @@ var useThreads = () => {
675
1035
  throw new Error("useThreads must be used within a ThreadProvider");
676
1036
  }
677
1037
  return context;
678
- };
679
- function Textarea({ className, ...props }) {
680
- return /* @__PURE__ */ jsx(
681
- "textarea",
682
- {
683
- "data-slot": "textarea",
684
- className: cn(
685
- "border-input bg-input/30 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 resize-none rounded-xl border px-3 py-3 text-base transition-colors focus-visible:ring-[3px] aria-invalid:ring-[3px] md:text-sm placeholder:text-muted-foreground flex field-sizing-content min-h-16 w-full outline-none disabled:cursor-not-allowed disabled:opacity-50",
686
- className
687
- ),
688
- ...props
689
- }
690
- );
691
- }
692
- var badgeVariants = cva(
693
- "h-5 gap-1 rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium transition-all has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&>svg]:size-3! inline-flex items-center justify-center w-fit whitespace-nowrap shrink-0 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-colors overflow-hidden group/badge",
694
- {
695
- variants: {
696
- variant: {
697
- default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
698
- secondary: "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
699
- destructive: "bg-destructive/10 [a]:hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 text-destructive dark:bg-destructive/20",
700
- outline: "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground bg-input/30",
701
- ghost: "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
702
- link: "text-primary underline-offset-4 hover:underline"
703
- }
704
- },
705
- defaultVariants: {
706
- variant: "default"
707
- }
708
- }
709
- );
710
- function Badge({
711
- className,
712
- variant = "default",
713
- render,
714
- ...props
715
- }) {
716
- return useRender({
717
- defaultTagName: "span",
718
- props: mergeProps(
719
- {
720
- className: cn(badgeVariants({ className, variant }))
721
- },
722
- props
723
- ),
724
- render,
725
- state: {
726
- slot: "badge",
727
- variant
728
- }
729
- });
730
- }
731
- function DropdownMenu({ ...props }) {
732
- return /* @__PURE__ */ jsx(Menu.Root, { "data-slot": "dropdown-menu", ...props });
733
- }
734
- function DropdownMenuTrigger({ ...props }) {
735
- return /* @__PURE__ */ jsx(Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
736
- }
737
- function DropdownMenuContent({
738
- align = "start",
739
- alignOffset = 0,
740
- side = "bottom",
741
- sideOffset = 4,
742
- className,
743
- ...props
744
- }) {
745
- return /* @__PURE__ */ jsx(Menu.Portal, { children: /* @__PURE__ */ jsx(
746
- Menu.Positioner,
747
- {
748
- className: "isolate z-50 outline-none",
749
- align,
750
- alignOffset,
751
- side,
752
- sideOffset,
753
- children: /* @__PURE__ */ jsx(
754
- Menu.Popup,
755
- {
756
- "data-slot": "dropdown-menu-content",
757
- className: cn("data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/5 bg-popover text-popover-foreground min-w-48 rounded-2xl p-1 shadow-2xl ring-1 duration-100 z-50 max-h-(--available-height) w-(--anchor-width) origin-(--transform-origin) overflow-x-hidden overflow-y-auto outline-none data-closed:overflow-hidden", className),
758
- ...props
759
- }
760
- )
761
- }
762
- ) });
763
- }
764
- function DropdownMenuGroup({ ...props }) {
765
- return /* @__PURE__ */ jsx(Menu.Group, { "data-slot": "dropdown-menu-group", ...props });
766
- }
767
- function DropdownMenuLabel({
768
- className,
769
- inset,
770
- ...props
771
- }) {
772
- return /* @__PURE__ */ jsx(
773
- Menu.GroupLabel,
774
- {
775
- "data-slot": "dropdown-menu-label",
776
- "data-inset": inset,
777
- className: cn("text-muted-foreground px-3 py-2.5 text-xs data-[inset]:pl-8", className),
778
- ...props
779
- }
780
- );
781
- }
782
- function DropdownMenuItem({
783
- className,
784
- inset,
785
- variant = "default",
786
- ...props
787
- }) {
1038
+ };
1039
+ function Textarea({ className, ...props }) {
788
1040
  return /* @__PURE__ */ jsx(
789
- Menu.Item,
1041
+ "textarea",
790
1042
  {
791
- "data-slot": "dropdown-menu-item",
792
- "data-inset": inset,
793
- "data-variant": variant,
1043
+ "data-slot": "textarea",
794
1044
  className: cn(
795
- "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:text-destructive not-data-[variant=destructive]:focus:**:text-accent-foreground gap-2.5 rounded-xl px-3 py-2 text-sm [&_svg:not([class*='size-'])]:size-4 group/dropdown-menu-item relative flex cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0",
1045
+ "border-input bg-input/30 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 resize-none rounded-xl border px-3 py-3 text-base transition-colors focus-visible:ring-[3px] aria-invalid:ring-[3px] md:text-sm placeholder:text-muted-foreground flex field-sizing-content min-h-16 w-full outline-none disabled:cursor-not-allowed disabled:opacity-50",
796
1046
  className
797
1047
  ),
798
1048
  ...props
799
1049
  }
800
1050
  );
801
1051
  }
802
- function DropdownMenuCheckboxItem({
803
- className,
804
- children,
805
- checked,
806
- ...props
807
- }) {
808
- return /* @__PURE__ */ jsxs(
809
- Menu.CheckboxItem,
810
- {
811
- "data-slot": "dropdown-menu-checkbox-item",
812
- className: cn(
813
- "focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground gap-2.5 rounded-xl py-2 pr-8 pl-3 text-sm [&_svg:not([class*='size-'])]:size-4 relative flex cursor-default items-center outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
814
- className
815
- ),
816
- checked,
817
- ...props,
818
- children: [
819
- /* @__PURE__ */ jsx(
820
- "span",
821
- {
822
- className: "pointer-events-none absolute right-2 flex items-center justify-center pointer-events-none",
823
- "data-slot": "dropdown-menu-checkbox-item-indicator",
824
- children: /* @__PURE__ */ jsx(Menu.CheckboxItemIndicator, { children: /* @__PURE__ */ jsx(
825
- IconCheck,
826
- {}
827
- ) })
828
- }
829
- ),
830
- children
831
- ]
1052
+ var badgeVariants = cva(
1053
+ "h-5 gap-1 rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium transition-all has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&>svg]:size-3! inline-flex items-center justify-center w-fit whitespace-nowrap shrink-0 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-colors overflow-hidden group/badge",
1054
+ {
1055
+ variants: {
1056
+ variant: {
1057
+ default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
1058
+ secondary: "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
1059
+ destructive: "bg-destructive/10 [a]:hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 text-destructive dark:bg-destructive/20",
1060
+ outline: "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground bg-input/30",
1061
+ ghost: "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
1062
+ link: "text-primary underline-offset-4 hover:underline"
1063
+ }
1064
+ },
1065
+ defaultVariants: {
1066
+ variant: "default"
832
1067
  }
833
- );
834
- }
835
- function DropdownMenuSeparator({
1068
+ }
1069
+ );
1070
+ function Badge({
836
1071
  className,
1072
+ variant = "default",
1073
+ render,
837
1074
  ...props
838
1075
  }) {
839
- return /* @__PURE__ */ jsx(
840
- Menu.Separator,
841
- {
842
- "data-slot": "dropdown-menu-separator",
843
- className: cn("bg-border/50 -mx-1 my-1 h-px", className),
844
- ...props
1076
+ return useRender({
1077
+ defaultTagName: "span",
1078
+ props: mergeProps(
1079
+ {
1080
+ className: cn(badgeVariants({ className, variant }))
1081
+ },
1082
+ props
1083
+ ),
1084
+ render,
1085
+ state: {
1086
+ slot: "badge",
1087
+ variant
845
1088
  }
846
- );
1089
+ });
847
1090
  }
848
1091
  function Composer({
849
1092
  value,
@@ -1088,11 +1331,12 @@ function Composer({
1088
1331
  /* @__PURE__ */ jsx(
1089
1332
  DropdownMenuTrigger,
1090
1333
  {
1091
- render: /* @__PURE__ */ jsxs(
1334
+ render: (props) => /* @__PURE__ */ jsxs(
1092
1335
  Button,
1093
1336
  {
1094
1337
  variant: "ghost",
1095
1338
  size: "sm",
1339
+ ...props,
1096
1340
  className: cn(
1097
1341
  "gap-2",
1098
1342
  selectedInGroup.length > 0 ? "text-foreground bg-muted/50" : "text-muted-foreground"
@@ -1131,7 +1375,7 @@ function Composer({
1131
1375
  Button,
1132
1376
  {
1133
1377
  type: "submit",
1134
- disabled: !value.trim() && attachedFiles.length === 0 && !isLoading || isLoading,
1378
+ disabled: !value.trim() && attachedFiles.length === 0 && selectedOptions.size === 0 && !isLoading || isLoading,
1135
1379
  size: "icon-lg",
1136
1380
  onClick: () => handleInternalSubmit().catch(console.error),
1137
1381
  children: isLoading ? /* @__PURE__ */ jsx(IconLoader2, { className: "h-5 w-5 animate-spin" }) : /* @__PURE__ */ jsx(IconArrowUp, { className: "h-5 w-5" })
@@ -1405,24 +1649,6 @@ var Spacer = ({
1405
1649
  }
1406
1650
  );
1407
1651
  };
1408
- function Separator({
1409
- className,
1410
- orientation = "horizontal",
1411
- ...props
1412
- }) {
1413
- return /* @__PURE__ */ jsx(
1414
- Separator$1,
1415
- {
1416
- "data-slot": "separator",
1417
- orientation,
1418
- className: cn(
1419
- "bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:w-px data-[orientation=vertical]:self-stretch",
1420
- className
1421
- ),
1422
- ...props
1423
- }
1424
- );
1425
- }
1426
1652
  var Divider = ({
1427
1653
  orientation = "horizontal",
1428
1654
  className,
@@ -1466,7 +1692,7 @@ var ListItem = ({
1466
1692
  const paddingClasses = {
1467
1693
  xs: "px-1.5 py-1",
1468
1694
  sm: "px-2 py-1.5",
1469
- md: "px-3 py-2",
1695
+ md: "px-3 py-1.5",
1470
1696
  lg: "px-4 py-3",
1471
1697
  xl: "px-6 py-4"
1472
1698
  };
@@ -1502,7 +1728,7 @@ var ListItem = ({
1502
1728
  {
1503
1729
  onClick: isInteractive ? handleClick : void 0,
1504
1730
  className: cn(
1505
- "flex rounded-md transition-colors",
1731
+ "flex rounded-md transition-colors text-sm",
1506
1732
  orientation === "horizontal" ? "flex-row" : "flex-col",
1507
1733
  gapClasses[gap] || "gap-3",
1508
1734
  alignClasses[resolvedAlign],
@@ -1519,111 +1745,6 @@ var ListItem = ({
1519
1745
  }
1520
1746
  );
1521
1747
  };
1522
- function Dialog({ ...props }) {
1523
- return /* @__PURE__ */ jsx(Dialog$1.Root, { "data-slot": "dialog", ...props });
1524
- }
1525
- function DialogTrigger({ ...props }) {
1526
- return /* @__PURE__ */ jsx(Dialog$1.Trigger, { "data-slot": "dialog-trigger", ...props });
1527
- }
1528
- function DialogPortal({ ...props }) {
1529
- return /* @__PURE__ */ jsx(Dialog$1.Portal, { "data-slot": "dialog-portal", ...props });
1530
- }
1531
- function DialogOverlay({
1532
- className,
1533
- ...props
1534
- }) {
1535
- return /* @__PURE__ */ jsx(
1536
- Dialog$1.Backdrop,
1537
- {
1538
- "data-slot": "dialog-overlay",
1539
- className: cn(
1540
- "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/80 duration-200 supports-backdrop-filter:backdrop-blur-sm fixed inset-0 isolate z-50",
1541
- className
1542
- ),
1543
- ...props
1544
- }
1545
- );
1546
- }
1547
- function DialogContent({
1548
- className,
1549
- ...props
1550
- }) {
1551
- return /* @__PURE__ */ jsxs(DialogPortal, { children: [
1552
- /* @__PURE__ */ jsx(DialogOverlay, {}),
1553
- /* @__PURE__ */ jsx(
1554
- Dialog$1.Popup,
1555
- {
1556
- "data-slot": "dialog-content",
1557
- className: cn(
1558
- "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 sm:rounded-lg outline-none",
1559
- className
1560
- ),
1561
- ...props
1562
- }
1563
- )
1564
- ] });
1565
- }
1566
- function DialogClose({
1567
- className,
1568
- ...props
1569
- }) {
1570
- return /* @__PURE__ */ jsx(
1571
- Dialog$1.Close,
1572
- {
1573
- "data-slot": "dialog-close",
1574
- className: cn(
1575
- "absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground",
1576
- className
1577
- ),
1578
- ...props
1579
- }
1580
- );
1581
- }
1582
- function DialogHeader({
1583
- className,
1584
- ...props
1585
- }) {
1586
- return /* @__PURE__ */ jsx(
1587
- "div",
1588
- {
1589
- "data-slot": "dialog-header",
1590
- className: cn(
1591
- "flex flex-col space-y-1.5 text-center sm:text-left",
1592
- className
1593
- ),
1594
- ...props
1595
- }
1596
- );
1597
- }
1598
- function DialogTitle({
1599
- className,
1600
- ...props
1601
- }) {
1602
- return /* @__PURE__ */ jsx(
1603
- Dialog$1.Title,
1604
- {
1605
- "data-slot": "dialog-title",
1606
- className: cn(
1607
- "text-lg font-semibold leading-none tracking-tight",
1608
- className
1609
- ),
1610
- ...props
1611
- }
1612
- );
1613
- }
1614
- function DialogDescription({
1615
- className,
1616
- ...props
1617
- }) {
1618
- return /* @__PURE__ */ jsx(
1619
- Dialog$1.Description,
1620
- {
1621
- "data-slot": "dialog-description",
1622
- className: cn("text-sm text-muted-foreground", className),
1623
- ...props
1624
- }
1625
- );
1626
- }
1627
1748
  var Image = ({
1628
1749
  src,
1629
1750
  alt,
@@ -2649,7 +2770,16 @@ function UIRenderer({ node }) {
2649
2770
  return /* @__PURE__ */ jsx(Component, { ...componentProps, children: renderedChildren });
2650
2771
  }
2651
2772
  function MessageContent({ events }) {
2773
+ const latestSlotIndexes = /* @__PURE__ */ new Map();
2774
+ events.forEach((event, index) => {
2775
+ if (event.slot) {
2776
+ latestSlotIndexes.set(event.slot, index);
2777
+ }
2778
+ });
2652
2779
  return /* @__PURE__ */ jsx(Fragment, { children: events.map((event, index) => {
2780
+ if (event.slot && latestSlotIndexes.get(event.slot) !== index) {
2781
+ return null;
2782
+ }
2653
2783
  if (event.type === "text-delta") {
2654
2784
  return /* @__PURE__ */ jsx("span", { children: event.data?.delta }, index);
2655
2785
  }
@@ -2762,7 +2892,8 @@ function Thread({
2762
2892
  const handleSubmit = async (state, overrideInput) => {
2763
2893
  const text = (overrideInput ?? input).trim();
2764
2894
  const hasFiles = state?.files && Array.isArray(state.files) && state.files.length > 0;
2765
- if (!text && !hasFiles || isLoading) return;
2895
+ const hasOptions = state && Object.keys(state).filter((k) => k !== "threadId").length > 0;
2896
+ if (!text && !hasFiles && !hasOptions || isLoading) return;
2766
2897
  if (!overrideInput) setInput("");
2767
2898
  await sendEvent(
2768
2899
  {
@@ -2770,7 +2901,12 @@ function Thread({
2770
2901
  role: "user",
2771
2902
  data: { content: text || "" }
2772
2903
  },
2773
- { state: { ...state, threadId: activeThreadId ?? void 0 } }
2904
+ {
2905
+ state: {
2906
+ ...state,
2907
+ threadId: activeThreadId ?? void 0
2908
+ }
2909
+ }
2774
2910
  );
2775
2911
  };
2776
2912
  const handleStarterPromptClick = (prompt) => {
@@ -2866,11 +3002,39 @@ function ChatHeader({
2866
3002
  }
2867
3003
  );
2868
3004
  }
2869
- var ThreadList = ({
3005
+ var Dropdown = ({
2870
3006
  className,
2871
- emptyState,
2872
- onThreadSelect
3007
+ trigger,
3008
+ triggerClassName,
3009
+ items
2873
3010
  }) => {
3011
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
3012
+ /* @__PURE__ */ jsx(
3013
+ DropdownMenuTrigger,
3014
+ {
3015
+ className: triggerClassName,
3016
+ render: (props) => /* @__PURE__ */ jsx(
3017
+ Button,
3018
+ {
3019
+ variant: "ghost",
3020
+ size: "icon-xs",
3021
+ ...props,
3022
+ onClick: (e) => {
3023
+ e.stopPropagation();
3024
+ props.onClick?.(e);
3025
+ },
3026
+ children: trigger || /* @__PURE__ */ jsx(IconDotsVertical, { className: "size-3.5" })
3027
+ }
3028
+ )
3029
+ }
3030
+ ),
3031
+ /* @__PURE__ */ jsx(DropdownMenuContent, { align: "start", className: cn("w-32", className), children: items.map((item) => /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: item.onClick, children: [
3032
+ item.icon,
3033
+ /* @__PURE__ */ jsx("span", { children: item.label })
3034
+ ] }, item.label)) })
3035
+ ] });
3036
+ };
3037
+ var ThreadList = ({ className }) => {
2874
3038
  const { threads, activeThreadId, selectThread, deleteThread, isLoading } = useThreads();
2875
3039
  const sortedThreads = React11.useMemo(() => {
2876
3040
  return [...threads].sort((a, b) => {
@@ -2879,73 +3043,44 @@ var ThreadList = ({
2879
3043
  return dateB - dateA;
2880
3044
  });
2881
3045
  }, [threads]);
2882
- const handleThreadClick = (threadId) => {
2883
- if (threadId !== activeThreadId) {
2884
- selectThread(threadId);
2885
- }
2886
- onThreadSelect?.(threadId);
2887
- };
2888
3046
  const handleDelete = async (threadId) => {
2889
- try {
2890
- await deleteThread(threadId);
2891
- } catch (error) {
2892
- console.error("Failed to delete thread:", error);
2893
- }
2894
- };
2895
- return /* @__PURE__ */ jsx("div", { className: cn("flex flex-col h-full", className), children: /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto", children: isLoading && threads.length === 0 ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-8", children: /* @__PURE__ */ jsx(IconLoader2, { className: "size-5 animate-spin text-muted-foreground" }) }) : threads.length === 0 ? /* @__PURE__ */ jsx("div", { className: "p-4 text-center text-muted-foreground", children: emptyState || /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2896
- /* @__PURE__ */ jsx(IconMessage, { className: "size-8 mx-auto opacity-50" }),
2897
- /* @__PURE__ */ jsx("p", { className: "text-sm", children: "No threads yet" })
2898
- ] }) }) : /* @__PURE__ */ jsx("div", { className: "p-2 space-y-1", children: sortedThreads.map((thread) => {
2899
- const isActive = thread.id === activeThreadId;
2900
- return /* @__PURE__ */ jsxs(
2901
- "div",
2902
- {
2903
- onClick: () => handleThreadClick(thread.id),
2904
- className: cn(
2905
- "group relative flex items-center gap-3 px-3 py-1.5 rounded-lg cursor-pointer transition-colors",
2906
- isActive ? "bg-muted text-foreground" : "hover:bg-muted/50 text-muted-foreground hover:text-foreground"
2907
- ),
2908
- children: [
2909
- /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx("p", { className: "text-sm font-medium truncate", children: thread.title || `Thread ${thread.id.slice(0, 8)}` }) }),
2910
- /* @__PURE__ */ jsx("div", { className: "shrink-0 flex items-center opacity-0 group-hover:opacity-100 transition-opacity", children: /* @__PURE__ */ jsxs(DropdownMenu, { children: [
2911
- /* @__PURE__ */ jsx(
2912
- DropdownMenuTrigger,
2913
- {
2914
- render: (props) => /* @__PURE__ */ jsx(
2915
- Button,
2916
- {
2917
- variant: "ghost",
2918
- size: "icon-xs",
2919
- ...props,
2920
- onClick: (e) => {
2921
- e.stopPropagation();
2922
- props.onClick?.(e);
2923
- },
2924
- children: /* @__PURE__ */ jsx(IconDotsVertical, { className: "size-3.5" })
2925
- }
2926
- )
2927
- }
2928
- ),
2929
- /* @__PURE__ */ jsx(DropdownMenuContent, { align: "start", className: "w-32", children: /* @__PURE__ */ jsxs(
2930
- DropdownMenuItem,
2931
- {
2932
- variant: "destructive",
2933
- onClick: (e) => {
2934
- e.stopPropagation();
2935
- handleDelete(thread.id);
2936
- },
2937
- children: [
2938
- /* @__PURE__ */ jsx(IconTrash, { className: "size-4 mr-2" }),
2939
- /* @__PURE__ */ jsx("span", { children: "Delete" })
2940
- ]
2941
- }
2942
- ) })
2943
- ] }) })
3047
+ try {
3048
+ await deleteThread(threadId);
3049
+ } catch (error) {
3050
+ console.error("Failed to delete thread:", error);
3051
+ }
3052
+ };
3053
+ return /* @__PURE__ */ jsx(List, { className, children: sortedThreads.map((thread) => {
3054
+ const isActive = thread.id === activeThreadId;
3055
+ return /* @__PURE__ */ jsxs(
3056
+ ListItem,
3057
+ {
3058
+ onClickAction: {
3059
+ type: "client:navigate",
3060
+ data: {
3061
+ url: `?threadId=${thread.id}`
3062
+ }
3063
+ },
3064
+ className: isActive ? "bg-muted text-foreground group" : "hover:bg-muted/50 text-muted-foreground hover:text-foreground group",
3065
+ children: [
3066
+ /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx("p", { className: "text-sm font-medium truncate", children: thread.title || `Thread ${thread.id.slice(0, 8)}` }) }),
3067
+ /* @__PURE__ */ jsx("div", { className: "shrink-0 flex items-center opacity-0 group-hover:opacity-100 transition-opacity", children: /* @__PURE__ */ jsx(
3068
+ Dropdown,
3069
+ {
3070
+ items: [
3071
+ {
3072
+ label: "Delete",
3073
+ icon: /* @__PURE__ */ jsx(IconTrash, { className: "size-4" }),
3074
+ onClick: () => handleDelete(thread.id)
3075
+ }
3076
+ ]
3077
+ }
3078
+ ) })
2944
3079
  ]
2945
3080
  },
2946
3081
  thread.id
2947
3082
  );
2948
- }) }) }) });
3083
+ }) });
2949
3084
  };
2950
3085
  function PopupChat({
2951
3086
  title = "Chat",
@@ -3032,7 +3167,6 @@ function PopupChat({
3032
3167
  ) : /* @__PURE__ */ jsx(
3033
3168
  ThreadList,
3034
3169
  {
3035
- onThreadSelect: () => setView("chat"),
3036
3170
  className: "h-full"
3037
3171
  }
3038
3172
  ) })
@@ -3335,8 +3469,7 @@ var ThreadPopover = ({
3335
3469
  buttonClassName,
3336
3470
  buttonVariant = "ghost",
3337
3471
  buttonSize = "icon",
3338
- emptyState,
3339
- onThreadSelect
3472
+ emptyState
3340
3473
  }) => {
3341
3474
  const [isOpen, setIsOpen] = React11.useState(false);
3342
3475
  useHotkeys(
@@ -3352,10 +3485,6 @@ var ThreadPopover = ({
3352
3485
  // Don't trigger in contenteditable elements
3353
3486
  }
3354
3487
  );
3355
- const handleThreadSelect = (threadId) => {
3356
- setIsOpen(false);
3357
- onThreadSelect?.(threadId);
3358
- };
3359
3488
  return /* @__PURE__ */ jsxs(Popover, { open: isOpen, onOpenChange: setIsOpen, children: [
3360
3489
  /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
3361
3490
  Button,
@@ -3373,14 +3502,7 @@ var ThreadPopover = ({
3373
3502
  side: "bottom",
3374
3503
  align: "start",
3375
3504
  sideOffset: 8,
3376
- children: /* @__PURE__ */ jsx("div", { className: "flex flex-col h-[400px]", children: /* @__PURE__ */ jsx(
3377
- ThreadList,
3378
- {
3379
- emptyState,
3380
- onThreadSelect: handleThreadSelect,
3381
- className: "h-full"
3382
- }
3383
- ) })
3505
+ children: /* @__PURE__ */ jsx("div", { className: "flex flex-col h-[400px]", children: /* @__PURE__ */ jsx(ThreadList, { emptyState, className: "h-full" }) })
3384
3506
  }
3385
3507
  )
3386
3508
  ] });
@@ -3434,231 +3556,6 @@ var CreateThreadButton = ({
3434
3556
  }
3435
3557
  );
3436
3558
  };
3437
- function AlertDialog({ ...props }) {
3438
- return /* @__PURE__ */ jsx(AlertDialog$1.Root, { "data-slot": "alert-dialog", ...props });
3439
- }
3440
- function AlertDialogPortal({ ...props }) {
3441
- return /* @__PURE__ */ jsx(AlertDialog$1.Portal, { "data-slot": "alert-dialog-portal", ...props });
3442
- }
3443
- function AlertDialogOverlay({
3444
- className,
3445
- ...props
3446
- }) {
3447
- return /* @__PURE__ */ jsx(
3448
- AlertDialog$1.Backdrop,
3449
- {
3450
- "data-slot": "alert-dialog-overlay",
3451
- className: cn(
3452
- "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/80 duration-100 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 isolate z-50",
3453
- className
3454
- ),
3455
- ...props
3456
- }
3457
- );
3458
- }
3459
- function AlertDialogContent({
3460
- className,
3461
- size = "default",
3462
- ...props
3463
- }) {
3464
- return /* @__PURE__ */ jsxs(AlertDialogPortal, { children: [
3465
- /* @__PURE__ */ jsx(AlertDialogOverlay, {}),
3466
- /* @__PURE__ */ jsx(
3467
- AlertDialog$1.Popup,
3468
- {
3469
- "data-slot": "alert-dialog-content",
3470
- "data-size": size,
3471
- className: cn(
3472
- "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 bg-background ring-foreground/5 gap-6 rounded-4xl p-6 ring-1 duration-100 data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-md group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 outline-none",
3473
- className
3474
- ),
3475
- ...props
3476
- }
3477
- )
3478
- ] });
3479
- }
3480
- function AlertDialogHeader({
3481
- className,
3482
- ...props
3483
- }) {
3484
- return /* @__PURE__ */ jsx(
3485
- "div",
3486
- {
3487
- "data-slot": "alert-dialog-header",
3488
- className: cn("grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-6 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]", className),
3489
- ...props
3490
- }
3491
- );
3492
- }
3493
- function AlertDialogTitle({
3494
- className,
3495
- ...props
3496
- }) {
3497
- return /* @__PURE__ */ jsx(
3498
- AlertDialog$1.Title,
3499
- {
3500
- "data-slot": "alert-dialog-title",
3501
- className: cn("text-lg font-medium sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2", className),
3502
- ...props
3503
- }
3504
- );
3505
- }
3506
- function AlertDialogDescription({
3507
- className,
3508
- ...props
3509
- }) {
3510
- return /* @__PURE__ */ jsx(
3511
- AlertDialog$1.Description,
3512
- {
3513
- "data-slot": "alert-dialog-description",
3514
- className: cn("text-muted-foreground *:[a]:hover:text-foreground text-sm text-balance md:text-pretty *:[a]:underline *:[a]:underline-offset-3", className),
3515
- ...props
3516
- }
3517
- );
3518
- }
3519
- var AccountDialog = ({
3520
- className,
3521
- variant = "outline",
3522
- size
3523
- }) => {
3524
- const { isLoading, isAuthenticated, user, login, logout } = useAuth();
3525
- const [open, setOpen] = React11.useState(false);
3526
- const [accountInfoOpen, setAccountInfoOpen] = React11.useState(false);
3527
- const [error, setError] = React11.useState(null);
3528
- const initials = React11.useMemo(() => {
3529
- const name = user?.displayName || user?.name;
3530
- if (!name) return "";
3531
- return name.split(" ").map((n) => n[0]).join("").toUpperCase().slice(0, 2);
3532
- }, [user?.displayName, user?.name]);
3533
- const handleGoogleSignIn = async () => {
3534
- login();
3535
- };
3536
- if (isAuthenticated) {
3537
- return /* @__PURE__ */ jsxs(Fragment, { children: [
3538
- /* @__PURE__ */ jsxs(DropdownMenu, { children: [
3539
- /* @__PURE__ */ jsx(
3540
- DropdownMenuTrigger,
3541
- {
3542
- render: (props) => /* @__PURE__ */ jsx(
3543
- Button,
3544
- {
3545
- variant,
3546
- size: "icon",
3547
- ...props,
3548
- className: cn("rounded-full", className),
3549
- children: user?.picture ? /* @__PURE__ */ jsx(
3550
- "img",
3551
- {
3552
- src: user.picture,
3553
- alt: user.displayName || user.name,
3554
- className: "size-7 rounded-full object-cover"
3555
- }
3556
- ) : /* @__PURE__ */ jsx("div", { className: "flex size-7 items-center justify-center rounded-full bg-muted text-xs font-bold", children: initials || /* @__PURE__ */ jsx(IconUser, { className: "size-4" }) })
3557
- }
3558
- )
3559
- }
3560
- ),
3561
- /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", className: "w-56", children: [
3562
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 p-2", children: [
3563
- user?.picture ? /* @__PURE__ */ jsx(
3564
- "img",
3565
- {
3566
- src: user.picture,
3567
- alt: user.displayName || user.name,
3568
- className: "size-8 rounded-full object-cover"
3569
- }
3570
- ) : /* @__PURE__ */ jsx("div", { className: "flex size-8 items-center justify-center rounded-full bg-muted text-xs font-bold", children: initials || /* @__PURE__ */ jsx(IconUser, { className: "size-4" }) }),
3571
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col space-y-0.5 overflow-hidden", children: [
3572
- /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-medium", children: user?.displayName || user?.name }),
3573
- /* @__PURE__ */ jsx("p", { className: "truncate text-xs text-muted-foreground", children: user?.email })
3574
- ] })
3575
- ] }),
3576
- /* @__PURE__ */ jsx(Separator, { className: "my-1" }),
3577
- /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: () => setAccountInfoOpen(true), children: [
3578
- /* @__PURE__ */ jsx(IconUser, { className: "mr-2 size-4" }),
3579
- "Account Settings"
3580
- ] }),
3581
- /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: logout, className: "text-destructive", children: [
3582
- /* @__PURE__ */ jsx(IconLogout, { className: "mr-2 size-4" }),
3583
- "Logout"
3584
- ] })
3585
- ] })
3586
- ] }),
3587
- /* @__PURE__ */ jsx(Dialog, { open: accountInfoOpen, onOpenChange: setAccountInfoOpen, children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-md", children: [
3588
- /* @__PURE__ */ jsxs(DialogHeader, { children: [
3589
- /* @__PURE__ */ jsx(DialogTitle, { children: "Account Information" }),
3590
- /* @__PURE__ */ jsx(DialogDescription, { children: "Your account details and settings." })
3591
- ] }),
3592
- /* @__PURE__ */ jsxs(DialogClose, { children: [
3593
- /* @__PURE__ */ jsx(IconX, { className: "size-4" }),
3594
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
3595
- ] }),
3596
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 py-4", children: [
3597
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
3598
- user?.picture ? /* @__PURE__ */ jsx(
3599
- "img",
3600
- {
3601
- src: user.picture,
3602
- alt: user.displayName || user.name,
3603
- className: "size-16 rounded-full object-cover"
3604
- }
3605
- ) : /* @__PURE__ */ jsx("div", { className: "flex size-16 items-center justify-center rounded-full bg-muted text-xl font-bold", children: initials || /* @__PURE__ */ jsx(IconUser, { className: "size-8 text-muted-foreground" }) }),
3606
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
3607
- /* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold", children: user?.displayName || user?.name }),
3608
- /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: user?.email })
3609
- ] })
3610
- ] }),
3611
- /* @__PURE__ */ jsx(Separator, {}),
3612
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
3613
- /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
3614
- /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-muted-foreground", children: "User ID" }),
3615
- /* @__PURE__ */ jsx("p", { className: "font-mono text-xs truncate", children: user?.uid || user?.id })
3616
- ] }),
3617
- /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
3618
- /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-muted-foreground", children: "Created At" }),
3619
- /* @__PURE__ */ jsx("p", { className: "text-xs", children: user?.createdAt || "N/A" })
3620
- ] })
3621
- ] })
3622
- ] })
3623
- ] }) })
3624
- ] });
3625
- }
3626
- return /* @__PURE__ */ jsxs(Fragment, { children: [
3627
- /* @__PURE__ */ jsx(
3628
- Button,
3629
- {
3630
- variant,
3631
- size,
3632
- onClick: () => setOpen(true),
3633
- className,
3634
- children: "Sign in"
3635
- }
3636
- ),
3637
- /* @__PURE__ */ jsx(AlertDialog, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxs(AlertDialogContent, { className: "sm:max-w-md", children: [
3638
- /* @__PURE__ */ jsxs(AlertDialogHeader, { children: [
3639
- /* @__PURE__ */ jsx(AlertDialogTitle, { children: "Sign in to continue" }),
3640
- /* @__PURE__ */ jsx(AlertDialogDescription, { children: "Choose your preferred sign-in method to access your account." })
3641
- ] }),
3642
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 py-4", children: [
3643
- error && /* @__PURE__ */ jsx("div", { className: "rounded-lg bg-destructive/10 p-3 text-sm text-destructive", children: error }),
3644
- /* @__PURE__ */ jsxs(
3645
- Button,
3646
- {
3647
- onClick: handleGoogleSignIn,
3648
- disabled: isLoading,
3649
- variant: "outline",
3650
- className: "w-full",
3651
- size: "lg",
3652
- children: [
3653
- /* @__PURE__ */ jsx(IconBrandGoogle, { className: "mr-2 size-5" }),
3654
- isLoading ? "Signing in..." : "Continue with Google"
3655
- ]
3656
- }
3657
- )
3658
- ] })
3659
- ] }) })
3660
- ] });
3661
- };
3662
3559
  function ThemeToggle() {
3663
3560
  const { theme, setTheme, resolvedTheme } = useTheme();
3664
3561
  const cycleTheme = () => {
@@ -3694,7 +3591,53 @@ function ThemeToggle() {
3694
3591
  }
3695
3592
  );
3696
3593
  }
3594
+ var CreateThreadNavItem = ({
3595
+ className
3596
+ }) => {
3597
+ const { createThread } = useThreads();
3598
+ const [isCreating, setIsCreating] = React11.useState(false);
3599
+ const handleCreateThread = async () => {
3600
+ if (isCreating) return;
3601
+ try {
3602
+ setIsCreating(true);
3603
+ const threadId = await createThread();
3604
+ } catch (error) {
3605
+ console.error("Failed to create thread:", error);
3606
+ } finally {
3607
+ setIsCreating(false);
3608
+ }
3609
+ };
3610
+ useHotkeys(
3611
+ "n",
3612
+ (e) => {
3613
+ e.preventDefault();
3614
+ handleCreateThread();
3615
+ },
3616
+ {
3617
+ enableOnFormTags: false,
3618
+ // Don't trigger when typing in form inputs
3619
+ enableOnContentEditable: false
3620
+ // Don't trigger in contenteditable elements
3621
+ }
3622
+ );
3623
+ return /* @__PURE__ */ jsxs(
3624
+ ListItem,
3625
+ {
3626
+ onClickAction: {
3627
+ type: "client:navigate",
3628
+ data: {
3629
+ url: `?threadId=${generateId()}`
3630
+ }
3631
+ },
3632
+ className: cn(className),
3633
+ children: [
3634
+ /* @__PURE__ */ jsx(IconPlus, { className: "size-4" }),
3635
+ "New chat"
3636
+ ]
3637
+ }
3638
+ );
3639
+ };
3697
3640
 
3698
- export { AccountDialog, AuthContext, AuthProvider, Badge2 as Badge, Box, Button2 as Button, Card2 as Card, Chart, ChatHeader, Checkbox, Col, Composer, CreateThreadButton, Divider, Form, FullChat, Heading, Image, Input2 as Input, Label2 as Label, List, ListItem, MelonyContext, MelonyProvider, PopupChat, RadioGroup, Row, Select2 as Select, Sidebar, SidebarContext, SidebarProvider, SidebarToggle, Spacer, Text, Textarea2 as Textarea, ThemeProvider, ThemeToggle, Thread, ThreadContext, ThreadList, ThreadPopover, ThreadProvider, UIRenderer, WelcomeScreen, groupEventsToMessages, useAuth, useMelony, useScreenSize, useSidebar, useTheme, useThreads };
3641
+ export { AccountButton, AuthContext, AuthProvider, Badge2 as Badge, Box, Button2 as Button, Card2 as Card, Chart, ChatHeader, Checkbox, Col, Composer, CreateThreadButton, CreateThreadNavItem, Divider, Dropdown, Form, FullChat, Heading, Image, Input2 as Input, Label2 as Label, List, ListItem, MelonyContext, MelonyProvider, PopupChat, RadioGroup, Row, Select2 as Select, Sidebar, SidebarContext, SidebarProvider, SidebarToggle, Spacer, Text, Textarea2 as Textarea, ThemeProvider, ThemeToggle, Thread, ThreadContext, ThreadList, ThreadPopover, ThreadProvider, UIRenderer, WelcomeScreen, groupEventsToMessages, useAuth, useMelony, useScreenSize, useSidebar, useTheme, useThreads };
3699
3642
  //# sourceMappingURL=index.js.map
3700
3643
  //# sourceMappingURL=index.js.map