@melony/react 0.1.26 → 0.1.27

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
@@ -1,18 +1,18 @@
1
- import * as React12 from 'react';
2
- import React12__default, { createContext, useState, useCallback, useEffect, useMemo, useContext, useRef } from 'react';
1
+ import * as React11 from 'react';
2
+ import React11__default, { createContext, useState, useContext, useCallback, useMemo, useEffect, useRef } from 'react';
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 { generateId } from 'melony/client';
7
- import { useQueryState, parseAsString } from 'nuqs';
8
- import { clsx } from 'clsx';
9
- import { twMerge } from 'tailwind-merge';
10
6
  import { Button as Button$1 } from '@base-ui/react/button';
11
7
  import { cva } from 'class-variance-authority';
8
+ import { clsx } from 'clsx';
9
+ import { twMerge } from 'tailwind-merge';
10
+ 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 { generateId } from 'melony/client';
13
+ import { useQueryState, parseAsString } from 'nuqs';
12
14
  import { mergeProps } from '@base-ui/react/merge-props';
13
15
  import { useRender } from '@base-ui/react/use-render';
14
- import * as ICONS from '@tabler/icons-react';
15
- import { IconPaperclip, IconX, IconPlus, IconChevronDown, IconLoader2, IconArrowUp, IconMessage, IconDotsVertical, IconTrash, IconHistory, IconArrowLeft, IconBrandGoogle, IconLayoutSidebarLeftExpand, IconLayoutSidebarLeftCollapse, IconLayoutSidebarRightExpand, IconLayoutSidebarRightCollapse, IconUser, IconLogout, IconDeviceDesktop, IconMoon, IconSun, IconCheck, IconSelector, IconChevronUp } from '@tabler/icons-react';
16
16
  import { Menu } from '@base-ui/react/menu';
17
17
  import { Separator as Separator$1 } from '@base-ui/react/separator';
18
18
  import { Dialog as Dialog$1 } from '@base-ui/react/dialog';
@@ -167,49 +167,215 @@ var MelonyClientProvider = ({
167
167
  }
168
168
  ) }) });
169
169
  };
170
+ function cn(...inputs) {
171
+ return twMerge(clsx(inputs));
172
+ }
173
+ var buttonVariants = cva(
174
+ "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
+ {
176
+ variants: {
177
+ variant: {
178
+ default: "bg-primary text-primary-foreground hover:bg-primary/80",
179
+ outline: "border-border bg-input/30 hover:bg-input/50 hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground",
180
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
181
+ ghost: "hover:bg-muted hover:text-foreground dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground",
182
+ destructive: "bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30",
183
+ link: "text-primary underline-offset-4 hover:underline"
184
+ },
185
+ size: {
186
+ default: "h-9 gap-1.5 px-3 has-data-[icon=inline-end]:pr-2.5 has-data-[icon=inline-start]:pl-2.5",
187
+ xs: "h-6 gap-1 px-2.5 text-xs has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2 [&_svg:not([class*='size-'])]:size-3",
188
+ sm: "h-8 gap-1 px-3 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
189
+ lg: "h-10 gap-1.5 px-4 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3",
190
+ icon: "size-9",
191
+ "icon-xs": "size-6 [&_svg:not([class*='size-'])]:size-3",
192
+ "icon-sm": "size-8",
193
+ "icon-lg": "size-10"
194
+ }
195
+ },
196
+ defaultVariants: {
197
+ variant: "default",
198
+ size: "default"
199
+ }
200
+ }
201
+ );
202
+ function Button({
203
+ className,
204
+ variant = "default",
205
+ size = "default",
206
+ ...props
207
+ }) {
208
+ return /* @__PURE__ */ jsx(
209
+ Button$1,
210
+ {
211
+ "data-slot": "button",
212
+ className: cn(buttonVariants({ variant, size, className })),
213
+ ...props
214
+ }
215
+ );
216
+ }
217
+ var useAuth = () => {
218
+ const context = useContext(AuthContext);
219
+ if (context === void 0) {
220
+ throw new Error("useAuth must be used within an AuthProvider");
221
+ }
222
+ return context;
223
+ };
224
+ function WelcomeScreen({
225
+ title = "Welcome to Melony",
226
+ description = "The most powerful AI agent framework for building modern applications. Connect your tools, build your brain, and ship faster.",
227
+ features = [
228
+ {
229
+ title: "Context Aware",
230
+ description: "Built-in state management for complex LLM flows."
231
+ },
232
+ {
233
+ title: "Extensible",
234
+ description: "Plugin architecture for easy integrations."
235
+ },
236
+ {
237
+ title: "Real-time",
238
+ description: "Streaming responses and live state updates."
239
+ },
240
+ {
241
+ title: "Tool-ready",
242
+ description: "Ready-to-use actions for common tasks."
243
+ }
244
+ ],
245
+ className,
246
+ onLoginClick,
247
+ termsUrl = "#",
248
+ privacyUrl = "#",
249
+ imageUrl,
250
+ imageAlt = "Product screenshot"
251
+ }) {
252
+ const { login, isLoading } = useAuth();
253
+ const handleLogin = () => {
254
+ if (onLoginClick) {
255
+ onLoginClick();
256
+ } else {
257
+ login();
258
+ }
259
+ };
260
+ return /* @__PURE__ */ jsxs(
261
+ "div",
262
+ {
263
+ className: cn(
264
+ "flex min-h-[600px] h-full w-full flex-col md:flex-row bg-background overflow-hidden",
265
+ className
266
+ ),
267
+ children: [
268
+ /* @__PURE__ */ jsxs("div", { className: "flex w-8/12 flex-col bg-sidebar text-foreground relative overflow-hidden", children: [
269
+ /* @__PURE__ */ jsx("div", { className: "absolute -top-24 -left-24 size-96 bg-primary/5 rounded-full blur-3xl" }),
270
+ /* @__PURE__ */ jsx("div", { className: "absolute -bottom-24 -right-24 size-96 bg-primary/5 rounded-full blur-3xl" }),
271
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto overflow-x-hidden relative z-10 flex flex-col p-8 md:p-12 lg:p-20", children: /* @__PURE__ */ jsxs("div", { className: "max-w-xl mx-auto w-full my-auto", children: [
272
+ /* @__PURE__ */ jsx("h1", { className: "mb-6 text-4xl font-bold tracking-tight md:text-5xl lg:text-6xl text-foreground", children: title }),
273
+ /* @__PURE__ */ jsx("p", { className: "mb-12 text-lg text-muted-foreground md:text-xl leading-relaxed", children: description }),
274
+ imageUrl && /* @__PURE__ */ jsxs("div", { className: "mb-12 relative group", children: [
275
+ /* @__PURE__ */ jsx("div", { className: "absolute -inset-1 bg-gradient-to-r from-primary/20 to-primary/10 rounded-xl blur opacity-25 group-hover:opacity-50 transition duration-1000 group-hover:duration-200" }),
276
+ /* @__PURE__ */ jsx(
277
+ "img",
278
+ {
279
+ src: imageUrl,
280
+ alt: imageAlt,
281
+ className: "relative rounded-xl border border-border/50 shadow-2xl transition-transform duration-500 hover:scale-[1.02] w-full"
282
+ }
283
+ )
284
+ ] }),
285
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-x-8 gap-y-10 sm:grid-cols-2", children: features.map((feature, i) => /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
286
+ /* @__PURE__ */ jsx("h3", { className: "font-bold text-lg text-foreground", children: feature.title }),
287
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground leading-relaxed", children: feature.description })
288
+ ] }, i)) })
289
+ ] }) })
290
+ ] }),
291
+ /* @__PURE__ */ jsx("div", { className: "flex w-4/12 flex-col overflow-y-auto p-8 md:p-12 lg:p-20 bg-background transition-colors duration-300", children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-sm space-y-8 my-auto mx-auto", children: [
292
+ /* @__PURE__ */ jsxs("div", { className: "space-y-3 text-center md:text-left", children: [
293
+ /* @__PURE__ */ jsx("h2", { className: "text-3xl font-bold tracking-tight text-foreground", children: "Get Started" }),
294
+ /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-lg", children: "Sign in to your account to continue" })
295
+ ] }),
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
+ ] }),
316
+ /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground leading-relaxed text-center md:text-left", children: [
317
+ "By continuing, you agree to our ",
318
+ /* @__PURE__ */ jsx("br", { className: "hidden md:block" }),
319
+ /* @__PURE__ */ jsx(
320
+ "a",
321
+ {
322
+ href: termsUrl,
323
+ target: "_blank",
324
+ rel: "noopener noreferrer",
325
+ className: "underline underline-offset-4 hover:text-primary transition-colors font-medium",
326
+ children: "Terms of Service"
327
+ }
328
+ ),
329
+ " ",
330
+ "and",
331
+ " ",
332
+ /* @__PURE__ */ jsx(
333
+ "a",
334
+ {
335
+ href: privacyUrl,
336
+ target: "_blank",
337
+ rel: "noopener noreferrer",
338
+ className: "underline underline-offset-4 hover:text-primary transition-colors font-medium",
339
+ children: "Privacy Policy"
340
+ }
341
+ ),
342
+ "."
343
+ ] })
344
+ ] }) })
345
+ ]
346
+ }
347
+ );
348
+ }
170
349
  var AuthContext = createContext(
171
350
  void 0
172
351
  );
