@mesob/ui 0.1.1 → 0.2.0

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.
Files changed (47) hide show
  1. package/dist/components/app-breadcrumbs.d.ts +34 -0
  2. package/dist/components/app-breadcrumbs.js +177 -0
  3. package/dist/components/app-breadcrumbs.js.map +1 -0
  4. package/dist/components/app-header-actions.d.ts +39 -0
  5. package/dist/components/app-header-actions.js +629 -0
  6. package/dist/components/app-header-actions.js.map +1 -0
  7. package/dist/components/app-sidebar.d.ts +24 -0
  8. package/dist/components/app-sidebar.js +669 -0
  9. package/dist/components/app-sidebar.js.map +1 -0
  10. package/dist/components/data-table/index.d.ts +9 -2
  11. package/dist/components/data-table/index.js +276 -101
  12. package/dist/components/data-table/index.js.map +1 -1
  13. package/dist/components/entity/index.d.ts +85 -9
  14. package/dist/components/entity/index.js +424 -304
  15. package/dist/components/entity/index.js.map +1 -1
  16. package/dist/components/input-group.d.ts +1 -1
  17. package/dist/components/link.d.ts +12 -0
  18. package/dist/components/link.js +51 -0
  19. package/dist/components/link.js.map +1 -0
  20. package/dist/components/mesob-context.d.ts +34 -0
  21. package/dist/components/mesob-context.js +53 -0
  22. package/dist/components/mesob-context.js.map +1 -0
  23. package/dist/components/page/index.d.ts +46 -0
  24. package/dist/components/page/index.js +197 -0
  25. package/dist/components/page/index.js.map +1 -0
  26. package/dist/components/powered-by.d.ts +4 -1
  27. package/dist/components/powered-by.js +28 -12
  28. package/dist/components/powered-by.js.map +1 -1
  29. package/dist/components/shell.d.ts +13 -0
  30. package/dist/components/shell.js +545 -0
  31. package/dist/components/shell.js.map +1 -0
  32. package/dist/components/sidebar.d.ts +4 -0
  33. package/dist/components/sidebar.js +37 -8
  34. package/dist/components/sidebar.js.map +1 -1
  35. package/dist/components/table.js +1 -1
  36. package/dist/components/table.js.map +1 -1
  37. package/dist/components/tooltip.d.ts +1 -1
  38. package/dist/components/tooltip.js +2 -1
  39. package/dist/components/tooltip.js.map +1 -1
  40. package/dist/hooks/use-router.d.ts +7 -0
  41. package/dist/hooks/use-router.js +36 -0
  42. package/dist/hooks/use-router.js.map +1 -0
  43. package/dist/hooks/use-translation.d.ts +5 -0
  44. package/dist/hooks/use-translation.js +41 -0
  45. package/dist/hooks/use-translation.js.map +1 -0
  46. package/package.json +7 -1
  47. package/src/styles/globals.css +4 -0
@@ -355,7 +355,7 @@ function EntityBulkActions({
355
355
  }
356
356
 
357
357
  // src/components/entity/entity-detail-header.tsx
358
- import { IconChevronDown as IconChevronDown2 } from "@tabler/icons-react";
358
+ import { IconChevronDown as IconChevronDown3, IconMenu2 } from "@tabler/icons-react";
359
359
  import { motion } from "motion/react";
360
360
  import { useLayoutEffect, useMemo, useRef, useState as useState2 } from "react";
361
361
 
@@ -375,8 +375,137 @@ function Card({ className, ...props }) {
375
375
  );
376
376
  }
377
377
 
378
- // src/components/entity/entity-detail-header.tsx
378
+ // src/components/select.tsx
379
+ import * as SelectPrimitive from "@radix-ui/react-select";
380
+ import { IconCheck as IconCheck2, IconChevronDown as IconChevronDown2, IconChevronUp } from "@tabler/icons-react";
379
381
  import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