173
352
  var AuthProvider = ({
174
353
  children,
175
- service
354
+ service,
355
+ welcomeScreenProps
176
356
  }) => {
177
- const [user, setUser] = useState(null);
178
- const [isLoading, setIsLoading] = useState(true);
179
- const fetchMe = useCallback(async () => {
180
- setIsLoading(true);
181
- try {
182
- const userData = await service.getMe();
183
- setUser(userData);
184
- } catch (error) {
185
- console.error("Failed to fetch user:", error);
186
- setUser(null);
187
- } finally {
188
- setIsLoading(false);
357
+ const queryClient = useQueryClient();
358
+ const { data: user, isLoading } = useQuery({
359
+ queryKey: ["auth-user", service],
360
+ queryFn: () => service.getMe(),
361
+ retry: false
362
+ });
363
+ const logoutMutation = useMutation({
364
+ mutationFn: () => service.logout(),
365
+ onSuccess: () => {
366
+ queryClient.setQueryData(["auth-user", service], null);
189
367
  }
190
- }, [service]);
191
- useEffect(() => {
192
- fetchMe();
193
- }, [fetchMe]);
368
+ });
194
369
  const login = useCallback(() => {
195
370
  service.login();
196
371
  }, [service]);
197
372
  const logout = useCallback(async () => {
198
373
  try {
199
- await service.logout();
200
- setUser(null);
374
+ await logoutMutation.mutateAsync();
201
375
  } catch (error) {
202
376
  console.error("Failed to logout:", error);
203
377
  }
204
- }, [service]);
205
- const value = {
206
- user,
207
- isAuthenticated: !!user,
208
- isLoading,
209
- login,
210
- logout,
211
- getToken: service.getToken
212
- };
378
+ }, [logoutMutation]);
213
379
  if (isLoading) {
214
380
  return /* @__PURE__ */ jsx(
215
381
  "div",
@@ -228,7 +394,15 @@ var AuthProvider = ({
228
394
  }
229
395
  );
230
396
  }
231
- return /* @__PURE__ */ jsx(AuthContext.Provider, { value, children });
397
+ const value = {
398
+ user: user || null,
399
+ isAuthenticated: !!user,
400
+ isLoading,
401
+ login,
402
+ logout,
403
+ getToken: service.getToken
404
+ };
405
+ return /* @__PURE__ */ jsx(AuthContext.Provider, { value, children: !value.isAuthenticated && welcomeScreenProps ? /* @__PURE__ */ jsx(WelcomeScreen, { ...welcomeScreenProps }) : children });
232
406
  };
233
407
  var ThreadContext = createContext(
234
408
  void 0
@@ -325,6 +499,103 @@ var ThreadProvider = ({
325
499
  );
326
500
  return /* @__PURE__ */ jsx(ThreadContext.Provider, { value, children });
327
501
  };
502
+ function useScreenSize(mobileBreakpoint = 768, tabletBreakpoint = 1024) {
503
+ const [screenSize, setScreenSize] = useState(() => {
504
+ if (typeof window === "undefined") {
505
+ return {
506
+ width: 1024,
507
+ height: 768,
508
+ isMobile: false,
509
+ isTablet: false,
510
+ isDesktop: true
511
+ };
512
+ }
513
+ const width = window.innerWidth;
514
+ return {
515
+ width,
516
+ height: window.innerHeight,
517
+ isMobile: width < mobileBreakpoint,
518
+ isTablet: width >= mobileBreakpoint && width < tabletBreakpoint,
519
+ isDesktop: width >= tabletBreakpoint
520
+ };
521
+ });
522
+ useEffect(() => {
523
+ if (typeof window === "undefined") return;
524
+ const updateScreenSize = () => {
525
+ const width = window.innerWidth;
526
+ const height = window.innerHeight;
527
+ setScreenSize({
528
+ width,
529
+ height,
530
+ isMobile: width < mobileBreakpoint,
531
+ isTablet: width >= mobileBreakpoint && width < tabletBreakpoint,
532
+ isDesktop: width >= tabletBreakpoint
533
+ });
534
+ };
535
+ updateScreenSize();
536
+ window.addEventListener("resize", updateScreenSize);
537
+ return () => {
538
+ window.removeEventListener("resize", updateScreenSize);
539
+ };
540
+ }, [mobileBreakpoint, tabletBreakpoint]);
541
+ return screenSize;
542
+ }
543
+ var SidebarContext = createContext(
544
+ void 0
545
+ );
546
+ function useSidebar() {
547
+ const context = useContext(SidebarContext);
548
+ if (context === void 0) {
549
+ throw new Error("useSidebar must be used within a SidebarProvider");
550
+ }
551
+ return context;
552
+ }
553
+ function SidebarProvider({
554
+ children,
555
+ defaultLeftCollapsed,
556
+ defaultRightCollapsed
557
+ }) {
558
+ const { isMobile, isTablet } = useScreenSize();
559
+ const isSmallScreen = isMobile || isTablet;
560
+ const [leftCollapsed, setLeftCollapsed] = useState(() => {
561
+ if (defaultLeftCollapsed !== void 0) return defaultLeftCollapsed;
562
+ if (typeof window !== "undefined") {
563
+ return window.innerWidth < 1024;
564
+ }
565
+ return false;
566
+ });
567
+ const [rightCollapsed, setRightCollapsed] = useState(() => {
568
+ if (defaultRightCollapsed !== void 0) return defaultRightCollapsed;
569
+ if (typeof window !== "undefined") {
570
+ return window.innerWidth < 1024;
571
+ }
572
+ return false;
573
+ });
574
+ useEffect(() => {
575
+ if (isSmallScreen) {
576
+ setLeftCollapsed(true);
577
+ setRightCollapsed(true);
578
+ }
579
+ }, [isSmallScreen]);
580
+ const handleLeftToggle = useCallback((collapsed) => {
581
+ setLeftCollapsed(collapsed);
582
+ }, []);
583
+ const handleRightToggle = useCallback((collapsed) => {
584
+ setRightCollapsed(collapsed);
585
+ }, []);
586
+ const contextValue = useMemo(
587
+ () => ({
588
+ leftCollapsed,
589
+ rightCollapsed,
590
+ setLeftCollapsed: handleLeftToggle,
591
+ setRightCollapsed: handleRightToggle,
592
+ leftCollapsible: true,
593
+ rightCollapsible: true
594
+ }),
595
+ [leftCollapsed, rightCollapsed, handleLeftToggle, handleRightToggle]
596
+ );
597
+ return /* @__PURE__ */ jsx(SidebarContext.Provider, { value: contextValue, children });
598
+ }
328
599
  var ThemeContext = createContext(void 0);
329
600
  function ThemeProvider({ children }) {
330
601
  const [theme, setThemeState] = useState("system");
@@ -398,13 +669,6 @@ var useMelony = (options) => {
398
669
  }, [client, initialEvents, reset]);
399
670
  return context;
400
671
  };
401
- var useAuth = () => {
402
- const context = useContext(AuthContext);
403
- if (context === void 0) {
404
- throw new Error("useAuth must be used within an AuthProvider");
405
- }
406
- return context;
407
- };
408
672
  var useThreads = () => {
409
673
  const context = useContext(ThreadContext);
410
674
  if (context === void 0) {
@@ -412,94 +676,6 @@ var useThreads = () => {
412
676
  }
413
677
  return context;
414
678
  };
415
- function useScreenSize(mobileBreakpoint = 768, tabletBreakpoint = 1024) {
416
- const [screenSize, setScreenSize] = useState(() => {
417
- if (typeof window === "undefined") {
418
- return {
419
- width: 1024,
420
- height: 768,
421
- isMobile: false,
422
- isTablet: false,
423
- isDesktop: true
424
- };
425
- }
426
- const width = window.innerWidth;
427
- return {
428
- width,
429
- height: window.innerHeight,
430
- isMobile: width < mobileBreakpoint,
431
- isTablet: width >= mobileBreakpoint && width < tabletBreakpoint,
432
- isDesktop: width >= tabletBreakpoint
433
- };
434
- });
435
- useEffect(() => {
436
- if (typeof window === "undefined") return;
437
- const updateScreenSize = () => {
438
- const width = window.innerWidth;
439
- const height = window.innerHeight;
440
- setScreenSize({
441
- width,
442
- height,
443
- isMobile: width < mobileBreakpoint,
444
- isTablet: width >= mobileBreakpoint && width < tabletBreakpoint,
445
- isDesktop: width >= tabletBreakpoint
446
- });
447
- };
448
- updateScreenSize();
449
- window.addEventListener("resize", updateScreenSize);
450
- return () => {
451
- window.removeEventListener("resize", updateScreenSize);
452
- };
453
- }, [mobileBreakpoint, tabletBreakpoint]);
454
- return screenSize;
455
- }
456
- function cn(...inputs) {
457
- return twMerge(clsx(inputs));
458
- }
459
- var buttonVariants = cva(
460
- "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",
461
- {
462
- variants: {
463
- variant: {
464
- default: "bg-primary text-primary-foreground hover:bg-primary/80",
465
- outline: "border-border bg-input/30 hover:bg-input/50 hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground",
466
- secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
467
- ghost: "hover:bg-muted hover:text-foreground dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground",
468
- destructive: "bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30",
469
- link: "text-primary underline-offset-4 hover:underline"
470
- },
471
- size: {
472
- default: "h-9 gap-1.5 px-3 has-data-[icon=inline-end]:pr-2.5 has-data-[icon=inline-start]:pl-2.5",
473
- xs: "h-6 gap-1 px-2.5 text-xs has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2 [&_svg:not([class*='size-'])]:size-3",
474
- sm: "h-8 gap-1 px-3 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
475
- lg: "h-10 gap-1.5 px-4 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3",
476
- icon: "size-9",
477
- "icon-xs": "size-6 [&_svg:not([class*='size-'])]:size-3",
478
- "icon-sm": "size-8",
479
- "icon-lg": "size-10"
480
- }
481
- },
482
- defaultVariants: {
483
- variant: "default",
484
- size: "default"
485
- }
486
- }
487
- );
488
- function Button({
489
- className,
490
- variant = "default",
491
- size = "default",
492
- ...props
493
- }) {
494
- return /* @__PURE__ */ jsx(
495
- Button$1,
496
- {
497
- "data-slot": "button",
498
- className: cn(buttonVariants({ variant, size, className })),
499
- ...props
500
- }
501
- );
502
- }
503
679
  function Textarea({ className, ...props }) {
504
680
  return /* @__PURE__ */ jsx(
505
681
  "textarea",
@@ -685,11 +861,26 @@ function Composer({
685
861
  const accept = fileAttachments?.accept;
686
862
  const maxFiles = fileAttachments?.maxFiles ?? 10;
687
863
  const maxFileSize = fileAttachments?.maxFileSize ?? 10 * 1024 * 1024;
688
- const [selectedOptions, setSelectedOptions] = React12__default.useState(
864
+ const [selectedOptions, setSelectedOptions] = React11__default.useState(
689
865
  () => new Set(defaultSelectedIds)
690
866
  );
691
- const [attachedFiles, setAttachedFiles] = React12__default.useState([]);
692
- const fileInputRef = React12__default.useRef(null);
867
+ const [attachedFiles, setAttachedFiles] = React11__default.useState([]);
868
+ const [previews, setPreviews] = React11__default.useState([]);
869
+ const fileInputRef = React11__default.useRef(null);
870
+ React11__default.useEffect(() => {
871
+ const newPreviews = attachedFiles.map((file) => ({
872
+ name: file.name,
873
+ type: file.type,
874
+ size: file.size,
875
+ url: file.type.startsWith("image/") ? URL.createObjectURL(file) : ""
876
+ }));
877
+ setPreviews(newPreviews);
878
+ return () => {
879
+ newPreviews.forEach((p) => {
880
+ if (p.url) URL.revokeObjectURL(p.url);
881
+ });
882
+ };
883
+ }, [attachedFiles]);
693
884
  const toggleOption = (id, groupOptions, type = "multiple") => {
694
885
  const next = new Set(selectedOptions);
695
886
  if (type === "single") {
@@ -735,11 +926,6 @@ function Composer({
735
926
  const handleRemoveFile = (index) => {
736
927
  setAttachedFiles((prev) => prev.filter((_, i) => i !== index));
737
928
  };
738
- const formatFileSize = (bytes) => {
739
- if (bytes < 1024) return bytes + " B";
740
- if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + " KB";
741
- return (bytes / (1024 * 1024)).toFixed(1) + " MB";
742
- };
743
929
  const handleInternalSubmit = async () => {
744
930
  const state = {};
745
931
  options.forEach((group) => {
@@ -805,13 +991,56 @@ function Composer({
805
991
  handleInternalSubmit().catch(console.error);
806
992
  }
807
993
  };
994
+ const handlePaste = (e) => {
995
+ if (!enabled) return;
996
+ const items = Array.from(e.clipboardData.items);
997
+ const files = items.map((item) => item.getAsFile()).filter((file) => file !== null);
998
+ if (files.length > 0) {
999
+ const remainingSlots = maxFiles - attachedFiles.length;
1000
+ const validFiles = files.filter((f) => f.size <= maxFileSize);
1001
+ const filesToAdd = validFiles.slice(0, remainingSlots);
1002
+ if (filesToAdd.length > 0) {
1003
+ setAttachedFiles((prev) => [...prev, ...filesToAdd]);
1004
+ }
1005
+ }
1006
+ };
808
1007
  return /* @__PURE__ */ jsx("div", { className: cn("relative flex flex-col w-full", className), children: /* @__PURE__ */ jsxs("div", { className: "relative flex flex-col w-full border-input border-[1.5px] rounded-3xl bg-background shadow-sm focus-within:border-ring transition-all p-2", children: [
1008
+ previews.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-3 p-2 px-3 pb-3", children: previews.map((preview, index) => /* @__PURE__ */ jsxs(
1009
+ "div",
1010
+ {
1011
+ className: "group relative flex flex-col items-center justify-center w-20 h-20 rounded-xl border bg-muted/30 overflow-hidden shadow-sm",
1012
+ children: [
1013
+ preview.type.startsWith("image/") ? /* @__PURE__ */ jsx(
1014
+ "img",
1015
+ {
1016
+ src: preview.url,
1017
+ alt: preview.name,
1018
+ className: "w-full h-full object-cover"
1019
+ }
1020
+ ) : /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center p-2 text-center", children: [
1021
+ preview.type.includes("text") || preview.type.includes("pdf") ? /* @__PURE__ */ jsx(IconFileText, { className: "h-8 w-8 text-muted-foreground" }) : /* @__PURE__ */ jsx(IconFile, { className: "h-8 w-8 text-muted-foreground" }),
1022
+ /* @__PURE__ */ jsx("span", { className: "text-[9px] truncate w-full px-1 mt-1 text-muted-foreground", children: preview.name })
1023
+ ] }),
1024
+ /* @__PURE__ */ jsx(
1025
+ "button",
1026
+ {
1027
+ type: "button",
1028
+ onClick: () => handleRemoveFile(index),
1029
+ className: "absolute top-1 right-1 p-1 rounded-full bg-foreground/10 hover:bg-foreground/20 backdrop-blur-md opacity-0 group-hover:opacity-100 transition-opacity",
1030
+ children: /* @__PURE__ */ jsx(IconX, { className: "h-3 w-3" })
1031
+ }
1032
+ )
1033
+ ]
1034
+ },
1035
+ index
1036
+ )) }),
809
1037
  /* @__PURE__ */ jsx(
810
1038
  Textarea,
811
1039
  {
812
1040
  value,
813
1041
  onChange: (e) => onChange(e.target.value),
814
1042
  onKeyDown: handleKeyDown,
1043
+ onPaste: handlePaste,
815
1044
  placeholder,
816
1045
  className: "min-h-[44px] max-h-[200px] border-none bg-transparent focus-visible:ring-0 focus-visible:ring-offset-0 px-3 py-2 text-[15px] resize-none",
817
1046
  autoFocus
@@ -832,100 +1061,22 @@ function Composer({
832
1061
  disabled: isLoading || attachedFiles.length >= maxFiles
833
1062
  }
834
1063
  ),
835
- attachedFiles.length === 0 ? /* @__PURE__ */ jsx(
1064
+ /* @__PURE__ */ jsxs(
836
1065
  Button,
837
1066
  {
838
1067
  type: "button",
839
1068
  variant: "ghost",
840
1069
  size: "sm",
841
1070
  onClick: () => fileInputRef.current?.click(),
842
- disabled: isLoading,
1071
+ disabled: isLoading || attachedFiles.length >= maxFiles,
843
1072
  className: "text-muted-foreground",
844
1073
  title: "Attach file",
845
- children: /* @__PURE__ */ jsx(IconPaperclip, { className: "h-4 w-4" })
1074
+ children: [
1075
+ /* @__PURE__ */ jsx(IconPaperclip, { className: "h-4 w-4" }),
1076
+ attachedFiles.length > 0 && /* @__PURE__ */ jsx(Badge, { className: "ml-1 h-[18px] min-w-[18px] px-1.5 text-[10px]", children: attachedFiles.length })
1077
+ ]
846
1078
  }
847
- ) : /* @__PURE__ */ jsxs(DropdownMenu, { children: [
848
- /* @__PURE__ */ jsx(
849
- DropdownMenuTrigger,
850
- {
851
- render: /* @__PURE__ */ jsxs(
852
- Button,
853
- {
854
- type: "button",
855
- variant: "ghost",
856
- size: "sm",
857
- className: "text-muted-foreground gap-2",
858
- title: `${attachedFiles.length} files attached`,
859
- children: [
860
- /* @__PURE__ */ jsx(IconPaperclip, { className: "h-4 w-4" }),
861
- /* @__PURE__ */ jsx(Badge, { className: "h-[18px] min-w-[18px] px-1.5 text-[10px]", children: attachedFiles.length })
862
- ]
863
- }
864
- )
865
- }
866
- ),
867
- /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "start", className: "w-64", children: [
868
- /* @__PURE__ */ jsxs(DropdownMenuGroup, { children: [
869
- /* @__PURE__ */ jsxs(DropdownMenuLabel, { children: [
870
- "Attached Files (",
871
- attachedFiles.length,
872
- "/",
873
- maxFiles,
874
- ")"
875
- ] }),
876
- /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
877
- attachedFiles.map((file, index) => /* @__PURE__ */ jsxs(
878
- DropdownMenuItem,
879
- {
880
- className: "flex items-center justify-between group",
881
- onSelect: (e) => e.preventDefault(),
882
- children: [
883
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-w-0 flex-1", children: [
884
- /* @__PURE__ */ jsx(
885
- "span",
886
- {
887
- className: "truncate text-sm",
888
- title: file.name,
889
- children: file.name
890
- }
891
- ),
892
- /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: formatFileSize(file.size) })
893
- ] }),
894
- /* @__PURE__ */ jsx(
895
- Button,
896
- {
897
- type: "button",
898
- variant: "ghost",
899
- size: "icon",
900
- className: "h-6 w-6 opacity-0 group-hover:opacity-100 transition-opacity",
901
- onClick: () => handleRemoveFile(index),
902
- children: /* @__PURE__ */ jsx(IconX, { className: "h-3 w-3" })
903
- }
904
- )
905
- ]
906
- },
907
- index
908
- ))
909
- ] }),
910
- attachedFiles.length < maxFiles && /* @__PURE__ */ jsxs(Fragment, { children: [
911
- /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
912
- /* @__PURE__ */ jsxs(
913
- DropdownMenuItem,
914
- {
915
- onSelect: (e) => {
916
- e.preventDefault();
917
- fileInputRef.current?.click();
918
- },
919
- className: "text-primary focus:text-primary",
920
- children: [
921
- /* @__PURE__ */ jsx(IconPlus, { className: "mr-2 h-4 w-4" }),
922
- /* @__PURE__ */ jsx("span", { children: "Add more files" })
923
- ]
924
- }
925
- )
926
- ] })
927
- ] })
928
- ] })
1079
+ )
929
1080
  ] }),
930
1081
  options.map((group) => {
931
1082
  const selectedInGroup = group.options.filter(
@@ -2720,15 +2871,8 @@ var ThreadList = ({
2720
2871
  emptyState,
2721
2872
  onThreadSelect
2722
2873
  }) => {
2723
- const {
2724
- threads,
2725
- activeThreadId,
2726
- selectThread,
2727
- createThread,
2728
- deleteThread,
2729
- isLoading
2730
- } = useThreads();
2731
- const sortedThreads = React12.useMemo(() => {
2874
+ const { threads, activeThreadId, selectThread, deleteThread, isLoading } = useThreads();
2875
+ const sortedThreads = React11.useMemo(() => {
2732
2876
  return [...threads].sort((a, b) => {
2733
2877
  const dateA = a.updatedAt ? new Date(a.updatedAt).getTime() : 0;
2734
2878
  const dateB = b.updatedAt ? new Date(b.updatedAt).getTime() : 0;
@@ -2745,87 +2889,65 @@ var ThreadList = ({
2745
2889
  try {
2746
2890
  await deleteThread(threadId);
2747
2891
  } catch (error) {
2748
- console.error("Failed to delete thread:", error);
2749
- }
2750
- };
2751
- const handleNewThread = async () => {
2752
- try {
2753
- await createThread();
2754
- } catch (error) {
2755
- console.error("Failed to create thread:", error);
2892
+ console.error("Failed to delete thread:", error);
2756
2893
  }
2757
2894
  };
2758
- return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col h-full", className), children: [
2759
- /* @__PURE__ */ jsx("div", { className: "p-2", children: /* @__PURE__ */ jsxs(
2760
- Button,
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",
2761
2902
  {
2762
- variant: "outline",
2763
- className: "w-full justify-start gap-2 h-9 px-3 border-dashed hover:border-solid transition-all",
2764
- onClick: handleNewThread,
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
+ ),
2765
2908
  children: [
2766
- /* @__PURE__ */ jsx(IconPlus, { className: "size-4" }),
2767
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: "New chat" })
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
+ ] }) })
2768
2944
  ]
2769
- }
2770
- ) }),
2771
- /* @__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: [
2772
- /* @__PURE__ */ jsx(IconMessage, { className: "size-8 mx-auto opacity-50" }),
2773
- /* @__PURE__ */ jsx("p", { className: "text-sm", children: "No threads yet" }),
2774
- /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: handleNewThread, children: "Start a conversation" })
2775
- ] }) }) : /* @__PURE__ */ jsx("div", { className: "p-2 space-y-1", children: sortedThreads.map((thread) => {
2776
- const isActive = thread.id === activeThreadId;
2777
- return /* @__PURE__ */ jsxs(
2778
- "div",
2779
- {
2780
- onClick: () => handleThreadClick(thread.id),
2781
- className: cn(
2782
- "group relative flex items-center gap-3 px-3 py-1.5 rounded-lg cursor-pointer transition-colors",
2783
- isActive ? "bg-muted text-foreground" : "hover:bg-muted/50 text-muted-foreground hover:text-foreground"
2784
- ),
2785
- children: [
2786
- /* @__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)}` }) }),
2787
- /* @__PURE__ */ jsx("div", { className: "shrink-0 flex items-center opacity-0 group-hover:opacity-100 transition-opacity", children: /* @__PURE__ */ jsxs(DropdownMenu, { children: [
2788
- /* @__PURE__ */ jsx(
2789
- DropdownMenuTrigger,
2790
- {
2791
- render: (props) => /* @__PURE__ */ jsx(
2792
- Button,
2793
- {
2794
- variant: "ghost",
2795
- size: "icon-xs",
2796
- ...props,
2797
- onClick: (e) => {
2798
- e.stopPropagation();
2799
- props.onClick?.(e);
2800
- },
2801
- children: /* @__PURE__ */ jsx(IconDotsVertical, { className: "size-3.5" })
2802
- }
2803
- )
2804
- }
2805
- ),
2806
- /* @__PURE__ */ jsx(DropdownMenuContent, { align: "start", className: "w-32", children: /* @__PURE__ */ jsxs(
2807
- DropdownMenuItem,
2808
- {
2809
- variant: "destructive",
2810
- onClick: (e) => {
2811
- e.stopPropagation();
2812
- handleDelete(thread.id);
2813
- },
2814
- children: [
2815
- /* @__PURE__ */ jsx(IconTrash, { className: "size-4 mr-2" }),
2816
- /* @__PURE__ */ jsx("span", { children: "Delete" })
2817
- ]
2818
- }
2819
- ) })
2820
- ] }) })
2821
- ]
2822
- },
2823
- thread.id
2824
- );
2825
- }) }) })
2826
- ] });
2945
+ },
2946
+ thread.id
2947
+ );
2948
+ }) }) }) });
2827
2949
  };