382
+ function Select({
383
+ ...props
384
+ }) {
385
+ return /* @__PURE__ */ jsx6(SelectPrimitive.Root, { "data-slot": "select", ...props });
386
+ }
387
+ function SelectValue({
388
+ ...props
389
+ }) {
390
+ return /* @__PURE__ */ jsx6(SelectPrimitive.Value, { "data-slot": "select-value", ...props });
391
+ }
392
+ function SelectTrigger({
393
+ className,
394
+ size = "default",
395
+ children,
396
+ ...props
397
+ }) {
398
+ return /* @__PURE__ */ jsxs4(
399
+ SelectPrimitive.Trigger,
400
+ {
401
+ "data-slot": "select-trigger",
402
+ "data-size": size,
403
+ className: cn(
404
+ "border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground 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:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
405
+ className
406
+ ),
407
+ ...props,
408
+ children: [
409
+ children,
410
+ /* @__PURE__ */ jsx6(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx6(IconChevronDown2, { className: "size-4 opacity-50" }) })
411
+ ]
412
+ }
413
+ );
414
+ }
415
+ function SelectContent({
416
+ className,
417
+ children,
418
+ position = "popper",
419
+ align = "center",
420
+ ...props
421
+ }) {
422
+ return /* @__PURE__ */ jsx6(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs4(
423
+ SelectPrimitive.Content,
424
+ {
425
+ "data-slot": "select-content",
426
+ className: cn(
427
+ "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=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 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
428
+ position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
429
+ className
430
+ ),
431
+ position,
432
+ align,
433
+ ...props,
434
+ children: [
435
+ /* @__PURE__ */ jsx6(SelectScrollUpButton, {}),
436
+ /* @__PURE__ */ jsx6(
437
+ SelectPrimitive.Viewport,
438
+ {
439
+ className: cn(
440
+ "p-1",
441
+ position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"
442
+ ),
443
+ children
444
+ }
445
+ ),
446
+ /* @__PURE__ */ jsx6(SelectScrollDownButton, {})
447
+ ]
448
+ }
449
+ ) });
450
+ }
451
+ function SelectItem({
452
+ className,
453
+ children,
454
+ ...props
455
+ }) {
456
+ return /* @__PURE__ */ jsxs4(
457
+ SelectPrimitive.Item,
458
+ {
459
+ "data-slot": "select-item",
460
+ className: cn(
461
+ "focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
462
+ className
463
+ ),
464
+ ...props,
465
+ children: [
466
+ /* @__PURE__ */ jsx6("span", { className: "absolute right-2 flex size-3.5 items-center justify-center", children: /* @__PURE__ */ jsx6(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx6(IconCheck2, { className: "size-4" }) }) }),
467
+ /* @__PURE__ */ jsx6(SelectPrimitive.ItemText, { children })
468
+ ]
469
+ }
470
+ );
471
+ }
472
+ function SelectScrollUpButton({
473
+ className,
474
+ ...props
475
+ }) {
476
+ return /* @__PURE__ */ jsx6(
477
+ SelectPrimitive.ScrollUpButton,
478
+ {
479
+ "data-slot": "select-scroll-up-button",
480
+ className: cn(
481
+ "flex cursor-default items-center justify-center py-1",
482
+ className
483
+ ),
484
+ ...props,
485
+ children: /* @__PURE__ */ jsx6(IconChevronUp, { className: "size-4" })
486
+ }
487
+ );
488
+ }
489
+ function SelectScrollDownButton({
490
+ className,
491
+ ...props
492
+ }) {
493
+ return /* @__PURE__ */ jsx6(
494
+ SelectPrimitive.ScrollDownButton,
495
+ {
496
+ "data-slot": "select-scroll-down-button",
497
+ className: cn(
498
+ "flex cursor-default items-center justify-center py-1",
499
+ className
500
+ ),
501
+ ...props,
502
+ children: /* @__PURE__ */ jsx6(IconChevronDown2, { className: "size-4" })
503
+ }
504
+ );
505
+ }
506
+
507
+ // src/components/entity/entity-detail-header.tsx
508
+ import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
380
509
  function EntityDetailHeader({
381
510
  title,
382
511
  icon,
@@ -408,6 +537,11 @@ function EntityDetailHeader({
408
537
  };
409
538
  useLayoutEffect(() => {
410
539
  const updateTabs = () => {
540
+ if (typeof window !== "undefined" && !window.matchMedia("(min-width: 640px)").matches) {
541
+ setVisibleTabs(tabs);
542
+ setOverflowTabs([]);
543
+ return;
544
+ }
411
545
  if (!containerRef.current) {
412
546
  return;
413
547
  }
@@ -507,7 +641,7 @@ function EntityDetailHeader({
507
641
  }
508
642
  };
509
643
  if (tab.href && LinkComponent) {
510
- return /* @__PURE__ */ jsx6(
644
+ return /* @__PURE__ */ jsx7(
511
645
  LinkComponent,
512
646
  {
513
647
  href: tab.href,
@@ -518,7 +652,7 @@ function EntityDetailHeader({
518
652
  tab.value
519
653
  );
520
654
  }
521
- return /* @__PURE__ */ jsx6(
655
+ return /* @__PURE__ */ jsx7(
522
656
  "button",
523
657
  {
524
658
  type: "button",
@@ -537,9 +671,9 @@ function EntityDetailHeader({
537
671
  isActive && "bg-accent font-medium"
538
672
  );
539
673
  if (tab.href && LinkComponent) {
540
- return /* @__PURE__ */ jsx6(DropdownMenuItem, { asChild: true, className: itemClassName, children: /* @__PURE__ */ jsx6(LinkComponent, { href: tab.href, children: tab.name }) }, tab.value);
674
+ return /* @__PURE__ */ jsx7(DropdownMenuItem, { asChild: true, className: itemClassName, children: /* @__PURE__ */ jsx7(LinkComponent, { href: tab.href, children: tab.name }) }, tab.value);
541
675
  }
542
- return /* @__PURE__ */ jsx6(
676
+ return /* @__PURE__ */ jsx7(
543
677
  DropdownMenuItem,
544
678
  {
545
679
  onClick: () => handleTabChange(tab.value),
@@ -549,59 +683,75 @@ function EntityDetailHeader({
549
683
  tab.value
550
684
  );
551
685
  };
552
- return /* @__PURE__ */ jsxs4("div", { className: cn("flex flex-col", className), children: [
553
- /* @__PURE__ */ jsxs4(Card, { className: "overflow-hidden p-0 gap-0", children: [
554
- /* @__PURE__ */ jsxs4("div", { className: "flex items-center justify-between gap-2 p-4 pb-2 ", children: [
555
- /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2", children: [
686
+ return /* @__PURE__ */ jsxs5("div", { className: cn("flex flex-col", className), children: [
687
+ /* @__PURE__ */ jsxs5(Card, { className: "overflow-hidden p-0 gap-0", children: [
688
+ /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between gap-2 p-4 pb-2 ", children: [
689
+ /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2", children: [
556
690
  backButton,
557
691
  icon,
558
- /* @__PURE__ */ jsx6("span", { className: "text-lg font-semibold", children: title })
692
+ /* @__PURE__ */ jsx7("span", { className: "text-lg font-semibold", children: title })
559
693
  ] }),
560
- actions && /* @__PURE__ */ jsx6("div", { className: "flex items-center gap-2", children: actions })
694
+ actions && /* @__PURE__ */ jsx7("div", { className: "flex items-center gap-2", children: actions })
561
695
  ] }),
562
- /* @__PURE__ */ jsx6("div", { ref: containerRef, className: "w-full px-4 ", children: /* @__PURE__ */ jsxs4("div", { ref: tabsListRef, className: "relative flex items-center", children: [
563
- visibleTabs.map((tab) => {
564
- const originalIndex = tabs.findIndex(
565
- (t) => t.value === tab.value
566
- );
567
- return renderTab(tab, originalIndex);
568
- }),
569
- overflowTabs.length > 0 && /* @__PURE__ */ jsxs4(DropdownMenu, { children: [
570
- /* @__PURE__ */ jsxs4(
571
- DropdownMenuTrigger,
572
- {
573
- ref: dropdownTriggerRef,
574
- className: cn(
575
- "relative z-10 flex items-center gap-1 px-4 py-3 text-sm font-medium transition-all duration-200",
576
- "hover:bg-muted/60 rounded-t-md",
577
- overflowTabs.some((tab) => tab.value === activeTab) ? "text-primary" : "text-muted-foreground hover:text-foreground"
578
- ),
579
- children: [
580
- "More",
581
- /* @__PURE__ */ jsx6(IconChevronDown2, { className: "h-4 w-4" })
582
- ]
583
- }
584
- ),
585
- /* @__PURE__ */ jsx6(DropdownMenuContent, { align: "start", className: "min-w-40", children: overflowTabs.map(renderDropdownItem) })
586
- ] }),
587
- /* @__PURE__ */ jsx6(
588
- motion.div,
696
+ /* @__PURE__ */ jsxs5("div", { ref: containerRef, className: "w-full px-4", children: [
697
+ /* @__PURE__ */ jsx7("div", { className: "mb-3 w-full sm:hidden", children: /* @__PURE__ */ jsxs5(Select, { value: activeTab, onValueChange: handleTabChange, children: [
698
+ /* @__PURE__ */ jsxs5(SelectTrigger, { className: "h-9 w-full gap-2 [&>svg:first-child]:shrink-0", children: [
699
+ /* @__PURE__ */ jsx7(IconMenu2, { className: "size-4 text-muted-foreground" }),
700
+ /* @__PURE__ */ jsx7(SelectValue, {})
701
+ ] }),
702
+ /* @__PURE__ */ jsx7(SelectContent, { children: tabs.map((tab) => /* @__PURE__ */ jsx7(SelectItem, { value: tab.value, children: tab.name }, tab.value)) })
703
+ ] }) }),
704
+ /* @__PURE__ */ jsxs5(
705
+ "div",
589
706
  {
590
- className: "absolute bottom-0 left-0 z-20 h-0.5 bg-primary",
591
- animate: {
592
- left: underlineStyle.left,
593
- width: underlineStyle.width
594
- },
595
- transition: {
596
- type: "spring",
597
- stiffness: 400,
598
- damping: 40
599
- }
707
+ ref: tabsListRef,
708
+ className: "relative hidden items-center sm:flex",
709
+ children: [
710
+ visibleTabs.map((tab) => {
711
+ const originalIndex = tabs.findIndex(
712
+ (t) => t.value === tab.value
713
+ );
714
+ return renderTab(tab, originalIndex);
715
+ }),
716
+ overflowTabs.length > 0 && /* @__PURE__ */ jsxs5(DropdownMenu, { children: [
717
+ /* @__PURE__ */ jsxs5(
718
+ DropdownMenuTrigger,
719
+ {
720
+ ref: dropdownTriggerRef,
721
+ className: cn(
722
+ "relative z-10 flex items-center gap-1 px-4 py-3 text-sm font-medium transition-all duration-200",
723
+ "hover:bg-muted/60 rounded-t-md",
724
+ overflowTabs.some((tab) => tab.value === activeTab) ? "text-primary" : "text-muted-foreground hover:text-foreground"
725
+ ),
726
+ children: [
727
+ "More",
728
+ /* @__PURE__ */ jsx7(IconChevronDown3, { className: "h-4 w-4" })
729
+ ]
730
+ }
731
+ ),
732
+ /* @__PURE__ */ jsx7(DropdownMenuContent, { align: "start", className: "min-w-40", children: overflowTabs.map(renderDropdownItem) })
733
+ ] }),
734
+ /* @__PURE__ */ jsx7(
735
+ motion.div,
736
+ {
737
+ className: "absolute bottom-0 left-0 z-20 h-0.5 bg-primary",
738
+ animate: {
739
+ left: underlineStyle.left,
740
+ width: underlineStyle.width
741
+ },
742
+ transition: {
743
+ type: "spring",
744
+ stiffness: 400,
745
+ damping: 40
746
+ }
747
+ }
748
+ )
749
+ ]
600
750
  }
601
751
  )
602
- ] }) })
752
+ ] })
603
753
  ] }),
604
- activeTabData?.content && /* @__PURE__ */ jsx6("div", { className: "flex-1", children: activeTabData.content })
754
+ activeTabData?.content && /* @__PURE__ */ jsx7("div", { className: "flex-1", children: activeTabData.content })
605
755
  ] });
606
756
  }
607
757
 
@@ -611,20 +761,20 @@ import { useState as useState3 } from "react";
611
761
  // src/components/sheet.tsx
612
762
  import * as SheetPrimitive from "@radix-ui/react-dialog";
613
763
  import { IconX } from "@tabler/icons-react";
614
- import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
764
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
615
765
  function Sheet({ ...props }) {
616
- return /* @__PURE__ */ jsx7(SheetPrimitive.Root, { "data-slot": "sheet", ...props });
766
+ return /* @__PURE__ */ jsx8(SheetPrimitive.Root, { "data-slot": "sheet", ...props });
617
767
  }
618
768
  function SheetPortal({
619
769
  ...props
620
770
  }) {
621
- return /* @__PURE__ */ jsx7(SheetPrimitive.Portal, { "data-slot": "sheet-portal", ...props });
771
+ return /* @__PURE__ */ jsx8(SheetPrimitive.Portal, { "data-slot": "sheet-portal", ...props });
622
772
  }
623
773
  function SheetOverlay({
624
774
  className,
625
775
  ...props
626
776
  }) {
627
- return /* @__PURE__ */ jsx7(
777
+ return /* @__PURE__ */ jsx8(
628
778
  SheetPrimitive.Overlay,
629
779
  {
630
780
  "data-slot": "sheet-overlay",
@@ -642,9 +792,9 @@ function SheetContent({
642
792
  side = "right",
643
793
  ...props
644
794
  }) {
645
- return /* @__PURE__ */ jsxs5(SheetPortal, { children: [
646
- /* @__PURE__ */ jsx7(SheetOverlay, {}),
647
- /* @__PURE__ */ jsxs5(
795
+ return /* @__PURE__ */ jsxs6(SheetPortal, { children: [
796
+ /* @__PURE__ */ jsx8(SheetOverlay, {}),
797
+ /* @__PURE__ */ jsxs6(
648
798
  SheetPrimitive.Content,
649
799
  {
650
800
  "data-slot": "sheet-content",
@@ -659,9 +809,9 @@ function SheetContent({
659
809
  ...props,
660
810
  children: [
661
811
  children,
662
- /* @__PURE__ */ jsxs5(SheetPrimitive.Close, { className: "ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none", children: [
663
- /* @__PURE__ */ jsx7(IconX, { className: "size-4" }),
664
- /* @__PURE__ */ jsx7("span", { className: "sr-only", children: "Close" })
812
+ /* @__PURE__ */ jsxs6(SheetPrimitive.Close, { className: "ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none", children: [
813
+ /* @__PURE__ */ jsx8(IconX, { className: "size-4" }),
814
+ /* @__PURE__ */ jsx8("span", { className: "sr-only", children: "Close" })
665
815
  ] })
666
816
  ]
667
817
  }
@@ -669,7 +819,7 @@ function SheetContent({
669
819
  ] });
670
820
  }
671
821
  function SheetHeader({ className, ...props }) {
672
- return /* @__PURE__ */ jsx7(
822
+ return /* @__PURE__ */ jsx8(
673
823
  "div",
674
824
  {
675
825
  "data-slot": "sheet-header",
@@ -682,7 +832,7 @@ function SheetTitle({
682
832
  className,
683
833
  ...props
684
834
  }) {
685
- return /* @__PURE__ */ jsx7(
835
+ return /* @__PURE__ */ jsx8(
686
836
  SheetPrimitive.Title,
687
837
  {
688
838
  "data-slot": "sheet-title",
@@ -693,7 +843,7 @@ function SheetTitle({
693
843
  }
694
844
 
695
845
  // src/components/entity/entity-drawer.tsx
696
- import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
846
+ import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
697
847
  var sizeClasses = {
698
848
  sm: "sm:max-w-sm",
699
849
  md: "sm:max-w-md",
@@ -721,8 +871,8 @@ function EntityDrawer({
721
871
  setShowConfirm(false);
722
872
  onClose();
723
873
  };
724
- return /* @__PURE__ */ jsxs6(Fragment2, { children: [
725
- /* @__PURE__ */ jsx8(Sheet, { open, onOpenChange: (isOpen) => !isOpen && handleClose(), children: /* @__PURE__ */ jsxs6(
874
+ return /* @__PURE__ */ jsxs7(Fragment2, { children: [
875
+ /* @__PURE__ */ jsx9(Sheet, { open, onOpenChange: (isOpen) => !isOpen && handleClose(), children: /* @__PURE__ */ jsxs7(
726
876
  SheetContent,
727
877
  {
728
878
  className: `${sizeClasses[size]} flex flex-col p-0`,
@@ -739,20 +889,20 @@ function EntityDrawer({
739
889
  }
740
890
  },
741
891
  children: [
742
- /* @__PURE__ */ jsx8(SheetHeader, { className: "border-b px-6 py-4", children: /* @__PURE__ */ jsx8(SheetTitle, { children: title }) }),
743
- /* @__PURE__ */ jsx8("div", { className: "flex-1 overflow-y-auto px-6 py-4", children: form }),
744
- /* @__PURE__ */ jsx8("div", { className: "border-t px-6 py-4", children: actions })
892
+ /* @__PURE__ */ jsx9(SheetHeader, { className: "border-b px-6 py-4", children: /* @__PURE__ */ jsx9(SheetTitle, { children: title }) }),
893
+ /* @__PURE__ */ jsx9("div", { className: "flex-1 overflow-y-auto px-6 py-4", children: form }),
894
+ /* @__PURE__ */ jsx9("div", { className: "border-t px-6 py-4", children: actions })
745
895
  ]
746
896
  }
747
897
  ) }),
748
- /* @__PURE__ */ jsx8(AlertDialog, { open: showConfirm, onOpenChange: setShowConfirm, children: /* @__PURE__ */ jsxs6(AlertDialogContent, { children: [
749
- /* @__PURE__ */ jsxs6(AlertDialogHeader, { children: [
750
- /* @__PURE__ */ jsx8(AlertDialogTitle, { children: "Discard changes?" }),
751
- /* @__PURE__ */ jsx8(AlertDialogDescription, { children: "You have unsaved changes. Are you sure you want to discard them?" })
898
+ /* @__PURE__ */ jsx9(AlertDialog, { open: showConfirm, onOpenChange: setShowConfirm, children: /* @__PURE__ */ jsxs7(AlertDialogContent, { children: [
899
+ /* @__PURE__ */ jsxs7(AlertDialogHeader, { children: [
900
+ /* @__PURE__ */ jsx9(AlertDialogTitle, { children: "Discard changes?" }),
901
+ /* @__PURE__ */ jsx9(AlertDialogDescription, { children: "You have unsaved changes. Are you sure you want to discard them?" })
752
902
  ] }),
753
- /* @__PURE__ */ jsxs6(AlertDialogFooter, { children: [
754
- /* @__PURE__ */ jsx8(AlertDialogCancel, { children: "Cancel" }),
755
- /* @__PURE__ */ jsx8(
903
+ /* @__PURE__ */ jsxs7(AlertDialogFooter, { children: [
904
+ /* @__PURE__ */ jsx9(AlertDialogCancel, { children: "Cancel" }),
905
+ /* @__PURE__ */ jsx9(
756
906
  AlertDialogAction,
757
907
  {
758
908
  onClick: handleConfirmDiscard,
@@ -768,7 +918,7 @@ function EntityDrawer({
768
918
  // src/components/entity/entity-drawer-trigger.tsx
769
919
  import { IconChevronRight as IconChevronRight2, IconPencil, IconPlus } from "@tabler/icons-react";
770
920
  import { useState as useState4 } from "react";
771
- import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
921
+ import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
772
922
  function EntityDrawerTrigger({
773
923
  mode,
774
924
  entity,
@@ -798,8 +948,8 @@ function EntityDrawerTrigger({
798
948
  }
799
949
  };
800
950
  const buttonLabel = label || (mode === "new" ? `New ${entity}` : `Edit ${entity}`);
801
- return /* @__PURE__ */ jsxs7(Fragment3, { children: [
802
- mode === "edit" && variant === "icon" && /* @__PURE__ */ jsx9(
951
+ return /* @__PURE__ */ jsxs8(Fragment3, { children: [
952
+ mode === "edit" && variant === "icon" && /* @__PURE__ */ jsx10(
803
953
  Button,
804
954
  {
805
955
  variant: "ghost",
@@ -807,10 +957,10 @@ function EntityDrawerTrigger({
807
957
  className: `h-8 w-8 opacity-0 group-hover:opacity-100 transition-opacity ${className}`,
808
958
  onClick: handleOpen,
809
959
  disabled,
810
- children: /* @__PURE__ */ jsx9(IconChevronRight2, { className: "h-4 w-4" })
960
+ children: /* @__PURE__ */ jsx10(IconChevronRight2, { className: "h-4 w-4" })
811
961
  }
812
962
  ),
813
- mode === "edit" && variant !== "icon" && /* @__PURE__ */ jsxs7(
963
+ mode === "edit" && variant !== "icon" && /* @__PURE__ */ jsxs8(
814
964
  Button,
815
965
  {
816
966
  variant: variant === "outline" ? "outline" : "default",
@@ -819,22 +969,25 @@ function EntityDrawerTrigger({
819
969
  disabled,
820
970
  className,
821
971
  children: [
822
- /* @__PURE__ */ jsx9(IconPencil, { className: "mr-2 h-4 w-4" }),
972
+ /* @__PURE__ */ jsx10(IconPencil, { className: "mr-2 h-4 w-4" }),
823
973
  buttonLabel
824
974
  ]
825
975
  }
826
976
  ),
827
- mode === "new" && /* @__PURE__ */ jsxs7(
977
+ mode === "new" && /* @__PURE__ */ jsxs8(
828
978
  Button,
829
979
  {
830
980
  variant: variant === "outline" ? "outline" : "default",
831
981
  size: "sm",
832
982
  onClick: handleOpen,
833
983
  disabled,
834
- className,
984
+ className: cn(
985
+ "max-sm:h-8 max-sm:w-8 max-sm:shrink-0 max-sm:justify-center max-sm:p-0",
986
+ className
987
+ ),
835
988
  children: [
836
- /* @__PURE__ */ jsx9(IconPlus, { className: "mr-2 h-4 w-4" }),
837
- buttonLabel
989
+ /* @__PURE__ */ jsx10(IconPlus, { className: "h-4 w-4 sm:mr-2" }),
990
+ /* @__PURE__ */ jsx10("span", { className: "hidden sm:inline", children: buttonLabel })
838
991
  ]
839
992
  }
840
993
  ),
@@ -847,9 +1000,9 @@ import { IconPackage } from "@tabler/icons-react";
847
1000
 
848
1001
  // src/components/empty.tsx
849
1002
  import { cva as cva2 } from "class-variance-authority";
850
- import { jsx as jsx10 } from "react/jsx-runtime";
1003
+ import { jsx as jsx11 } from "react/jsx-runtime";
851
1004
  function Empty({ className, ...props }) {
852
- return /* @__PURE__ */ jsx10(
1005
+ return /* @__PURE__ */ jsx11(
853
1006
  "div",
854
1007
  {
855
1008
  "data-slot": "empty",
@@ -862,7 +1015,7 @@ function Empty({ className, ...props }) {
862
1015
  );
863
1016
  }
864
1017
  function EmptyHeader({ className, ...props }) {
865
- return /* @__PURE__ */ jsx10(
1018
+ return /* @__PURE__ */ jsx11(
866
1019
  "div",
867
1020
  {
868
1021
  "data-slot": "empty-header",
@@ -893,7 +1046,7 @@ function EmptyMedia({
893
1046
  variant = "default",
894
1047
  ...props
895
1048
  }) {
896
- return /* @__PURE__ */ jsx10(
1049
+ return /* @__PURE__ */ jsx11(
897
1050
  "div",
898
1051
  {
899
1052
  "data-slot": "empty-icon",
@@ -904,7 +1057,7 @@ function EmptyMedia({
904
1057
  );
905
1058
  }
906
1059
  function EmptyTitle({ className, ...props }) {
907
- return /* @__PURE__ */ jsx10(
1060
+ return /* @__PURE__ */ jsx11(
908
1061
  "div",
909
1062
  {
910
1063
  "data-slot": "empty-title",
@@ -914,7 +1067,7 @@ function EmptyTitle({ className, ...props }) {
914
1067
  );
915
1068
  }
916
1069
  function EmptyDescription({ className, ...props }) {
917
- return /* @__PURE__ */ jsx10(
1070
+ return /* @__PURE__ */ jsx11(
918
1071
  "div",
919
1072
  {
920
1073
  "data-slot": "empty-description",
@@ -927,7 +1080,7 @@ function EmptyDescription({ className, ...props }) {
927
1080
  );
928
1081
  }
929
1082
  function EmptyContent({ className, ...props }) {
930
- return /* @__PURE__ */ jsx10(
1083
+ return /* @__PURE__ */ jsx11(
931
1084
  "div",
932
1085
  {
933
1086
  "data-slot": "empty-content",
@@ -941,7 +1094,7 @@ function EmptyContent({ className, ...props }) {
941
1094
  }
942
1095
 
943
1096
  // src/components/entity/entity-empty-state.tsx
944
- import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
1097
+ import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
945
1098
  function EntityEmptyState({
946
1099
  icon: Icon2 = IconPackage,
947
1100
  title,
@@ -955,185 +1108,56 @@ function EntityEmptyState({
955
1108
  const defaultTitle = `No ${entityName}s yet`;
956
1109
  const defaultDescription = `Get started by creating your first ${entityName}.`;
957
1110
  const defaultActionLabel = `Create ${entityName}`;
958
- return /* @__PURE__ */ jsxs8(Empty, { className: cn("border py-12", className), children: [
959
- /* @__PURE__ */ jsxs8(EmptyHeader, { children: [
960
- /* @__PURE__ */ jsx11(EmptyMedia, { variant: "icon", children: /* @__PURE__ */ jsx11(Icon2, { className: "size-5" }) }),
961
- /* @__PURE__ */ jsx11(EmptyTitle, { children: title ?? defaultTitle }),
962
- /* @__PURE__ */ jsx11(EmptyDescription, { children: description ?? defaultDescription })
1111
+ return /* @__PURE__ */ jsxs9(Empty, { className: cn("border py-12", className), children: [
1112
+ /* @__PURE__ */ jsxs9(EmptyHeader, { children: [
1113
+ /* @__PURE__ */ jsx12(EmptyMedia, { variant: "icon", children: /* @__PURE__ */ jsx12(Icon2, { className: "size-5" }) }),
1114
+ /* @__PURE__ */ jsx12(EmptyTitle, { children: title ?? defaultTitle }),
1115
+ /* @__PURE__ */ jsx12(EmptyDescription, { children: description ?? defaultDescription })
963
1116
  ] }),
964
- /* @__PURE__ */ jsx11(EmptyContent, { children: children ?? (onAction && /* @__PURE__ */ jsx11(Button, { onClick: onAction, children: actionLabel ?? defaultActionLabel })) })
1117
+ /* @__PURE__ */ jsx12(EmptyContent, { children: children ?? (onAction && /* @__PURE__ */ jsx12(Button, { onClick: onAction, children: actionLabel ?? defaultActionLabel })) })
965
1118
  ] });
966
1119
  }
967
1120
 
968
1121
  // src/components/entity/entity-filter.tsx
969
1122
  import { IconFilter } from "@tabler/icons-react";
970
- import { parseAsString, useQueryState } from "nuqs";
971
-
972
- // src/components/select.tsx
973
- import * as SelectPrimitive from "@radix-ui/react-select";
974
- import { IconCheck as IconCheck2, IconChevronDown as IconChevronDown3, IconChevronUp } from "@tabler/icons-react";
975
- import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
976
- function Select({
977
- ...props
978
- }) {
979
- return /* @__PURE__ */ jsx12(SelectPrimitive.Root, { "data-slot": "select", ...props });
980
- }
981
- function SelectValue({
982
- ...props
983
- }) {
984
- return /* @__PURE__ */ jsx12(SelectPrimitive.Value, { "data-slot": "select-value", ...props });
985
- }
986
- function SelectTrigger({
987
- className,
988
- size = "default",
989
- children,
990
- ...props
991
- }) {
992
- return /* @__PURE__ */ jsxs9(
993
- SelectPrimitive.Trigger,
994
- {
995
- "data-slot": "select-trigger",
996
- "data-size": size,
997
- className: cn(
998
- "border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground 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:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
999
- className
1000
- ),
1001
- ...props,
1002
- children: [
1003
- children,
1004
- /* @__PURE__ */ jsx12(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx12(IconChevronDown3, { className: "size-4 opacity-50" }) })
1005
- ]
1006
- }
1007
- );
1008
- }
1009
- function SelectContent({
1010
- className,
1011
- children,
1012
- position = "popper",
1013
- align = "center",
1014
- ...props
1015
- }) {
1016
- return /* @__PURE__ */ jsx12(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs9(
1017
- SelectPrimitive.Content,
1018
- {
1019
- "data-slot": "select-content",
1020
- className: cn(
1021
- "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=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 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
1022
- position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
1023
- className
1024
- ),
1025
- position,
1026
- align,
1027
- ...props,
1028
- children: [
1029
- /* @__PURE__ */ jsx12(SelectScrollUpButton, {}),
1030
- /* @__PURE__ */ jsx12(
1031
- SelectPrimitive.Viewport,
1032
- {
1033
- className: cn(
1034
- "p-1",
1035
- position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"
1036
- ),
1037
- children
1038
- }
1039
- ),
1040
- /* @__PURE__ */ jsx12(SelectScrollDownButton, {})
1041
- ]
1042
- }
1043
- ) });
1044
- }
1045
- function SelectItem({
1046
- className,
1047
- children,
1048
- ...props
1049
- }) {
1050
- return /* @__PURE__ */ jsxs9(
1051
- SelectPrimitive.Item,
1052
- {
1053
- "data-slot": "select-item",
1054
- className: cn(
1055
- "focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
1056
- className
1057
- ),
1058
- ...props,
1059
- children: [
1060
- /* @__PURE__ */ jsx12("span", { className: "absolute right-2 flex size-3.5 items-center justify-center", children: /* @__PURE__ */ jsx12(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx12(IconCheck2, { className: "size-4" }) }) }),
1061
- /* @__PURE__ */ jsx12(SelectPrimitive.ItemText, { children })
1062
- ]
1063
- }
1064
- );
1065
- }
1066
- function SelectScrollUpButton({
1067
- className,
1068
- ...props
1069
- }) {
1070
- return /* @__PURE__ */ jsx12(
1071
- SelectPrimitive.ScrollUpButton,
1072
- {
1073
- "data-slot": "select-scroll-up-button",
1074
- className: cn(
1075
- "flex cursor-default items-center justify-center py-1",
1076
- className
1077
- ),
1078
- ...props,
1079
- children: /* @__PURE__ */ jsx12(IconChevronUp, { className: "size-4" })
1080
- }
1081
- );
1082
- }
1083
- function SelectScrollDownButton({
1084
- className,
1085
- ...props
1086
- }) {
1087
- return /* @__PURE__ */ jsx12(
1088
- SelectPrimitive.ScrollDownButton,
1089
- {
1090
- "data-slot": "select-scroll-down-button",
1091
- className: cn(
1092
- "flex cursor-default items-center justify-center py-1",
1093
- className
1094
- ),
1095
- ...props,
1096
- children: /* @__PURE__ */ jsx12(IconChevronDown3, { className: "size-4" })
1097
- }
1098
- );
1099
- }
1100
-
1101
- // src/components/entity/entity-filter.tsx
1123
+ import { parseAsInteger, parseAsString, useQueryState } from "nuqs";
1102
1124
  import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
1103
1125
  function EntityFilter({
1104
- paramKey = "filter",
1105
1126
  options,
1106
1127
  placeholder = "Filter",
1107
1128
  className,
1108
1129
  label
1109
1130
  }) {
1110
- const [filter, setFilter] = useQueryState(
1111
- paramKey,
1112
- parseAsString.withDefault("").withOptions({ shallow: false })
1113
- );
1114
- return /* @__PURE__ */ jsxs10("div", { className: cn("flex items-center gap-2", className), children: [
1115
- label && /* @__PURE__ */ jsx13("span", { className: "text-sm text-muted-foreground", children: label }),
1116
- /* @__PURE__ */ jsxs10(
1117
- Select,
1118
- {
1119
- value: filter || void 0,
1120
- onValueChange: (value) => setFilter(value || null),
1121
- children: [
1122
- /* @__PURE__ */ jsxs10(SelectTrigger, { className: "w-[150px] h-9", children: [
1123
- /* @__PURE__ */ jsx13(IconFilter, { className: "mr-2 h-4 w-4" }),
1124
- /* @__PURE__ */ jsx13(SelectValue, { placeholder })
1125
- ] }),
1126
- /* @__PURE__ */ jsx13(SelectContent, { children: options.map((option) => /* @__PURE__ */ jsx13(SelectItem, { value: option.value, children: option.label }, option.value)) })
1127
- ]
1128
- }
1129
- )
1131
+ const [value, setValue] = useQueryState("filter", parseAsString);
1132
+ const [, setPage] = useQueryState("page", parseAsInteger.withDefault(1));
1133
+ const handleChange = (newValue) => {
1134
+ if (newValue === "__all__") {
1135
+ setValue(null);
1136
+ } else {
1137
+ setValue(newValue || null);
1138
+ }
1139
+ setPage(1);
1140
+ };
1141
+ const validOptions = options.filter((opt) => opt.value !== "");
1142
+ const displayValue = value || (options.some((opt) => opt.value === "") ? "__all__" : void 0);
1143
+ return /* @__PURE__ */ jsxs10("div", { className: cn("flex w-full items-center gap-2", className), children: [
1144
+ label && /* @__PURE__ */ jsx13("span", { className: "shrink-0 text-sm text-muted-foreground", children: label }),
1145
+ /* @__PURE__ */ jsx13("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsxs10(Select, { value: displayValue, onValueChange: handleChange, children: [
1146
+ /* @__PURE__ */ jsxs10(SelectTrigger, { className: "h-9 w-full min-w-[150px]", children: [
1147
+ /* @__PURE__ */ jsx13(IconFilter, { className: "mr-2 h-4 w-4" }),
1148
+ /* @__PURE__ */ jsx13(SelectValue, { placeholder })
1149
+ ] }),
1150
+ /* @__PURE__ */ jsxs10(SelectContent, { children: [
1151
+ options.some((opt) => opt.value === "") && /* @__PURE__ */ jsx13(SelectItem, { value: "__all__", children: options.find((opt) => opt.value === "")?.label || "All" }, "__all__"),
1152
+ validOptions.map((option) => /* @__PURE__ */ jsx13(SelectItem, { value: option.value, children: option.label }, option.value))
1153
+ ] })
1154
+ ] }) })
1130
1155
  ] });
1131
1156
  }
1132
1157
 
1133
1158
  // src/components/entity/entity-form-actions.tsx
1134
1159
  import {
1135
- IconCheck as IconCheck3,
1136
- IconPlus as IconPlus2,
1160
+ IconDeviceFloppy,
1137
1161
  IconRotateClockwise,
1138
1162
  IconTrash as IconTrash2
1139
1163
  } from "@tabler/icons-react";
@@ -1181,9 +1205,8 @@ function EntityFormActions({
1181
1205
  disabled: disabled || isSubmitting,
1182
1206
  className: "cursor-pointer",
1183
1207
  children: [
1184
- isSubmitting && /* @__PURE__ */ jsx15(Spinner, { className: "mr-2 h-4 w-4" }),
1185
- !isSubmitting && mode === "new" && /* @__PURE__ */ jsx15(IconPlus2, { className: "mr-2 h-4 w-4" }),
1186
- !isSubmitting && mode === "edit" && /* @__PURE__ */ jsx15(IconCheck3, { className: "mr-2 h-4 w-4" }),
1208
+ isSubmitting && /* @__PURE__ */ jsx15(Spinner, { className: " h-4 w-4" }),
1209
+ !isSubmitting && /* @__PURE__ */ jsx15(IconDeviceFloppy, { className: " h-4 w-4" }),
1187
1210
  label
1188
1211
  ]
1189
1212
  }
@@ -1196,7 +1219,7 @@ function EntityFormActions({
1196
1219
  disabled,
1197
1220
  className: "cursor-pointer",
1198
1221
  children: [
1199
- /* @__PURE__ */ jsx15(IconRotateClockwise, { className: "mr-2 h-4 w-4" }),
1222
+ /* @__PURE__ */ jsx15(IconRotateClockwise, { className: " h-4 w-4" }),
1200
1223
  "Reset"
1201
1224
  ]
1202
1225
  }
@@ -1209,8 +1232,8 @@ function EntityFormActions({
1209
1232
  disabled: disabled || isDeleting,
1210
1233
  className: "cursor-pointer",
1211
1234
  children: [
1212
- isDeleting && /* @__PURE__ */ jsx15(Spinner, { className: "mr-2 h-4 w-4" }),
1213
- /* @__PURE__ */ jsx15(IconTrash2, { className: "mr-2 h-4 w-4" }),
1235
+ isDeleting && /* @__PURE__ */ jsx15(Spinner, { className: " h-4 w-4" }),
1236
+ /* @__PURE__ */ jsx15(IconTrash2, { className: " h-4 w-4" }),
1214
1237
  deleteLabel
1215
1238
  ]
1216
1239
  }
@@ -1251,6 +1274,8 @@ function EntityFormActions({
1251
1274
  }
1252
1275
 
1253
1276
  // src/components/entity/entity-header.tsx
1277
+ import { IconChevronDown as IconChevronDown4, IconChevronUp as IconChevronUp2 } from "@tabler/icons-react";
1278
+ import { useState as useState5 } from "react";
1254
1279
  import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
1255
1280
  function EntityHeader({
1256
1281
  title,
@@ -1261,22 +1286,48 @@ function EntityHeader({
1261
1286
  sort,
1262
1287
  view
1263
1288
  }) {
1289
+ const [toolbarOpen, setToolbarOpen] = useState5(false);
1290
+ const hasToolbar = [search, filter, sort, view].some(Boolean);
1264
1291
  return /* @__PURE__ */ jsx16(Card, { className: "p-4", children: /* @__PURE__ */ jsxs12("div", { className: "flex flex-col gap-4", children: [
1265
- /* @__PURE__ */ jsxs12("div", { className: "flex items-center justify-between gap-2", children: [
1292
+ /* @__PURE__ */ jsxs12("div", { className: "flex items-center justify-between", children: [
1266
1293
  /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-2", children: [
1267
1294
  icon,
1268
1295
  /* @__PURE__ */ jsx16("span", { className: "text-lg font-semibold", children: title })
1269
1296
  ] }),
1270
- actions
1271
- ] }),
1272
- /* @__PURE__ */ jsxs12("div", { className: "flex flex-col md:flex-row md:items-center justify-between gap-2", children: [
1273
- /* @__PURE__ */ jsx16("div", { className: "grow", children: search }),
1274
1297
  /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-2", children: [
1275
- filter,
1276
- sort,
1277
- view
1298
+ actions,
1299
+ hasToolbar && /* @__PURE__ */ jsx16(
1300
+ Button,
1301
+ {
1302
+ variant: "secondary",
1303
+ size: "icon-sm",
1304
+ className: "md:hidden",
1305
+ onClick: () => setToolbarOpen((o) => !o),
1306
+ "aria-expanded": toolbarOpen,
1307
+ "aria-label": toolbarOpen ? "Hide filters" : "Show filters",
1308
+ children: toolbarOpen ? /* @__PURE__ */ jsx16(IconChevronUp2, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx16(IconChevronDown4, { className: "h-4 w-4" })
1309
+ }
1310
+ )
1278
1311
  ] })
1279
- ] })
1312
+ ] }),
1313
+ hasToolbar && /* @__PURE__ */ jsxs12(
1314
+ "div",
1315
+ {
1316
+ className: cn(
1317
+ "flex flex-col gap-2 md:flex-row md:items-center md:justify-between",
1318
+ !toolbarOpen && "hidden",
1319
+ "md:flex"
1320
+ ),
1321
+ children: [
1322
+ /* @__PURE__ */ jsx16("div", { className: "w-full *:w-full *:max-w-none md:*:max-w-md md:grow", children: search }),
1323
+ /* @__PURE__ */ jsxs12("div", { className: "flex w-full flex-col gap-2 *:w-full md:w-auto md:flex-row md:items-center md:gap-2 md:*:w-auto", children: [
1324
+ filter,
1325
+ sort,
1326
+ view
1327
+ ] })
1328
+ ]
1329
+ }
1330
+ )
1280
1331
  ] }) });
1281
1332
  }
1282
1333
 
@@ -1305,7 +1356,7 @@ function Table({ className, ...props }) {
1305
1356
  "table",
1306
1357
  {
1307
1358
  "data-slot": "table",
1308
- className: cn("w-full caption-bottom text-sm", className),
1359
+ className: cn("w-full caption-bottom text-sm px-2", className),
1309
1360
  ...props
1310
1361
  }
1311
1362
  )
@@ -1413,7 +1464,7 @@ function EntityLoadingState({
1413
1464
 
1414
1465
  // src/components/entity/entity-search.tsx
1415
1466
  import { IconSearch, IconX as IconX2 } from "@tabler/icons-react";
1416
- import { parseAsString as parseAsString2, useQueryState as useQueryState2 } from "nuqs";
1467
+ import { parseAsInteger as parseAsInteger2, parseAsString as parseAsString2, useQueryState as useQueryState2 } from "nuqs";
1417
1468
  import { useRef as useRef2 } from "react";
1418
1469
  import { useDebouncedCallback } from "use-debounce";
1419
1470
 
@@ -1443,33 +1494,36 @@ function EntitySearch({
1443
1494
  placeholder = "Search...",
1444
1495
  className
1445
1496
  }) {
1446
- const ref = useRef2(null);
1447
- const [search, setSearch] = useQueryState2(
1497
+ const [value, setValue] = useQueryState2(
1448
1498
  paramKey,
1449
- parseAsString2.withDefault("").withOptions({ shallow: false })
1499
+ parseAsString2.withDefault("")
1450
1500
  );
1501
+ const [, setPage] = useQueryState2("page", parseAsInteger2.withDefault(1));
1502
+ const ref = useRef2(null);
1451
1503
  const handleSearch = useDebouncedCallback((term) => {
1452
- setSearch(term || null);
1504
+ setValue(term || null);
1505
+ setPage(1);
1453
1506
  }, 300);
1454
1507
  const handleClear = () => {
1455
- setSearch(null);
1508
+ setValue(null);
1509
+ setPage(1);
1456
1510
  if (ref.current) {
1457
1511
  ref.current.value = "";
1458
1512
  }
1459
1513
  };
1460
- return /* @__PURE__ */ jsxs14("div", { className: cn("relative", className), children: [
1514
+ return /* @__PURE__ */ jsxs14("div", { className: cn("relative w-full min-w-0", className), children: [
1461
1515
  /* @__PURE__ */ jsx21(IconSearch, { className: "absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }),
1462
1516
  /* @__PURE__ */ jsx21(
1463
1517
  Input,
1464
1518
  {
1465
1519
  ref,
1466
1520
  placeholder,
1467
- defaultValue: search,
1521
+ defaultValue: value,
1468
1522
  onChange: (e) => handleSearch(e.target.value),
1469
- className: "pl-9 pr-9"
1523
+ className: "w-full min-w-0 pl-9 pr-9"
1470
1524
  }
1471
1525
  ),
1472
- search && /* @__PURE__ */ jsx21(
1526
+ value && /* @__PURE__ */ jsx21(
1473
1527
  "button",
1474
1528
  {
1475
1529
  type: "button",
@@ -1486,37 +1540,42 @@ import {
1486
1540
  IconSortAscendingLetters,
1487
1541
  IconSortDescendingLetters
1488
1542
  } from "@tabler/icons-react";
1489
- import { parseAsString as parseAsString3, useQueryState as useQueryState3 } from "nuqs";
1543
+ import { parseAsInteger as parseAsInteger3, parseAsString as parseAsString3, useQueryState as useQueryState3 } from "nuqs";
1490
1544
  import { jsx as jsx22, jsxs as jsxs15 } from "react/jsx-runtime";
1491
1545
  function EntitySort({
1492
- sortKey = "sort",
1493
- orderKey = "order",
1494
1546
  options,
1495
- defaultSort,
1547
+ defaultSort = "createdAt",
1548
+ defaultOrder = "desc",
1496
1549
  className
1497
1550
  }) {
1498
1551
  const [sort, setSort] = useQueryState3(
1499
- sortKey,
1500
- parseAsString3.withDefault(defaultSort || options[0]?.value || "").withOptions({ shallow: false })
1552
+ "sort",
1553
+ parseAsString3.withDefault(defaultSort)
1501
1554
  );
1502
1555
  const [order, setOrder] = useQueryState3(
1503
- orderKey,
1504
- parseAsString3.withDefault("desc").withOptions({ shallow: false })
1556
+ "order",
1557
+ parseAsString3.withDefault(defaultOrder)
1505
1558
  );
1559
+ const [, setPage] = useQueryState3("page", parseAsInteger3.withDefault(1));
1560
+ const handleSortChange = (value) => {
1561
+ setSort(value);
1562
+ setPage(1);
1563
+ };
1506
1564
  const toggleOrder = () => {
1507
1565
  setOrder(order === "asc" ? "desc" : "asc");
1566
+ setPage(1);
1508
1567
  };
1509
- return /* @__PURE__ */ jsxs15("div", { className: cn("flex items-center gap-0", className), children: [
1510
- /* @__PURE__ */ jsxs15(Select, { value: sort, onValueChange: setSort, children: [
1511
- /* @__PURE__ */ jsx22(SelectTrigger, { className: "w-[150px] h-9 rounded-r-none border-r-0", children: /* @__PURE__ */ jsx22(SelectValue, { placeholder: "Sort by" }) }),
1568
+ return /* @__PURE__ */ jsxs15("div", { className: cn("flex w-full items-center gap-0", className), children: [
1569
+ /* @__PURE__ */ jsx22("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsxs15(Select, { value: sort, onValueChange: handleSortChange, children: [
1570
+ /* @__PURE__ */ jsx22(SelectTrigger, { className: "h-9 w-full min-w-[150px] rounded-r-none border-r-0", children: /* @__PURE__ */ jsx22(SelectValue, { placeholder: "Sort by" }) }),
1512
1571
  /* @__PURE__ */ jsx22(SelectContent, { children: options.map((option) => /* @__PURE__ */ jsx22(SelectItem, { value: option.value, children: option.label }, option.value)) })
1513
- ] }),
1572
+ ] }) }),
1514
1573
  /* @__PURE__ */ jsx22(
1515
1574
  Button,
1516
1575
  {
1517
1576
  variant: "outline",
1518
1577
  size: "icon",
1519
- className: "h-9 rounded-l-none",
1578
+ className: "h-9 shrink-0 rounded-l-none",
1520
1579
  onClick: toggleOrder,
1521
1580
  children: order === "asc" ? /* @__PURE__ */ jsx22(IconSortAscendingLetters, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx22(IconSortDescendingLetters, { className: "h-4 w-4" })
1522
1581
  }
@@ -1625,28 +1684,26 @@ var viewIcons = {
1625
1684
  list: /* @__PURE__ */ jsx25(IconList, { className: "h-4 w-4" })
1626
1685
  };
1627
1686
  function EntityViewToggle({
1628
- paramKey = "view",
1629
- defaultView = "table",
1630
1687
  views = ["table", "card"],
1631
1688
  className
1632
1689
  }) {
1633
- const [view, setView] = useQueryState4(
1634
- paramKey,
1635
- parseAsString4.withDefault(defaultView).withOptions({ shallow: false })
1690
+ const [value, setValue] = useQueryState4(
1691
+ "view",
1692
+ parseAsString4.withDefault("table")
1636
1693
  );
1637
1694
  return /* @__PURE__ */ jsx25(
1638
1695
  ToggleGroup,
1639
1696
  {
1640
1697
  type: "single",
1641
- value: view,
1642
- onValueChange: (value) => value && setView(value),
1643
- className: cn("border rounded-md", className),
1698
+ value,
1699
+ onValueChange: (v) => v && setValue(v),
1700
+ className: cn("w-full! border rounded-md md:w-auto!", className),
1644
1701
  children: views.map((v) => /* @__PURE__ */ jsx25(
1645
1702
  ToggleGroupItem,
1646
1703
  {
1647
1704
  value: v,
1648
1705
  "aria-label": `${v} view`,
1649
- className: "h-9 px-3",
1706
+ className: "h-9 min-w-0 flex-1 px-3",
1650
1707
  children: viewIcons[v]
1651
1708
  },
1652
1709
  v
@@ -1654,6 +1711,67 @@ function EntityViewToggle({
1654
1711
  }
1655
1712
  );
1656
1713
  }
1714
+
1715
+ // src/components/entity/use-entity-pagination.ts
1716
+ function useEntityPagination({
1717
+ items,
1718
+ total,
1719
+ pageSize
1720
+ }) {
1721
+ const totalCount = Number(total ?? items.length);
1722
+ const pageCount = Math.ceil(totalCount / pageSize);
1723
+ return {
1724
+ total: totalCount,
1725
+ pageCount,
1726
+ hasData: items.length > 0,
1727
+ isEmpty: totalCount === 0
1728
+ };
1729
+ }
1730
+
1731
+ // src/components/entity/use-entity-params.ts
1732
+ import { parseAsInteger as parseAsInteger4, parseAsString as parseAsString5, useQueryStates } from "nuqs";
1733
+ import { useMemo as useMemo2 } from "react";
1734
+ function useEntityParams(config = {}) {
1735
+ const {
1736
+ searchKey = "search",
1737
+ searchParamName,
1738
+ defaultSort = "createdAt",
1739
+ defaultOrder = "desc",
1740
+ defaultPageSize = 10
1741
+ } = config;
1742
+ const [params, setParams] = useQueryStates({
1743
+ ...searchKey && {
1744
+ [searchKey]: parseAsString5.withDefault("")
1745
+ },
1746
+ view: parseAsString5.withDefault("table"),
1747
+ page: parseAsInteger4.withDefault(1),
1748
+ pageSize: parseAsInteger4.withDefault(defaultPageSize),
1749
+ filter: parseAsString5,
1750
+ sort: parseAsString5.withDefault(defaultSort),
1751
+ order: parseAsString5.withDefault(defaultOrder)
1752
+ });
1753
+ const queryConfig = useMemo2(
1754
+ () => ({
1755
+ params: {
1756
+ query: {
1757
+ page: params.page,
1758
+ limit: params.pageSize,
1759
+ ...searchKey && params[searchKey] && {
1760
+ [searchParamName || (searchKey === "search" ? "search" : "handle")]: params[searchKey]
1761
+ },
1762
+ ...params.filter && { filter: params.filter },
1763
+ ...params.sort && { sort: params.sort, order: params.order }
1764
+ }
1765
+ }
1766
+ }),
1767
+ [params, searchKey, searchParamName]
1768
+ );
1769
+ return {
1770
+ params,
1771
+ setParams,
1772
+ queryConfig
1773
+ };
1774
+ }
1657
1775
  export {
1658
1776
  EntityBulkActions,
1659
1777
  EntityDetailHeader,
@@ -1666,6 +1784,8 @@ export {
1666
1784
  EntityLoadingState,
1667
1785
  EntitySearch,
1668
1786
  EntitySort,
1669
- EntityViewToggle
1787
+ EntityViewToggle,
1788
+ useEntityPagination,
1789
+ useEntityParams
1670
1790
  };
1671
1791
  //# sourceMappingURL=index.js.map