2828
- function ChatPopup({
2950
+ function PopupChat({
2829
2951
  title = "Chat",
2830
2952
  placeholder = "Message the AI",
2831
2953
  starterPrompts,
@@ -2929,266 +3051,45 @@ function ChatPopup({
2929
3051
  )
2930
3052
  ] });
2931
3053
  }
2932
- function ChatSidebar({
2933
- title = "Chat",
2934
- placeholder = "Message the AI",
2935
- starterPrompts,
2936
- options,
2937
- className,
2938
- headerProps,
2939
- defaultSelectedIds
2940
- }) {
2941
- return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col h-full border-r bg-background w-80", className), children: [
2942
- /* @__PURE__ */ jsx(ChatHeader, { title, ...headerProps }),
2943
- /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsx(
2944
- Thread,
2945
- {
2946
- placeholder,
2947
- starterPrompts,
2948
- options,
2949
- className: "h-full",
2950
- defaultSelectedIds
2951
- }
2952
- ) })
2953
- ] });
2954
- }
2955
- var ChatSidebarContext = createContext(
2956
- void 0
2957
- );
2958
- function useChatSidebar() {
2959
- const context = useContext(ChatSidebarContext);
2960
- if (context === void 0) {
2961
- throw new Error("useChatSidebar must be used within a ChatSidebarProvider");
2962
- }
2963
- return context;
2964
- }
2965
- function WelcomeScreen({
2966
- title = "Welcome to Melony",
2967
- description = "The most powerful AI agent framework for building modern applications. Connect your tools, build your brain, and ship faster.",
2968
- features = [
2969
- {
2970
- title: "Context Aware",
2971
- description: "Built-in state management for complex LLM flows."
2972
- },
2973
- {
2974
- title: "Extensible",
2975
- description: "Plugin architecture for easy integrations."
2976
- },
2977
- {
2978
- title: "Real-time",
2979
- description: "Streaming responses and live state updates."
2980
- },
2981
- {
2982
- title: "Tool-ready",
2983
- description: "Ready-to-use actions for common tasks."
2984
- }
2985
- ],
2986
- className,
2987
- onLoginClick,
2988
- termsUrl = "#",
2989
- privacyUrl = "#",
2990
- imageUrl,
2991
- imageAlt = "Product screenshot"
2992
- }) {
2993
- const { login, isLoading } = useAuth();
2994
- const handleLogin = () => {
2995
- if (onLoginClick) {
2996
- onLoginClick();
2997
- } else {
2998
- login();
2999
- }
3000
- };
3001
- return /* @__PURE__ */ jsxs(
3054
+ function Sidebar({ side, children, className }) {
3055
+ const { leftCollapsed, rightCollapsed } = useSidebar();
3056
+ const collapsed = side === "left" ? leftCollapsed : rightCollapsed;
3057
+ return /* @__PURE__ */ jsx(
3002
3058
  "div",
3003
3059
  {
3004
3060
  className: cn(
3005
- "flex min-h-[600px] h-full w-full flex-col md:flex-row bg-background overflow-hidden",
3006
- className
3061
+ "flex-shrink-0 border-border bg-background transition-all duration-300 ease-in-out overflow-hidden flex flex-col",
3062
+ side === "left" ? "border-r" : "border-l",
3063
+ collapsed ? "w-0 border-r-0 border-l-0 min-w-0" : "",
3064
+ !collapsed && className
3007
3065
  ),
3008
- children: [
3009
- /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col bg-sidebar text-foreground relative overflow-hidden", children: [
3010
- /* @__PURE__ */ jsx("div", { className: "absolute -top-24 -left-24 size-96 bg-primary/5 rounded-full blur-3xl" }),
3011
- /* @__PURE__ */ jsx("div", { className: "absolute -bottom-24 -right-24 size-96 bg-primary/5 rounded-full blur-3xl" }),
3012
- /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto overflow-x-hidden relative z-10 flex flex-col p-8 md:p-12 lg:p-20", children: /* @__PURE__ */ jsxs("div", { className: "max-w-xl mx-auto w-full", children: [
3013
- /* @__PURE__ */ jsx("h1", { className: "mb-6 text-4xl font-bold tracking-tight md:text-5xl lg:text-6xl text-foreground", children: title }),
3014
- /* @__PURE__ */ jsx("p", { className: "mb-12 text-lg text-muted-foreground md:text-xl leading-relaxed", children: description }),
3015
- imageUrl && /* @__PURE__ */ jsxs("div", { className: "mb-12 relative group", children: [
3016
- /* @__PURE__ */ jsx("div", { className: "absolute -inset-1 bg-gradient-to-r from-primary/20 to-primary/10 rounded-xl blur opacity-25 group-hover:opacity-50 transition duration-1000 group-hover:duration-200" }),
3017
- /* @__PURE__ */ jsx(
3018
- "img",
3019
- {
3020
- src: imageUrl,
3021
- alt: imageAlt,
3022
- className: "relative rounded-xl border border-border/50 shadow-2xl transition-transform duration-500 hover:scale-[1.02] w-full"
3023
- }
3024
- )
3025
- ] }),
3026
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-x-8 gap-y-10 sm:grid-cols-2", children: features.map((feature, i) => /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
3027
- /* @__PURE__ */ jsx("h3", { className: "font-bold text-lg text-foreground", children: feature.title }),
3028
- /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground leading-relaxed", children: feature.description })
3029
- ] }, i)) })
3030
- ] }) })
3031
- ] }),
3032
- /* @__PURE__ */ jsx("div", { className: "flex flex-1 flex-col items-center justify-center p-8 md:p-12 lg:p-20 bg-background transition-colors duration-300", children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-sm space-y-8", children: [
3033
- /* @__PURE__ */ jsxs("div", { className: "space-y-3 text-center md:text-left", children: [
3034
- /* @__PURE__ */ jsx("h2", { className: "text-3xl font-bold tracking-tight text-foreground", children: "Get Started" }),
3035
- /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-lg", children: "Sign in to your account to continue" })
3036
- ] }),
3037
- /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
3038
- /* @__PURE__ */ jsxs(
3039
- Button,
3040
- {
3041
- size: "lg",
3042
- variant: "outline",
3043
- 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",
3044
- onClick: handleLogin,
3045
- disabled: isLoading,
3046
- children: [
3047
- /* @__PURE__ */ jsx(IconBrandGoogle, { className: "size-6" }),
3048
- isLoading ? "Signing in..." : "Continue with Google"
3049
- ]
3050
- }
3051
- ),
3052
- /* @__PURE__ */ jsxs("div", { className: "relative py-4", children: [
3053
- /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center", children: /* @__PURE__ */ jsx("span", { className: "w-full border-t border-border" }) }),
3054
- /* @__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" }) })
3055
- ] })
3056
- ] }),
3057
- /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground leading-relaxed text-center md:text-left", children: [
3058
- "By continuing, you agree to our ",
3059
- /* @__PURE__ */ jsx("br", { className: "hidden md:block" }),
3060
- /* @__PURE__ */ jsx(
3061
- "a",
3062
- {
3063
- href: termsUrl,
3064
- target: "_blank",
3065
- rel: "noopener noreferrer",
3066
- className: "underline underline-offset-4 hover:text-primary transition-colors font-medium",
3067
- children: "Terms of Service"
3068
- }
3069
- ),
3070
- " ",
3071
- "and",
3072
- " ",
3073
- /* @__PURE__ */ jsx(
3074
- "a",
3075
- {
3076
- href: privacyUrl,
3077
- target: "_blank",
3078
- rel: "noopener noreferrer",
3079
- className: "underline underline-offset-4 hover:text-primary transition-colors font-medium",
3080
- children: "Privacy Policy"
3081
- }
3082
- ),
3083
- "."
3084
- ] })
3085
- ] }) })
3086
- ]
3066
+ children: /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden min-h-0", children })
3087
3067
  }
3088
3068
  );
3089
3069
  }
3090
- function ChatFull({
3070
+ function FullChat({
3091
3071
  title = "Chat",
3092
3072
  placeholder,
3093
3073
  starterPrompts,
3094
3074
  options,
3095
3075
  className,
3096
3076
  headerProps,
3097
- leftSidebar,
3098
- rightSidebar,
3099
- leftSidebarClassName,
3100
- rightSidebarClassName,
3101
3077
  autoFocus = false,
3102
- defaultSelectedIds,
3103
- showWelcomeScreen = false,
3104
- welcomeScreenProps
3078
+ defaultSelectedIds
3105
3079
  }) {
3106
- const { isMobile, isTablet } = useScreenSize();
3107
- const { isAuthenticated, isLoading } = useAuth();
3108
- const isSmallScreen = isMobile || isTablet;
3109
- const [internalLeftCollapsed, setInternalLeftCollapsed] = useState(() => {
3110
- if (typeof window !== "undefined") {
3111
- return window.innerWidth < 1024;
3112
- }
3113
- return false;
3114
- });
3115
- const [internalRightCollapsed, setInternalRightCollapsed] = useState(() => {
3116
- if (typeof window !== "undefined") {
3117
- return window.innerWidth < 1024;
3118
- }
3119
- return false;
3120
- });
3121
- useEffect(() => {
3122
- if (isSmallScreen) {
3123
- setInternalLeftCollapsed(true);
3124
- setInternalRightCollapsed(true);
3125
- }
3126
- }, [isSmallScreen]);
3127
- const leftCollapsed = internalLeftCollapsed;
3128
- const rightCollapsed = internalRightCollapsed;
3129
- const handleLeftToggle = useCallback((collapsed) => {
3130
- setInternalLeftCollapsed(collapsed);
3131
- }, []);
3132
- const handleRightToggle = useCallback((collapsed) => {
3133
- setInternalRightCollapsed(collapsed);
3134
- }, []);
3135
- const contextValue = useMemo(
3136
- () => ({
3137
- leftCollapsed,
3138
- rightCollapsed,
3139
- setLeftCollapsed: handleLeftToggle,
3140
- setRightCollapsed: handleRightToggle,
3141
- leftCollapsible: true,
3142
- rightCollapsible: true
3143
- }),
3144
- [leftCollapsed, rightCollapsed, handleLeftToggle, handleRightToggle]
3145
- );
3146
- if (showWelcomeScreen && !isAuthenticated && !isLoading) {
3147
- return /* @__PURE__ */ jsx(WelcomeScreen, { ...welcomeScreenProps });
3148
- }
3149
- return /* @__PURE__ */ jsx(ChatSidebarContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs(
3150
- "div",
3151
- {
3152
- className: cn("flex flex-col h-full w-full bg-background", className),
3153
- children: [
3154
- title && /* @__PURE__ */ jsx(ChatHeader, { title, ...headerProps }),
3155
- /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-hidden flex relative", children: [
3156
- leftSidebar && /* @__PURE__ */ jsx(
3157
- "div",
3158
- {
3159
- className: cn(
3160
- "flex-shrink-0 border-r border-border bg-background transition-all duration-300 ease-in-out overflow-hidden flex flex-col",
3161
- leftCollapsed ? "w-0 border-r-0 min-w-0" : "",
3162
- !leftCollapsed && leftSidebarClassName
3163
- ),
3164
- children: /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden min-h-0", children: leftSidebar })
3165
- }
3166
- ),
3167
- /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden min-w-0", children: /* @__PURE__ */ jsx(
3168
- Thread,
3169
- {
3170
- placeholder,
3171
- starterPrompts,
3172
- options,
3173
- autoFocus,
3174
- defaultSelectedIds
3175
- }
3176
- ) }),
3177
- rightSidebar && /* @__PURE__ */ jsx(
3178
- "div",
3179
- {
3180
- className: cn(
3181
- "flex-shrink-0 border-l border-border bg-background transition-all duration-300 ease-in-out overflow-hidden flex flex-col",
3182
- rightCollapsed ? "w-0 border-l-0 min-w-0" : "",
3183
- !rightCollapsed && rightSidebarClassName
3184
- ),
3185
- children: /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden min-h-0", children: rightSidebar })
3186
- }
3187
- )
3188
- ] })
3189
- ]
3190
- }
3191
- ) });
3080
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col h-full w-full bg-background", className), children: [
3081
+ title && /* @__PURE__ */ jsx(ChatHeader, { title, ...headerProps }),
3082
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden flex relative", children: /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden min-w-0", children: /* @__PURE__ */ jsx(
3083
+ Thread,
3084
+ {
3085
+ placeholder,
3086
+ starterPrompts,
3087
+ options,
3088
+ autoFocus,
3089
+ defaultSelectedIds
3090
+ }
3091
+ ) }) })
3092
+ ] });
3192
3093
  }
3193
3094
  function SidebarToggle({ side, className }) {
3194
3095
  const {
@@ -3198,13 +3099,14 @@ function SidebarToggle({ side, className }) {
3198
3099
  setRightCollapsed,
3199
3100
  leftCollapsible,
3200
3101
  rightCollapsible
3201
- } = useChatSidebar();
3102
+ } = useSidebar();
3202
3103
  if (side === "left") {
3203
3104
  if (!leftCollapsible) return null;
3204
3105
  return /* @__PURE__ */ jsx(
3205
3106
  Button,
3206
3107
  {
3207
3108
  variant: "ghost",
3109
+ size: "icon",
3208
3110
  onClick: () => setLeftCollapsed(!leftCollapsed),
3209
3111
  "aria-label": leftCollapsed ? "Expand left sidebar" : "Collapse left sidebar",
3210
3112
  className: cn("", className),
@@ -3218,6 +3120,7 @@ function SidebarToggle({ side, className }) {
3218
3120
  Button,
3219
3121
  {
3220
3122
  variant: "ghost",
3123
+ size: "icon",
3221
3124
  onClick: () => setRightCollapsed(!rightCollapsed),
3222
3125
  "aria-label": rightCollapsed ? "Expand right sidebar" : "Collapse right sidebar",
3223
3126
  className: cn("", className),
@@ -3227,11 +3130,11 @@ function SidebarToggle({ side, className }) {
3227
3130
  }
3228
3131
  return null;
3229
3132
  }
3230
- var PopoverContext = React12.createContext(
3133
+ var PopoverContext = React11.createContext(
3231
3134
  void 0
3232
3135
  );
3233
3136
  function usePopoverContext() {
3234
- const context = React12.useContext(PopoverContext);
3137
+ const context = React11.useContext(PopoverContext);
3235
3138
  if (!context) {
3236
3139
  throw new Error("Popover components must be used within a Popover");
3237
3140
  }
@@ -3243,10 +3146,10 @@ function Popover({
3243
3146
  open: controlledOpen,
3244
3147
  onOpenChange
3245
3148
  }) {
3246
- const [internalOpen, setInternalOpen] = React12.useState(defaultOpen);
3247
- const triggerRef = React12.useRef(null);
3149
+ const [internalOpen, setInternalOpen] = React11.useState(defaultOpen);
3150
+ const triggerRef = React11.useRef(null);
3248
3151
  const open = controlledOpen ?? internalOpen;
3249
- const setOpen = React12.useCallback(
3152
+ const setOpen = React11.useCallback(
3250
3153
  (newOpen) => {
3251
3154
  if (controlledOpen === void 0) {
3252
3155
  setInternalOpen(newOpen);
@@ -3255,7 +3158,7 @@ function Popover({
3255
3158
  },
3256
3159
  [controlledOpen, onOpenChange]
3257
3160
  );
3258
- const value = React12.useMemo(
3161
+ const value = React11.useMemo(
3259
3162
  () => ({
3260
3163
  open,
3261
3164
  setOpen,
@@ -3265,15 +3168,15 @@ function Popover({
3265
3168
  );
3266
3169
  return /* @__PURE__ */ jsx(PopoverContext.Provider, { value, children });
3267
3170
  }
3268
- var PopoverTrigger = React12.forwardRef(
3171
+ var PopoverTrigger = React11.forwardRef(
3269
3172
  ({ asChild, className, children, ...props }, ref) => {
3270
3173
  const { setOpen, triggerRef } = usePopoverContext();
3271
3174
  const handleClick = (e) => {
3272
3175
  setOpen(true);
3273
3176
  props.onClick?.(e);
3274
3177
  };
3275
- if (asChild && React12.isValidElement(children)) {
3276
- return React12.cloneElement(children, {
3178
+ if (asChild && React11.isValidElement(children)) {
3179
+ return React11.cloneElement(children, {
3277
3180
  ref: (node) => {
3278
3181
  triggerRef.current = node;
3279
3182
  if (typeof children.ref === "function") {
@@ -3305,7 +3208,7 @@ var PopoverTrigger = React12.forwardRef(
3305
3208
  }
3306
3209
  );
3307
3210
  PopoverTrigger.displayName = "PopoverTrigger";
3308
- var PopoverContent = React12.forwardRef(
3211
+ var PopoverContent = React11.forwardRef(
3309
3212
  ({
3310
3213
  className,
3311
3214
  side = "bottom",
@@ -3316,9 +3219,9 @@ var PopoverContent = React12.forwardRef(
3316
3219
  ...props
3317
3220
  }, ref) => {
3318
3221
  const { open, setOpen, triggerRef } = usePopoverContext();
3319
- const [position, setPosition] = React12.useState({ top: 0, left: 0 });
3320
- const contentRef = React12.useRef(null);
3321
- React12.useEffect(() => {
3222
+ const [position, setPosition] = React11.useState({ top: 0, left: 0 });
3223
+ const contentRef = React11.useRef(null);
3224
+ React11.useEffect(() => {
3322
3225
  if (!open || !triggerRef.current) return;
3323
3226
  const updatePosition = () => {
3324
3227
  if (!triggerRef.current || !contentRef.current) return;
@@ -3379,7 +3282,7 @@ var PopoverContent = React12.forwardRef(
3379
3282
  window.removeEventListener("scroll", updatePosition, true);
3380
3283
  };
3381
3284
  }, [open, side, align, sideOffset, alignOffset, triggerRef]);
3382
- React12.useEffect(() => {
3285
+ React11.useEffect(() => {
3383
3286
  if (!open) return;
3384
3287
  const handleClickOutside = (event) => {
3385
3288
  if (contentRef.current && !contentRef.current.contains(event.target) && triggerRef.current && !triggerRef.current.contains(event.target)) {
@@ -3435,7 +3338,7 @@ var ThreadPopover = ({
3435
3338
  emptyState,
3436
3339
  onThreadSelect
3437
3340
  }) => {
3438
- const [isOpen, setIsOpen] = React12.useState(false);
3341
+ const [isOpen, setIsOpen] = React11.useState(false);
3439
3342
  useHotkeys(
3440
3343
  "h",
3441
3344
  (e) => {
@@ -3485,12 +3388,12 @@ var ThreadPopover = ({
3485
3388
  var CreateThreadButton = ({
3486
3389
  className,
3487
3390
  variant = "ghost",
3488
- size = "icon",
3391
+ size = "default",
3489
3392
  children,
3490
3393
  onThreadCreated
3491
3394
  }) => {
3492
3395
  const { createThread } = useThreads();
3493
- const [isCreating, setIsCreating] = React12.useState(false);
3396
+ const [isCreating, setIsCreating] = React11.useState(false);
3494
3397
  const handleCreateThread = async () => {
3495
3398
  if (isCreating) return;
3496
3399
  try {
@@ -3516,7 +3419,7 @@ var CreateThreadButton = ({
3516
3419
  // Don't trigger in contenteditable elements
3517
3420
  }
3518
3421
  );
3519
- return /* @__PURE__ */ jsx(
3422
+ return /* @__PURE__ */ jsxs(
3520
3423
  Button,
3521
3424
  {
3522
3425
  variant,
@@ -3524,7 +3427,10 @@ var CreateThreadButton = ({
3524
3427
  onClick: handleCreateThread,
3525
3428
  disabled: isCreating,
3526
3429
  className: cn(className),
3527
- children: /* @__PURE__ */ jsx(IconPlus, { className: "size-4" })
3430
+ children: [
3431
+ /* @__PURE__ */ jsx(IconPlus, { className: "size-4" }),
3432
+ "New chat"
3433
+ ]
3528
3434
  }
3529
3435
  );
3530
3436
  };
@@ -3616,10 +3522,10 @@ var AccountDialog = ({
3616
3522
  size
3617
3523
  }) => {
3618
3524
  const { isLoading, isAuthenticated, user, login, logout } = useAuth();
3619
- const [open, setOpen] = React12.useState(false);
3620
- const [accountInfoOpen, setAccountInfoOpen] = React12.useState(false);
3621
- const [error, setError] = React12.useState(null);
3622
- const initials = React12.useMemo(() => {
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(() => {
3623
3529
  const name = user?.displayName || user?.name;
3624
3530
  if (!name) return "";
3625
3531
  return name.split(" ").map((n) => n[0]).join("").toUpperCase().slice(0, 2);
@@ -3718,17 +3624,14 @@ var AccountDialog = ({
3718
3624
  ] });
3719
3625
  }
3720
3626
  return /* @__PURE__ */ jsxs(Fragment, { children: [
3721
- /* @__PURE__ */ jsxs(
3627
+ /* @__PURE__ */ jsx(
3722
3628
  Button,
3723
3629
  {
3724
3630
  variant,
3725
3631
  size,
3726
3632
  onClick: () => setOpen(true),
3727
3633
  className,
3728
- children: [
3729
- /* @__PURE__ */ jsx(IconBrandGoogle, { className: "mr-2 size-4" }),
3730
- "Sign in with Google"
3731
- ]
3634
+ children: "Sign in"
3732
3635
  }
3733
3636
  ),
3734
3637
  /* @__PURE__ */ jsx(AlertDialog, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxs(AlertDialogContent, { className: "sm:max-w-md", children: [
@@ -3792,6 +3695,6 @@ function ThemeToggle() {
3792
3695
  );
3793
3696
  }
3794
3697
 
3795
- export { AccountDialog, AuthContext, AuthProvider, Badge2 as Badge, Box, Button2 as Button, Card2 as Card, Chart, ChatFull, ChatHeader, ChatPopup, ChatSidebar, ChatSidebarContext, Checkbox, Col, Composer, CreateThreadButton, Divider, Form, Heading, Image, Input2 as Input, Label2 as Label, List, ListItem, MelonyClientProvider, MelonyContext, RadioGroup, Row, Select2 as Select, SidebarToggle, Spacer, Text, Textarea2 as Textarea, ThemeProvider, ThemeToggle, Thread, ThreadContext, ThreadList, ThreadPopover, ThreadProvider, UIRenderer, WelcomeScreen, groupEventsToMessages, useAuth, useChatSidebar, useMelony, useScreenSize, useTheme, useThreads };
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, MelonyClientProvider, MelonyContext, 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 };
3796
3699
  //# sourceMappingURL=index.js.map
3797
3700
  //# sourceMappingURL=index.js.map