@spacesync/client 0.1.0 → 0.1.1

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 (122) hide show
  1. package/README.md +9 -14
  2. package/dist/analog-clock-picker.d.ts +2 -2
  3. package/dist/analog-clock-picker.js +12 -406
  4. package/dist/analog-clock-picker.js.map +1 -1
  5. package/dist/api.js +7 -87
  6. package/dist/api.js.map +1 -1
  7. package/dist/app-modal.d.ts +7 -8
  8. package/dist/app-modal.js +3 -74
  9. package/dist/app-modal.js.map +1 -1
  10. package/dist/app-shell-mobile-nav.d.ts +1 -2
  11. package/dist/app-shell-mobile-nav.js +2 -66
  12. package/dist/app-shell-mobile-nav.js.map +1 -1
  13. package/dist/app-web-shell.d.ts +2 -2
  14. package/dist/app-web-shell.js +1 -4
  15. package/dist/app-web-shell.js.map +1 -1
  16. package/dist/booking-schedule-calendars.d.ts +12 -12
  17. package/dist/booking-schedule-calendars.js +13 -402
  18. package/dist/booking-schedule-calendars.js.map +1 -1
  19. package/dist/chat-stick-to-bottom.d.ts +1 -2
  20. package/dist/chat-stick-to-bottom.js +12 -48
  21. package/dist/chat-stick-to-bottom.js.map +1 -1
  22. package/dist/chunk-4A6RCBB5.js +4925 -0
  23. package/dist/chunk-4A6RCBB5.js.map +1 -0
  24. package/dist/chunk-4NNK5IXY.js +79 -0
  25. package/dist/chunk-4NNK5IXY.js.map +1 -0
  26. package/dist/chunk-4Y5DBM6Z.js +6 -0
  27. package/dist/chunk-4Y5DBM6Z.js.map +1 -0
  28. package/dist/chunk-7YCAAP43.js +107 -0
  29. package/dist/chunk-7YCAAP43.js.map +1 -0
  30. package/dist/chunk-DMPSQ22Q.js +11 -0
  31. package/dist/chunk-DMPSQ22Q.js.map +1 -0
  32. package/dist/chunk-FCY5FYJB.js +104 -0
  33. package/dist/chunk-FCY5FYJB.js.map +1 -0
  34. package/dist/chunk-H7EX6B6N.js +580 -0
  35. package/dist/chunk-H7EX6B6N.js.map +1 -0
  36. package/dist/chunk-HCHASUB6.js +13 -0
  37. package/dist/chunk-HCHASUB6.js.map +1 -0
  38. package/dist/chunk-L65F4EMK.js +34 -0
  39. package/dist/chunk-L65F4EMK.js.map +1 -0
  40. package/dist/chunk-LUB7QWGU.js +301 -0
  41. package/dist/chunk-LUB7QWGU.js.map +1 -0
  42. package/dist/chunk-OMSJWTSZ.js +120 -0
  43. package/dist/chunk-OMSJWTSZ.js.map +1 -0
  44. package/dist/chunk-OWNUMPUC.js +9 -0
  45. package/dist/chunk-OWNUMPUC.js.map +1 -0
  46. package/dist/chunk-P65TMY3D.js +87 -0
  47. package/dist/chunk-P65TMY3D.js.map +1 -0
  48. package/dist/chunk-PBNBLCC2.js +84 -0
  49. package/dist/chunk-PBNBLCC2.js.map +1 -0
  50. package/dist/chunk-RV5PMZYZ.js +63 -0
  51. package/dist/chunk-RV5PMZYZ.js.map +1 -0
  52. package/dist/chunk-VHINHHZQ.js +48 -0
  53. package/dist/chunk-VHINHHZQ.js.map +1 -0
  54. package/dist/chunk-VVXGQKN7.js +107 -0
  55. package/dist/chunk-VVXGQKN7.js.map +1 -0
  56. package/dist/chunk-XU3EFSQX.js +22 -0
  57. package/dist/chunk-XU3EFSQX.js.map +1 -0
  58. package/dist/chunk-YAVEMXXV.js +381 -0
  59. package/dist/chunk-YAVEMXXV.js.map +1 -0
  60. package/dist/chunk-ZIJQ7BXU.js +27 -0
  61. package/dist/chunk-ZIJQ7BXU.js.map +1 -0
  62. package/dist/detail-page-header.d.ts +3 -3
  63. package/dist/detail-page-header.js +5 -149
  64. package/dist/detail-page-header.js.map +1 -1
  65. package/dist/{dialog-CIdvylPK.d.ts → dialog-CPkbi5N3.d.ts} +10 -11
  66. package/dist/file-picker-field.d.ts +2 -2
  67. package/dist/file-picker-field.js +3 -163
  68. package/dist/file-picker-field.js.map +1 -1
  69. package/dist/file-viewer-dialog.d.ts +2 -2
  70. package/dist/file-viewer-dialog.js +12 -223
  71. package/dist/file-viewer-dialog.js.map +1 -1
  72. package/dist/floor-switcher.d.ts +2 -2
  73. package/dist/floor-switcher.js +13 -323
  74. package/dist/floor-switcher.js.map +1 -1
  75. package/dist/forms.js +1 -23
  76. package/dist/forms.js.map +1 -1
  77. package/dist/image-picker-field.d.ts +2 -2
  78. package/dist/image-picker-field.js +3 -48
  79. package/dist/image-picker-field.js.map +1 -1
  80. package/dist/layout-canvas-view.d.ts +2 -2
  81. package/dist/layout-canvas-view.js +17 -220
  82. package/dist/layout-canvas-view.js.map +1 -1
  83. package/dist/lib/dateDisplay.js +1 -82
  84. package/dist/lib/dateDisplay.js.map +1 -1
  85. package/dist/live-resource-meta.js +1 -25
  86. package/dist/live-resource-meta.js.map +1 -1
  87. package/dist/live-space-pulse-dot.d.ts +2 -2
  88. package/dist/live-space-pulse-dot.js +2 -16
  89. package/dist/live-space-pulse-dot.js.map +1 -1
  90. package/dist/notification-sidebar-preview.d.ts +3 -3
  91. package/dist/notification-sidebar-preview.js +3 -61
  92. package/dist/notification-sidebar-preview.js.map +1 -1
  93. package/dist/page-list-chrome.d.ts +25 -25
  94. package/dist/page-list-chrome.js +6 -968
  95. package/dist/page-list-chrome.js.map +1 -1
  96. package/dist/platform-support-message-composer.d.ts +4 -4
  97. package/dist/platform-support-message-composer.js +15 -218
  98. package/dist/platform-support-message-composer.js.map +1 -1
  99. package/dist/shell-sidebar-nav.js +8 -13
  100. package/dist/shell-sidebar-nav.js.map +1 -1
  101. package/dist/shell-theme.js +1 -7
  102. package/dist/shell-theme.js.map +1 -1
  103. package/dist/shell-top-bar-chrome.js +3 -103
  104. package/dist/shell-top-bar-chrome.js.map +1 -1
  105. package/dist/shell-top-bar.d.ts +3 -3
  106. package/dist/shell-top-bar.js +1 -69
  107. package/dist/shell-top-bar.js.map +1 -1
  108. package/dist/support-presence-status.d.ts +2 -2
  109. package/dist/support-presence-status.js +3 -41
  110. package/dist/support-presence-status.js.map +1 -1
  111. package/dist/theme-appearance-control.d.ts +2 -2
  112. package/dist/theme-appearance-control.js +4 -63
  113. package/dist/theme-appearance-control.js.map +1 -1
  114. package/dist/theme-boot-script.js +1 -2
  115. package/dist/theme-boot-script.js.map +1 -1
  116. package/dist/theme-provider.d.ts +2 -2
  117. package/dist/theme-provider.js +2 -23
  118. package/dist/theme-provider.js.map +1 -1
  119. package/dist/ui.d.ts +261 -262
  120. package/dist/ui.js +11 -5635
  121. package/dist/ui.js.map +1 -1
  122. package/package.json +11 -2
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/theme/shell-theme.ts","../src/ui/utils.ts","../src/shell/shell-sidebar-nav.ts"],"names":[],"mappings":";;;;AAKO,SAAS,aAAA,GAA4B;AAC1C,EAAA,OAAuC,OAAA;AACzC;ACJO,SAAS,MAAM,MAAA,EAAsB;AAC1C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC7B;;;ACDA,IAAM,uBAAA,GACJ,mGAAA;AAGK,SAAS,wBAAA,CAAyB,UAAmB,SAAA,EAAoB;AAG9E,EAAA,OAAO,EAAA;AAAA,IACL,yFAAA;AAAA,IACA,uBAAA;AAAA,IACA,YACI,yCAAA,GACA,mDAAA;AAAA,IACJ,QAAA,GAGM,6CAAA,GACF;AAAA,GACN;AACF;AAEO,SAAS,yBAAyB,QAAA,EAAmB;AAC1D,EAAA,MAAM,WAAA,GAAc,eAAc,KAAM,MAAA;AACxC,EAAA,IAAI,CAAC,UAAU,OAAO,4BAAA;AACtB,EAAA,OAAO,cAAc,eAAA,GAAkB,eAAA;AACzC;AAEO,SAAS,gCAAgC,SAAA,EAAoB;AAClE,EAAA,OAAO,EAAA;AAAA,IACL,wBAAA,CAAyB,OAAO,SAAS,CAAA;AAAA,IACzC;AAAA,GACF;AACF;AAGO,SAAS,4BAA4B,QAAA,EAAmB;AAG7D,EAAA,OAAO,EAAA;AAAA,IACL,yFAAA;AAAA,IACA,uBAAA;AAAA,IACA,wCAAA;AAAA,IACA,QAAA,GAGM,6CAAA,GACF;AAAA,GACN;AACF;AAGO,SAAS,+BAAA,CACd,eAAA,EACA,SAAA,EACA,MAAA,EACA;AACA,EAAA,OAAO,EAAA;AAAA,IACL,wBAAA,CAAyB,eAAA,IAAmB,CAAC,MAAA,EAAQ,SAAS,CAAA;AAAA,IAC9D,CAAC,SAAA,IAAa,MAAA,IAAU,eAAA,IAAmB;AAAA,GAC7C;AACF;AAGO,SAAS,+BAA+B,QAAA,EAAmB;AAChE,EAAA,OAAO,EAAA;AAAA,IACL,iGAAA;AAAA,IACA,WACI,oDAAA,GACA;AAAA,GACN;AACF;AAGO,SAAS,sCAAsC,MAAA,EAAiB;AACrE,EAAA,OAAO,EAAA;AAAA,IACL,4DAAA;AAAA,IACA,SAAS,iBAAA,GAAoB;AAAA,GAC/B;AACF;AAGO,SAAS,8BAAA,CAA+B,gBAAgB,KAAA,EAAO;AAGpE,EAAA,OAAO,EAAA;AAAA,IACL,oIAAA;AAAA,IACA,gBAAgB,4BAAA,GAA+B,SAAA;AAAA,IACE;AAAA,GACnD;AACF","file":"shell-sidebar-nav.js","sourcesContent":["/** Flip to compare light vs dark outer shell with the team. */\nexport const SHELL_USE_DARK_THEME = false;\n\nexport type ShellTheme = \"light\" | \"dark\";\n\nexport function getShellTheme(): ShellTheme {\n return SHELL_USE_DARK_THEME ? \"dark\" : \"light\";\n}\n","import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import { getShellTheme } from \"../theme/shell-theme\";\nimport { cn } from \"../ui/utils\";\n\n/** Neutralize default {@link Button} chrome when it doubles as a sidebar nav row. */\nconst shellSidebarButtonReset =\n \"font-normal shadow-none hover:bg-sidebar-accent hover:text-sidebar-foreground [&_svg]:size-[18px]\";\n\n/** Nav link / button styles for {@link AppWebShell}'s sidebar column. */\nexport function shellSidebarNavItemClass(isActive: boolean, collapsed: boolean) {\n const isDarkShell = getShellTheme() === \"dark\";\n\n return cn(\n \"relative flex w-full items-center rounded-lg border text-left text-sm transition-colors\",\n shellSidebarButtonReset,\n collapsed\n ? \"h-9 justify-center px-0 has-[>svg]:px-0\"\n : \"justify-start gap-3 px-2.5 py-2 has-[>svg]:px-2.5\",\n isActive\n ? isDarkShell\n ? \"border-blue-500/25 bg-blue-500/15 text-blue-300\"\n : \"border-blue-200/60 bg-blue-50 text-blue-700\"\n : \"border-transparent text-sidebar-foreground/65 hover:bg-sidebar-accent hover:text-sidebar-foreground\",\n );\n}\n\nexport function shellSidebarNavIconClass(isActive: boolean) {\n const isDarkShell = getShellTheme() === \"dark\";\n if (!isActive) return \"text-sidebar-foreground/55\";\n return isDarkShell ? \"text-blue-400\" : \"text-blue-600\";\n}\n\nexport function shellSidebarCollapseButtonClass(collapsed: boolean) {\n return cn(\n shellSidebarNavItemClass(false, collapsed),\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500/30\",\n );\n}\n\n/** Sub-item row inside an expanded nav group (e.g. Bookings → Today's Booking). */\nexport function shellSidebarNavSubItemClass(isActive: boolean) {\n const isDarkShell = getShellTheme() === \"dark\";\n\n return cn(\n \"relative flex w-full items-center rounded-md border text-left text-sm transition-colors\",\n shellSidebarButtonReset,\n \"justify-start gap-2 py-1.5 pl-9 pr-2.5\",\n isActive\n ? isDarkShell\n ? \"border-blue-500/25 bg-blue-500/15 text-blue-300\"\n : \"border-blue-200/60 bg-blue-50 text-blue-700\"\n : \"border-transparent text-sidebar-foreground/60 hover:bg-sidebar-accent hover:text-sidebar-foreground\",\n );\n}\n\n/** Parent row for a nav group with expandable children. */\nexport function shellSidebarNavGroupHeaderClass(\n isSectionActive: boolean,\n collapsed: boolean,\n isOpen: boolean,\n) {\n return cn(\n shellSidebarNavItemClass(isSectionActive && !isOpen, collapsed),\n !collapsed && isOpen && isSectionActive && \"border-transparent bg-transparent text-sidebar-foreground/65\",\n );\n}\n\n/** Flyout sub-item (collapsed sidebar hover panel). */\nexport function shellSidebarFlyoutSubItemClass(isActive: boolean) {\n return cn(\n \"flex w-full items-center justify-between gap-2 rounded-md px-2.5 py-2 text-sm transition-colors\",\n isActive\n ? \"bg-blue-500/20 font-medium text-popover-foreground\"\n : \"text-popover-foreground/85 hover:bg-white/10 hover:text-popover-foreground\",\n );\n}\n\n/** Animated wrapper for expandable submenu lists. */\nexport function shellSidebarNavSubItemsContainerClass(isOpen: boolean) {\n return cn(\n \"grid transition-[grid-template-rows] duration-200 ease-out\",\n isOpen ? \"grid-rows-[1fr]\" : \"grid-rows-[0fr]\",\n );\n}\n\n/** Numeric count badge on submenu rows or collapsed group icons. */\nexport function shellSidebarNavCountBadgeClass(collapsedIcon = false) {\n const isDarkShell = getShellTheme() === \"dark\";\n\n return cn(\n \"pointer-events-none flex h-5 min-w-5 shrink-0 items-center justify-center rounded-full px-1 text-[10px] font-semibold tabular-nums\",\n collapsedIcon ? \"absolute right-0.5 top-0.5\" : \"ml-auto\",\n isDarkShell ? \"bg-amber-500/20 text-amber-300\" : \"bg-amber-100 text-amber-700\",\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/shell/shell-sidebar-nav.ts"],"names":[],"mappings":";;;;AAIA,IAAM,uBAAA,GACJ,mGAAA;AAGK,SAAS,wBAAA,CAAyB,UAAmB,SAAA,EAAoB;AAC9E,EAAA,MAAM,WAAA,GAAc,eAAc,KAAM,MAAA;AAExC,EAAA,OAAO,EAAA;AAAA,IACL,yFAAA;AAAA,IACA,uBAAA;AAAA,IACA,YACI,yCAAA,GACA,mDAAA;AAAA,IACJ,QAAA,GACI,WAAA,GACE,iDAAA,GACA,6CAAA,GACF;AAAA,GACN;AACF;AAEO,SAAS,yBAAyB,QAAA,EAAmB;AAC1D,EAAA,MAAM,WAAA,GAAc,eAAc,KAAM,MAAA;AACxC,EAAA,IAAI,CAAC,UAAU,OAAO,4BAAA;AACtB,EAAA,OAAO,cAAc,eAAA,GAAkB,eAAA;AACzC;AAEO,SAAS,gCAAgC,SAAA,EAAoB;AAClE,EAAA,OAAO,EAAA;AAAA,IACL,wBAAA,CAAyB,OAAO,SAAS,CAAA;AAAA,IACzC;AAAA,GACF;AACF;AAGO,SAAS,4BAA4B,QAAA,EAAmB;AAC7D,EAAA,MAAM,WAAA,GAAc,eAAc,KAAM,MAAA;AAExC,EAAA,OAAO,EAAA;AAAA,IACL,yFAAA;AAAA,IACA,uBAAA;AAAA,IACA,wCAAA;AAAA,IACA,QAAA,GACI,WAAA,GACE,iDAAA,GACA,6CAAA,GACF;AAAA,GACN;AACF;AAGO,SAAS,+BAAA,CACd,eAAA,EACA,SAAA,EACA,MAAA,EACA;AACA,EAAA,OAAO,EAAA;AAAA,IACL,wBAAA,CAAyB,eAAA,IAAmB,CAAC,MAAA,EAAQ,SAAS,CAAA;AAAA,IAC9D,CAAC,SAAA,IAAa,MAAA,IAAU,eAAA,IAAmB;AAAA,GAC7C;AACF;AAGO,SAAS,+BAA+B,QAAA,EAAmB;AAChE,EAAA,OAAO,EAAA;AAAA,IACL,iGAAA;AAAA,IACA,WACI,oDAAA,GACA;AAAA,GACN;AACF;AAGO,SAAS,sCAAsC,MAAA,EAAiB;AACrE,EAAA,OAAO,EAAA;AAAA,IACL,4DAAA;AAAA,IACA,SAAS,iBAAA,GAAoB;AAAA,GAC/B;AACF;AAGO,SAAS,8BAAA,CAA+B,gBAAgB,KAAA,EAAO;AACpE,EAAA,MAAM,WAAA,GAAc,eAAc,KAAM,MAAA;AAExC,EAAA,OAAO,EAAA;AAAA,IACL,oIAAA;AAAA,IACA,gBAAgB,4BAAA,GAA+B,SAAA;AAAA,IAC/C,cAAc,gCAAA,GAAmC;AAAA,GACnD;AACF","file":"shell-sidebar-nav.js","sourcesContent":["import { getShellTheme } from \"../theme/shell-theme\";\nimport { cn } from \"../ui/utils\";\n\n/** Neutralize default {@link Button} chrome when it doubles as a sidebar nav row. */\nconst shellSidebarButtonReset =\n \"font-normal shadow-none hover:bg-sidebar-accent hover:text-sidebar-foreground [&_svg]:size-[18px]\";\n\n/** Nav link / button styles for {@link AppWebShell}'s sidebar column. */\nexport function shellSidebarNavItemClass(isActive: boolean, collapsed: boolean) {\n const isDarkShell = getShellTheme() === \"dark\";\n\n return cn(\n \"relative flex w-full items-center rounded-lg border text-left text-sm transition-colors\",\n shellSidebarButtonReset,\n collapsed\n ? \"h-9 justify-center px-0 has-[>svg]:px-0\"\n : \"justify-start gap-3 px-2.5 py-2 has-[>svg]:px-2.5\",\n isActive\n ? isDarkShell\n ? \"border-blue-500/25 bg-blue-500/15 text-blue-300\"\n : \"border-blue-200/60 bg-blue-50 text-blue-700\"\n : \"border-transparent text-sidebar-foreground/65 hover:bg-sidebar-accent hover:text-sidebar-foreground\",\n );\n}\n\nexport function shellSidebarNavIconClass(isActive: boolean) {\n const isDarkShell = getShellTheme() === \"dark\";\n if (!isActive) return \"text-sidebar-foreground/55\";\n return isDarkShell ? \"text-blue-400\" : \"text-blue-600\";\n}\n\nexport function shellSidebarCollapseButtonClass(collapsed: boolean) {\n return cn(\n shellSidebarNavItemClass(false, collapsed),\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500/30\",\n );\n}\n\n/** Sub-item row inside an expanded nav group (e.g. Bookings → Today's Booking). */\nexport function shellSidebarNavSubItemClass(isActive: boolean) {\n const isDarkShell = getShellTheme() === \"dark\";\n\n return cn(\n \"relative flex w-full items-center rounded-md border text-left text-sm transition-colors\",\n shellSidebarButtonReset,\n \"justify-start gap-2 py-1.5 pl-9 pr-2.5\",\n isActive\n ? isDarkShell\n ? \"border-blue-500/25 bg-blue-500/15 text-blue-300\"\n : \"border-blue-200/60 bg-blue-50 text-blue-700\"\n : \"border-transparent text-sidebar-foreground/60 hover:bg-sidebar-accent hover:text-sidebar-foreground\",\n );\n}\n\n/** Parent row for a nav group with expandable children. */\nexport function shellSidebarNavGroupHeaderClass(\n isSectionActive: boolean,\n collapsed: boolean,\n isOpen: boolean,\n) {\n return cn(\n shellSidebarNavItemClass(isSectionActive && !isOpen, collapsed),\n !collapsed && isOpen && isSectionActive && \"border-transparent bg-transparent text-sidebar-foreground/65\",\n );\n}\n\n/** Flyout sub-item (collapsed sidebar hover panel). */\nexport function shellSidebarFlyoutSubItemClass(isActive: boolean) {\n return cn(\n \"flex w-full items-center justify-between gap-2 rounded-md px-2.5 py-2 text-sm transition-colors\",\n isActive\n ? \"bg-blue-500/20 font-medium text-popover-foreground\"\n : \"text-popover-foreground/85 hover:bg-white/10 hover:text-popover-foreground\",\n );\n}\n\n/** Animated wrapper for expandable submenu lists. */\nexport function shellSidebarNavSubItemsContainerClass(isOpen: boolean) {\n return cn(\n \"grid transition-[grid-template-rows] duration-200 ease-out\",\n isOpen ? \"grid-rows-[1fr]\" : \"grid-rows-[0fr]\",\n );\n}\n\n/** Numeric count badge on submenu rows or collapsed group icons. */\nexport function shellSidebarNavCountBadgeClass(collapsedIcon = false) {\n const isDarkShell = getShellTheme() === \"dark\";\n\n return cn(\n \"pointer-events-none flex h-5 min-w-5 shrink-0 items-center justify-center rounded-full px-1 text-[10px] font-semibold tabular-nums\",\n collapsedIcon ? \"absolute right-0.5 top-0.5\" : \"ml-auto\",\n isDarkShell ? \"bg-amber-500/20 text-amber-300\" : \"bg-amber-100 text-amber-700\",\n );\n}\n"]}
@@ -1,9 +1,3 @@
1
- // src/theme/shell-theme.ts
2
- var SHELL_USE_DARK_THEME = false;
3
- function getShellTheme() {
4
- return "light";
5
- }
6
-
7
- export { SHELL_USE_DARK_THEME, getShellTheme };
1
+ export { SHELL_USE_DARK_THEME, getShellTheme } from './chunk-OWNUMPUC.js';
8
2
  //# sourceMappingURL=shell-theme.js.map
9
3
  //# sourceMappingURL=shell-theme.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/theme/shell-theme.ts"],"names":[],"mappings":";AACO,IAAM,oBAAA,GAAuB;AAI7B,SAAS,aAAA,GAA4B;AAC1C,EAAA,OAAuC,OAAA;AACzC","file":"shell-theme.js","sourcesContent":["/** Flip to compare light vs dark outer shell with the team. */\nexport const SHELL_USE_DARK_THEME = false;\n\nexport type ShellTheme = \"light\" | \"dark\";\n\nexport function getShellTheme(): ShellTheme {\n return SHELL_USE_DARK_THEME ? \"dark\" : \"light\";\n}\n"]}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"shell-theme.js"}
@@ -1,105 +1,5 @@
1
- import { clsx } from 'clsx';
2
- import { twMerge } from 'tailwind-merge';
3
-
4
- // src/theme/shell-theme.ts
5
- function cn(...inputs) {
6
- return twMerge(clsx(inputs));
7
- }
8
-
9
- // src/shell/shell-top-bar-chrome.ts
10
- var shellTopBarMutedIconClass = "text-sidebar-foreground/60";
11
- var shellTopBarTitleTextClass = "text-sidebar-foreground";
12
- var shellTopBarActionSize = cn(
13
- "inline-flex !h-7 min-h-0 items-center justify-center gap-1 px-2.5 text-xs font-medium",
14
- "[&_svg:not([class*='size-'])]:size-3.5"
15
- );
16
- var shellTopBarRadius = "rounded-md";
17
- var shellTopBarNeutralRest = "border border-sidebar-border bg-sidebar-accent text-sidebar-foreground shadow-none transition-colors";
18
- var shellTopBarNeutralHover = "hover:!border-sidebar-foreground/14 hover:!bg-sidebar-foreground/6 hover:!text-sidebar-foreground";
19
- var shellTopBarNeutralActive = "active:!border-sidebar-foreground/10 active:!bg-sidebar-foreground/4 active:!text-sidebar-foreground";
20
- var shellTopBarNeutralActionDataAttr = {
21
- "data-shell-top-bar-action": ""
22
- };
23
- var shellTopBarBackButtonClass = cn(
24
- "inline-flex !h-6 !w-6 shrink-0 items-center justify-center text-sidebar-foreground/70",
25
- shellTopBarRadius,
26
- shellTopBarNeutralRest,
27
- shellTopBarNeutralHover,
28
- shellTopBarNeutralActive
29
- );
30
- var shellTopBarIconButtonClass = cn(
31
- "inline-flex !h-7 !w-7 shrink-0 items-center justify-center text-sidebar-foreground/70",
32
- shellTopBarRadius,
33
- shellTopBarNeutralRest,
34
- shellTopBarNeutralHover,
35
- shellTopBarNeutralActive,
36
- "[&_svg:not([class*='size-'])]:size-3.5"
37
- );
38
- var shellTopBarSecondaryButtonClass = cn(
39
- shellTopBarActionSize,
40
- shellTopBarRadius,
41
- "!border-sidebar-border !bg-sidebar-accent !text-sidebar-foreground shadow-none transition-colors",
42
- "!py-0",
43
- shellTopBarNeutralHover,
44
- shellTopBarNeutralActive,
45
- "disabled:pointer-events-none disabled:!border-sidebar-border/60 disabled:!bg-sidebar-accent/60 disabled:!text-sidebar-foreground/40"
46
- );
47
- var shellTopBarPrimaryButtonClass = cn(
48
- shellTopBarActionSize,
49
- shellTopBarRadius,
50
- "bg-blue-500 text-white transition-colors hover:bg-blue-600",
51
- "disabled:pointer-events-none disabled:opacity-50"
52
- );
53
- var shellTopBarAccentButtonClass = cn(
54
- shellTopBarActionSize,
55
- shellTopBarRadius,
56
- "bg-emerald-600 text-white transition-colors hover:bg-emerald-700"
57
- );
58
- var shellTopBarSuccessButtonClass = cn(
59
- shellTopBarActionSize,
60
- shellTopBarRadius,
61
- "border border-emerald-200 bg-emerald-50 text-emerald-700 transition-colors hover:border-emerald-300 hover:bg-emerald-100"
62
- );
63
- var shellTopBarInfoButtonClass = cn(
64
- shellTopBarActionSize,
65
- shellTopBarRadius,
66
- "border border-blue-200 bg-blue-50 text-blue-700 transition-colors hover:border-blue-300 hover:bg-blue-100"
67
- );
68
- var shellTopBarOutlineButtonClass = shellTopBarSecondaryButtonClass;
69
- var shellTopBarSegmentedShellClass = cn(
70
- "flex items-center gap-0.5 border border-sidebar-border bg-sidebar-accent p-0.5",
71
- shellTopBarRadius
72
- );
73
- function shellTopBarSegmentedItemClass(active) {
74
- return cn(
75
- shellTopBarActionSize,
76
- "!h-6 px-2",
77
- "rounded-sm",
78
- active ? "bg-white text-sidebar-foreground shadow-sm" : "text-sidebar-foreground/60 hover:bg-sidebar-foreground/6 hover:text-sidebar-foreground"
79
- );
80
- }
81
- var shellTopBarControlGroupClass = cn(
82
- "flex h-7 items-center gap-1.5 border border-sidebar-border bg-sidebar-accent pl-2.5 pr-1 text-sidebar-foreground",
83
- shellTopBarRadius
84
- );
85
- var shellTopBarControlLabelClass = "m-0 shrink-0 text-[11px] font-normal text-sidebar-foreground/60";
86
- var shellTopBarSelectTriggerClass = "h-6 min-w-[140px] flex-1 border-0 bg-transparent px-1 text-xs text-sidebar-foreground shadow-none focus-visible:ring-0 focus-visible:ring-offset-0 [&_svg]:text-sidebar-foreground/60";
87
- var shellTopBarCompactIconButtonClass = cn(
88
- "inline-flex !h-6 !w-6 items-center justify-center text-sidebar-foreground/70",
89
- shellTopBarRadius,
90
- shellTopBarNeutralRest,
91
- shellTopBarNeutralHover,
92
- shellTopBarNeutralActive,
93
- "[&_svg:not([class*='size-'])]:size-3.5"
94
- );
95
- var shellTopBarDateLabelButtonClass = cn(
96
- shellTopBarActionSize,
97
- "min-w-[72px]",
98
- shellTopBarNeutralRest,
99
- shellTopBarNeutralHover,
100
- shellTopBarNeutralActive
101
- );
102
-
103
- export { shellTopBarAccentButtonClass, shellTopBarBackButtonClass, shellTopBarCompactIconButtonClass, shellTopBarControlGroupClass, shellTopBarControlLabelClass, shellTopBarDateLabelButtonClass, shellTopBarIconButtonClass, shellTopBarInfoButtonClass, shellTopBarMutedIconClass, shellTopBarNeutralActionDataAttr, shellTopBarOutlineButtonClass, shellTopBarPrimaryButtonClass, shellTopBarSecondaryButtonClass, shellTopBarSegmentedItemClass, shellTopBarSegmentedShellClass, shellTopBarSelectTriggerClass, shellTopBarSuccessButtonClass, shellTopBarTitleTextClass };
1
+ export { shellTopBarAccentButtonClass, shellTopBarBackButtonClass, shellTopBarCompactIconButtonClass, shellTopBarControlGroupClass, shellTopBarControlLabelClass, shellTopBarDateLabelButtonClass, shellTopBarIconButtonClass, shellTopBarInfoButtonClass, shellTopBarMutedIconClass, shellTopBarNeutralActionDataAttr, shellTopBarOutlineButtonClass, shellTopBarPrimaryButtonClass, shellTopBarSecondaryButtonClass, shellTopBarSegmentedItemClass, shellTopBarSegmentedShellClass, shellTopBarSelectTriggerClass, shellTopBarSuccessButtonClass, shellTopBarTitleTextClass } from './chunk-FCY5FYJB.js';
2
+ import './chunk-OWNUMPUC.js';
3
+ import './chunk-DMPSQ22Q.js';
104
4
  //# sourceMappingURL=shell-top-bar-chrome.js.map
105
5
  //# sourceMappingURL=shell-top-bar-chrome.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ui/utils.ts","../src/shell/shell-top-bar-chrome.ts"],"names":[],"mappings":";;;;AAGO,SAAS,MAAM,MAAA,EAAsB;AAC1C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC7B;;;ACFO,IAAM,yBAAA,GAA4B;AAClC,IAAM,yBAAA,GAA4B;AAGzC,IAAM,qBAAA,GAAwB,EAAA;AAAA,EAC5B,uFAAA;AAAA,EACA;AACF,CAAA;AACA,IAAM,iBAAA,GAAoB,YAAA;AAO1B,IAAM,sBAAA,GACJ,sGAAA;AAGF,IAAM,uBAAA,GAEF,mGAAA;AAEJ,IAAM,wBAAA,GAEF,sGAAA;AAGG,IAAM,gCAAA,GAAmC;AAAA,EAC9C,2BAAA,EAA6B;AAC/B;AAGO,IAAM,0BAAA,GAA6B,EAAA;AAAA,EACxC,uFAAA;AAAA,EACA,iBAAA;AAAA,EACA,sBAAA;AAAA,EACA,uBAAA;AAAA,EACA;AACF;AAGO,IAAM,0BAAA,GAA6B,EAAA;AAAA,EACxC,uFAAA;AAAA,EACA,iBAAA;AAAA,EACA,sBAAA;AAAA,EACA,uBAAA;AAAA,EACA,wBAAA;AAAA,EACA;AACF;AAMO,IAAM,+BAAA,GAAkC,EAAA;AAAA,EAC7C,qBAAA;AAAA,EACA,iBAAA;AAAA,EACA,kGAAA;AAAA,EACA,OAAA;AAAA,EACA,uBAAA;AAAA,EACA,wBAAA;AAAA,EACA;AACF;AAGO,IAAM,6BAAA,GAAgC,EAAA;AAAA,EAC3C,qBAAA;AAAA,EACA,iBAAA;AAAA,EACA,4DAAA;AAAA,EACA;AACF;AAGO,IAAM,4BAAA,GAA+B,EAAA;AAAA,EAC1C,qBAAA;AAAA,EACA,iBAAA;AAAA,EACA;AACF;AAGO,IAAM,6BAAA,GAAgC,EAAA;AAAA,EAC3C,qBAAA;AAAA,EACA,iBAAA;AAAA,EAGI;AACN;AAGO,IAAM,0BAAA,GAA6B,EAAA;AAAA,EACxC,qBAAA;AAAA,EACA,iBAAA;AAAA,EAGI;AACN;AAGO,IAAM,6BAAA,GAAgC;AAGtC,IAAM,8BAAA,GAAiC,EAAA;AAAA,EAC5C,gFAAA;AAAA,EACA;AACF;AAEO,SAAS,8BAA8B,MAAA,EAAiB;AAE7D,EAAA,OAAO,EAAA;AAAA,IACL,qBAAA;AAAA,IACA,WAAA;AAAA,IACA,YAAA;AAAA,IACA,MAAA,GAGM,4CAAA,GAGA;AAAA,GACR;AACF;AAGO,IAAM,4BAAA,GAA+B,EAAA;AAAA,EAC1C,kHAAA;AAAA,EACA;AACF;AAEO,IAAM,4BAAA,GACX;AAGK,IAAM,6BAAA,GACX;AAGK,IAAM,iCAAA,GAAoC,EAAA;AAAA,EAC/C,8EAAA;AAAA,EACA,iBAAA;AAAA,EACA,sBAAA;AAAA,EACA,uBAAA;AAAA,EACA,wBAAA;AAAA,EACA;AACF;AAGO,IAAM,+BAAA,GAAkC,EAAA;AAAA,EAC7C,qBAAA;AAAA,EACA,cAAA;AAAA,EACA,sBAAA;AAAA,EACA,uBAAA;AAAA,EACA;AACF","file":"shell-top-bar-chrome.js","sourcesContent":["import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import { getShellTheme } from \"../theme/shell-theme\";\nimport { cn } from \"../ui/utils\";\n\nexport const shellTopBarMutedIconClass = \"text-sidebar-foreground/60\";\nexport const shellTopBarTitleTextClass = \"text-sidebar-foreground\";\n\n/** Shared sizing and corner radius for shell top bar actions. */\nconst shellTopBarActionSize = cn(\n \"inline-flex !h-7 min-h-0 items-center justify-center gap-1 px-2.5 text-xs font-medium\",\n \"[&_svg:not([class*='size-'])]:size-3.5\",\n);\nconst shellTopBarRadius = \"rounded-md\";\n\nfunction isDarkShell() {\n return getShellTheme() === \"dark\";\n}\n\n/** Resting surface for neutral shell controls (secondary, outline, icon). */\nconst shellTopBarNeutralRest =\n \"border border-sidebar-border bg-sidebar-accent text-sidebar-foreground shadow-none transition-colors\";\n\n/** Visible hover — lighten fill on dark shell, darken on light shell. */\nconst shellTopBarNeutralHover = isDarkShell()\n ? \"hover:!border-sidebar-foreground/25 hover:!bg-sidebar-foreground/12 hover:!text-sidebar-foreground\"\n : \"hover:!border-sidebar-foreground/14 hover:!bg-sidebar-foreground/6 hover:!text-sidebar-foreground\";\n\nconst shellTopBarNeutralActive = isDarkShell()\n ? \"active:!border-sidebar-foreground/20 active:!bg-sidebar-foreground/8 active:!text-sidebar-foreground\"\n : \"active:!border-sidebar-foreground/10 active:!bg-sidebar-foreground/4 active:!text-sidebar-foreground\";\n\n/** Apply to native shell actions (links, ticket buttons) so they share the same hover treatment as {@link ShellTopBarSecondaryActionButton}. */\nexport const shellTopBarNeutralActionDataAttr = {\n \"data-shell-top-bar-action\": \"\",\n} as const;\n\n/** Compact back control in the shell top bar (detail pages). */\nexport const shellTopBarBackButtonClass = cn(\n \"inline-flex !h-6 !w-6 shrink-0 items-center justify-center text-sidebar-foreground/70\",\n shellTopBarRadius,\n shellTopBarNeutralRest,\n shellTopBarNeutralHover,\n shellTopBarNeutralActive,\n);\n\n/** Icon-only control (e.g. overflow menu) in the shell top bar. */\nexport const shellTopBarIconButtonClass = cn(\n \"inline-flex !h-7 !w-7 shrink-0 items-center justify-center text-sidebar-foreground/70\",\n shellTopBarRadius,\n shellTopBarNeutralRest,\n shellTopBarNeutralHover,\n shellTopBarNeutralActive,\n \"[&_svg:not([class*='size-'])]:size-3.5\",\n);\n\n/**\n * Neutral secondary / outline action in the shell top bar.\n * Uses `!` on hover so shadcn `Button variant=\"outline\"` cannot win.\n */\nexport const shellTopBarSecondaryButtonClass = cn(\n shellTopBarActionSize,\n shellTopBarRadius,\n \"!border-sidebar-border !bg-sidebar-accent !text-sidebar-foreground shadow-none transition-colors\",\n \"!py-0\",\n shellTopBarNeutralHover,\n shellTopBarNeutralActive,\n \"disabled:pointer-events-none disabled:!border-sidebar-border/60 disabled:!bg-sidebar-accent/60 disabled:!text-sidebar-foreground/40\",\n);\n\n/** Primary CTA in the shell top bar (New invoice, Add staff, etc.). */\nexport const shellTopBarPrimaryButtonClass = cn(\n shellTopBarActionSize,\n shellTopBarRadius,\n \"bg-blue-500 text-white transition-colors hover:bg-blue-600\",\n \"disabled:pointer-events-none disabled:opacity-50\",\n);\n\n/** Positive / payment emphasis in the shell top bar (e.g. Mark as paid). */\nexport const shellTopBarAccentButtonClass = cn(\n shellTopBarActionSize,\n shellTopBarRadius,\n \"bg-emerald-600 text-white transition-colors hover:bg-emerald-700\",\n);\n\n/** Positive status action in the shell top bar (e.g. Mark resolved). */\nexport const shellTopBarSuccessButtonClass = cn(\n shellTopBarActionSize,\n shellTopBarRadius,\n isDarkShell()\n ? \"border border-emerald-500/35 bg-emerald-500/15 text-emerald-300 transition-colors hover:border-emerald-400/45 hover:bg-emerald-500/25\"\n : \"border border-emerald-200 bg-emerald-50 text-emerald-700 transition-colors hover:border-emerald-300 hover:bg-emerald-100\",\n);\n\n/** Informative / reopen action in the shell top bar. */\nexport const shellTopBarInfoButtonClass = cn(\n shellTopBarActionSize,\n shellTopBarRadius,\n isDarkShell()\n ? \"border border-blue-500/35 bg-blue-500/15 text-blue-300 transition-colors hover:border-blue-400/45 hover:bg-blue-500/25\"\n : \"border border-blue-200 bg-blue-50 text-blue-700 transition-colors hover:border-blue-300 hover:bg-blue-100\",\n);\n\n/** Outline-style action — same neutral chrome as {@link shellTopBarSecondaryButtonClass}. */\nexport const shellTopBarOutlineButtonClass = shellTopBarSecondaryButtonClass;\n\n/** Wrapper for segmented toggles (2D / list, etc.) in the shell top bar. */\nexport const shellTopBarSegmentedShellClass = cn(\n \"flex items-center gap-0.5 border border-sidebar-border bg-sidebar-accent p-0.5\",\n shellTopBarRadius,\n);\n\nexport function shellTopBarSegmentedItemClass(active: boolean) {\n const dark = isDarkShell();\n return cn(\n shellTopBarActionSize,\n \"!h-6 px-2\",\n \"rounded-sm\",\n active\n ? dark\n ? \"bg-sidebar text-sidebar-foreground shadow-sm\"\n : \"bg-white text-sidebar-foreground shadow-sm\"\n : dark\n ? \"text-sidebar-foreground/60 hover:bg-sidebar-foreground/10 hover:text-sidebar-foreground\"\n : \"text-sidebar-foreground/60 hover:bg-sidebar-foreground/6 hover:text-sidebar-foreground\",\n );\n}\n\n/** Grouped field shell (month picker, etc.) in the top bar. */\nexport const shellTopBarControlGroupClass = cn(\n \"flex h-7 items-center gap-1.5 border border-sidebar-border bg-sidebar-accent pl-2.5 pr-1 text-sidebar-foreground\",\n shellTopBarRadius,\n);\n\nexport const shellTopBarControlLabelClass =\n \"m-0 shrink-0 text-[11px] font-normal text-sidebar-foreground/60\";\n\n/** Select trigger embedded in {@link shellTopBarControlGroupClass}. */\nexport const shellTopBarSelectTriggerClass =\n \"h-6 min-w-[140px] flex-1 border-0 bg-transparent px-1 text-xs text-sidebar-foreground shadow-none focus-visible:ring-0 focus-visible:ring-offset-0 [&_svg]:text-sidebar-foreground/60\";\n\n/** Square control for date steppers and similar compact actions. */\nexport const shellTopBarCompactIconButtonClass = cn(\n \"inline-flex !h-6 !w-6 items-center justify-center text-sidebar-foreground/70\",\n shellTopBarRadius,\n shellTopBarNeutralRest,\n shellTopBarNeutralHover,\n shellTopBarNeutralActive,\n \"[&_svg:not([class*='size-'])]:size-3.5\",\n);\n\n/** Center label in a date stepper (shows “Today” or a formatted date). */\nexport const shellTopBarDateLabelButtonClass = cn(\n shellTopBarActionSize,\n \"min-w-[72px]\",\n shellTopBarNeutralRest,\n shellTopBarNeutralHover,\n shellTopBarNeutralActive,\n);\n"]}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"shell-top-bar-chrome.js"}
@@ -1,9 +1,9 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as React from 'react';
2
2
  import { ReactNode } from 'react';
3
3
 
4
4
  declare function ShellTopBarProvider({ children }: {
5
5
  children: ReactNode;
6
- }): react_jsx_runtime.JSX.Element;
6
+ }): React.JSX.Element;
7
7
  /** Pages render a title and optional actions for the app shell top bar. */
8
8
  declare function ShellTopBar({ title, icon, actions, }: {
9
9
  title: ReactNode;
@@ -11,6 +11,6 @@ declare function ShellTopBar({ title, icon, actions, }: {
11
11
  actions?: ReactNode;
12
12
  }): null;
13
13
  /** Renders registered page title and actions inside AppWebShell topBar. */
14
- declare function ShellTopBarFrame(): react_jsx_runtime.JSX.Element;
14
+ declare function ShellTopBarFrame(): React.JSX.Element;
15
15
 
16
16
  export { ShellTopBar, ShellTopBarFrame, ShellTopBarProvider };
@@ -1,71 +1,3 @@
1
- import { createContext, useState, useEffect, useSyncExternalStore, useContext } from 'react';
2
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
-
4
- // src/shell/shell-top-bar.tsx
5
- var EMPTY_TOP_BAR_STATE = {};
6
- function createShellTopBarStore() {
7
- let state = EMPTY_TOP_BAR_STATE;
8
- const listeners = /* @__PURE__ */ new Set();
9
- return {
10
- getSnapshot: () => state,
11
- subscribe: (listener) => {
12
- listeners.add(listener);
13
- return () => listeners.delete(listener);
14
- },
15
- setState: (next) => {
16
- state = next;
17
- listeners.forEach((listener) => listener());
18
- }
19
- };
20
- }
21
- var ShellTopBarStoreContext = createContext(null);
22
- function ShellTopBarProvider({ children }) {
23
- const [store] = useState(createShellTopBarStore);
24
- return /* @__PURE__ */ jsx(ShellTopBarStoreContext.Provider, { value: store, children });
25
- }
26
- function useShellTopBarStore() {
27
- const store = useContext(ShellTopBarStoreContext);
28
- if (!store) {
29
- throw new Error("ShellTopBar components must be used within ShellTopBarProvider");
30
- }
31
- return store;
32
- }
33
- function ShellTopBar({
34
- title,
35
- icon,
36
- actions
37
- }) {
38
- const store = useShellTopBarStore();
39
- useEffect(() => {
40
- store.setState({ title, icon, actions });
41
- return () => store.setState(EMPTY_TOP_BAR_STATE);
42
- }, [title, icon, actions, store]);
43
- return null;
44
- }
45
- function ShellTopBarFrame() {
46
- const store = useShellTopBarStore();
47
- const state = useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);
48
- const { title, icon, actions } = state;
49
- if (title == null && actions == null) {
50
- return /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-center" });
51
- }
52
- const titleIsPlainText = typeof title === "string";
53
- return /* @__PURE__ */ jsxs(Fragment, { children: [
54
- /* @__PURE__ */ jsx("div", { className: "flex min-w-0 flex-1 items-center", children: title != null ? /* @__PURE__ */ jsx(
55
- "div",
56
- {
57
- "data-slot": "shell-top-bar-title",
58
- className: "flex min-w-0 flex-1 items-center gap-2 text-sidebar-foreground",
59
- children: titleIsPlainText ? /* @__PURE__ */ jsxs(Fragment, { children: [
60
- icon != null ? /* @__PURE__ */ jsx("span", { className: "flex shrink-0 items-center text-sidebar-foreground/60", children: icon }) : null,
61
- /* @__PURE__ */ jsx("h1", { className: "truncate text-sm font-normal", children: title })
62
- ] }) : title
63
- }
64
- ) : null }),
65
- actions != null ? /* @__PURE__ */ jsx("div", { "data-slot": "shell-top-bar-actions", className: "flex shrink-0 items-center gap-1.5", children: actions }) : null
66
- ] });
67
- }
68
-
69
- export { ShellTopBar, ShellTopBarFrame, ShellTopBarProvider };
1
+ export { ShellTopBar, ShellTopBarFrame, ShellTopBarProvider } from './chunk-4NNK5IXY.js';
70
2
  //# sourceMappingURL=shell-top-bar.js.map
71
3
  //# sourceMappingURL=shell-top-bar.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/shell/shell-top-bar.tsx"],"names":[],"mappings":"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","file":"shell-top-bar.js","sourcesContent":["import {\n createContext,\n useContext,\n useEffect,\n useState,\n useSyncExternalStore,\n type ReactNode,\n} from \"react\";\n\ntype ShellTopBarState = {\n title?: ReactNode;\n icon?: ReactNode;\n actions?: ReactNode;\n};\n\ntype ShellTopBarStore = {\n getSnapshot: () => ShellTopBarState;\n subscribe: (listener: () => void) => () => void;\n setState: (next: ShellTopBarState) => void;\n};\n\nconst EMPTY_TOP_BAR_STATE: ShellTopBarState = {};\n\nfunction createShellTopBarStore(): ShellTopBarStore {\n let state = EMPTY_TOP_BAR_STATE;\n const listeners = new Set<() => void>();\n\n return {\n getSnapshot: () => state,\n subscribe: (listener) => {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n setState: (next) => {\n state = next;\n listeners.forEach((listener) => listener());\n },\n };\n}\n\nconst ShellTopBarStoreContext = createContext<ShellTopBarStore | null>(null);\n\nexport function ShellTopBarProvider({ children }: { children: ReactNode }) {\n const [store] = useState(createShellTopBarStore);\n\n return (\n <ShellTopBarStoreContext.Provider value={store}>\n {children}\n </ShellTopBarStoreContext.Provider>\n );\n}\n\nfunction useShellTopBarStore() {\n const store = useContext(ShellTopBarStoreContext);\n if (!store) {\n throw new Error(\"ShellTopBar components must be used within ShellTopBarProvider\");\n }\n return store;\n}\n\n/** Pages render a title and optional actions for the app shell top bar. */\nexport function ShellTopBar({\n title,\n icon,\n actions,\n}: {\n title: ReactNode;\n icon?: ReactNode;\n actions?: ReactNode;\n}) {\n const store = useShellTopBarStore();\n\n useEffect(() => {\n store.setState({ title, icon, actions });\n return () => store.setState(EMPTY_TOP_BAR_STATE);\n }, [title, icon, actions, store]);\n\n return null;\n}\n\n/** Renders registered page title and actions inside AppWebShell topBar. */\nexport function ShellTopBarFrame() {\n const store = useShellTopBarStore();\n const state = useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);\n const { title, icon, actions } = state;\n\n if (title == null && actions == null) {\n return <div className=\"flex flex-1 items-center\" />;\n }\n\n const titleIsPlainText = typeof title === \"string\";\n\n return (\n <>\n <div className=\"flex min-w-0 flex-1 items-center\">\n {title != null ? (\n <div\n data-slot=\"shell-top-bar-title\"\n className=\"flex min-w-0 flex-1 items-center gap-2 text-sidebar-foreground\"\n >\n {titleIsPlainText ? (\n <>\n {icon != null ? (\n <span className=\"flex shrink-0 items-center text-sidebar-foreground/60\">{icon}</span>\n ) : null}\n <h1 className=\"truncate text-sm font-normal\">{title}</h1>\n </>\n ) : (\n title\n )}\n </div>\n ) : null}\n </div>\n {actions != null ? (\n <div data-slot=\"shell-top-bar-actions\" className=\"flex shrink-0 items-center gap-1.5\">\n {actions}\n </div>\n ) : null}\n </>\n );\n}\n"]}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"shell-top-bar.js"}
@@ -1,4 +1,4 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as React from 'react';
2
2
 
3
3
  /** Green pulse when online; gray dot + last-seen otherwise. Ticks so "3m ago" stays current. */
4
4
  declare function SupportPresenceStatus({ lastSeenAt, onlineLabel, neverSeenLabel, className, }: {
@@ -6,6 +6,6 @@ declare function SupportPresenceStatus({ lastSeenAt, onlineLabel, neverSeenLabel
6
6
  onlineLabel?: string;
7
7
  neverSeenLabel?: string;
8
8
  className?: string;
9
- }): react_jsx_runtime.JSX.Element;
9
+ }): React.JSX.Element;
10
10
 
11
11
  export { SupportPresenceStatus };
@@ -1,47 +1,9 @@
1
+ import { LiveSpacePulseDot } from './chunk-HCHASUB6.js';
2
+ import { formatRelativeTimeAgo } from './chunk-PBNBLCC2.js';
3
+ import { cn } from './chunk-DMPSQ22Q.js';
1
4
  import { useState, useEffect } from 'react';
2
- import { clsx } from 'clsx';
3
- import { twMerge } from 'tailwind-merge';
4
5
  import { jsxs, jsx } from 'react/jsx-runtime';
5
6
 
6
- // src/support/support-presence-status.tsx
7
-
8
- // src/lib/dateDisplay.ts
9
- var MS_MIN = 6e4;
10
- var MS_HOUR = 60 * MS_MIN;
11
- var MS_DAY = 24 * MS_HOUR;
12
- function formatRelativeTimeAgo(iso, now = /* @__PURE__ */ new Date()) {
13
- try {
14
- const d = new Date(iso.trim());
15
- if (!Number.isFinite(d.getTime())) return "";
16
- let diffMs = now.getTime() - d.getTime();
17
- if (diffMs < 0) diffMs = 0;
18
- const sec = Math.floor(diffMs / 1e3);
19
- if (sec < 60) return "just now";
20
- const min = Math.floor(diffMs / MS_MIN);
21
- if (min < 60) return `${min}m ago`;
22
- const hr = Math.floor(diffMs / MS_HOUR);
23
- if (hr < 24) return `${hr}h ago`;
24
- const day = Math.floor(diffMs / MS_DAY);
25
- if (day < 7) return `${day}d ago`;
26
- const week = Math.floor(day / 7);
27
- if (week < 5) return `${week}w ago`;
28
- const mo = Math.floor(day / 30);
29
- if (mo < 12) return `${mo}mo ago`;
30
- const yr = Math.floor(day / 365);
31
- return `${Math.max(1, yr)}y ago`;
32
- } catch {
33
- return "";
34
- }
35
- }
36
- function cn(...inputs) {
37
- return twMerge(clsx(inputs));
38
- }
39
- function LiveSpacePulseDot({ className }) {
40
- return /* @__PURE__ */ jsxs("span", { className: cn("relative flex h-2 w-2 shrink-0", className), "aria-hidden": "true", children: [
41
- /* @__PURE__ */ jsx("span", { className: "absolute inline-flex h-full w-full animate-ping rounded-full bg-emerald-400 opacity-40" }),
42
- /* @__PURE__ */ jsx("span", { className: "relative inline-flex h-2 w-2 rounded-full bg-emerald-500" })
43
- ] });
44
- }
45
7
  var SUPPORT_PRESENCE_ONLINE_MS = 45e3;
46
8
  function supportPresenceFromLastSeen(lastSeenAt, nowMs = Date.now()) {
47
9
  if (!lastSeenAt) return { lastSeenAt: null, online: false };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lib/dateDisplay.ts","../src/ui/utils.ts","../src/live-space/live-space-pulse-dot.tsx","../src/support/support-presence-status.tsx"],"names":["jsx","jsxs"],"mappings":";;;;;;;;AAsEA,IAAM,MAAA,GAAS,GAAA;AACf,IAAM,UAAU,EAAA,GAAK,MAAA;AACrB,IAAM,SAAS,EAAA,GAAK,OAAA;AAMb,SAAS,qBAAA,CAAsB,GAAA,EAAa,GAAA,mBAAY,IAAI,MAAK,EAAW;AACjF,EAAA,IAAI;AACF,IAAA,MAAM,CAAA,GAAI,IAAI,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA;AAC7B,IAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,EAAE,OAAA,EAAS,GAAG,OAAO,EAAA;AAC1C,IAAA,IAAI,MAAA,GAAS,GAAA,CAAI,OAAA,EAAQ,GAAI,EAAE,OAAA,EAAQ;AACvC,IAAA,IAAI,MAAA,GAAS,GAAG,MAAA,GAAS,CAAA;AACzB,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,MAAA,GAAS,GAAI,CAAA;AACpC,IAAA,IAAI,GAAA,GAAM,IAAI,OAAO,UAAA;AACrB,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,MAAA,GAAS,MAAM,CAAA;AACtC,IAAA,IAAI,GAAA,GAAM,EAAA,EAAI,OAAO,CAAA,EAAG,GAAG,CAAA,KAAA,CAAA;AAC3B,IAAA,MAAM,EAAA,GAAK,IAAA,CAAK,KAAA,CAAM,MAAA,GAAS,OAAO,CAAA;AACtC,IAAA,IAAI,EAAA,GAAK,EAAA,EAAI,OAAO,CAAA,EAAG,EAAE,CAAA,KAAA,CAAA;AACzB,IAAA,MAAM,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,MAAA,GAAS,MAAM,CAAA;AACtC,IAAA,IAAI,GAAA,GAAM,CAAA,EAAG,OAAO,CAAA,EAAG,GAAG,CAAA,KAAA,CAAA;AAC1B,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,GAAA,GAAM,CAAC,CAAA;AAC/B,IAAA,IAAI,IAAA,GAAO,CAAA,EAAG,OAAO,CAAA,EAAG,IAAI,CAAA,KAAA,CAAA;AAC5B,IAAA,MAAM,EAAA,GAAK,IAAA,CAAK,KAAA,CAAM,GAAA,GAAM,EAAE,CAAA;AAC9B,IAAA,IAAI,EAAA,GAAK,EAAA,EAAI,OAAO,CAAA,EAAG,EAAE,CAAA,MAAA,CAAA;AACzB,IAAA,MAAM,EAAA,GAAK,IAAA,CAAK,KAAA,CAAM,GAAA,GAAM,GAAG,CAAA;AAC/B,IAAA,OAAO,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,EAAE,CAAC,CAAA,KAAA,CAAA;AAAA,EAC3B,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,EAAA;AAAA,EACT;AACF;AClGO,SAAS,MAAM,MAAA,EAAsB;AAC1C,EAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC7B;ACFO,SAAS,iBAAA,CAAkB,EAAE,SAAA,EAAU,EAA2B;AACvE,EAAA,uBACE,IAAA,CAAC,UAAK,SAAA,EAAW,EAAA,CAAG,kCAAkC,SAAS,CAAA,EAAG,eAAY,MAAA,EAC5E,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,WAAU,wFAAA,EAAyF,CAAA;AAAA,oBACzG,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,0DAAA,EAA2D;AAAA,GAAA,EAC7E,CAAA;AAEJ;ACLA,IAAM,0BAAA,GAA6B,IAAA;AAEnC,SAAS,2BAAA,CACP,UAAA,EACA,KAAA,GAAQ,IAAA,CAAK,KAAI,EAC+B;AAChD,EAAA,IAAI,CAAC,UAAA,EAAY,OAAO,EAAE,UAAA,EAAY,IAAA,EAAM,QAAQ,KAAA,EAAM;AAC1D,EAAA,MAAM,EAAA,GAAK,IAAI,IAAA,CAAK,UAAU,EAAE,OAAA,EAAQ;AACxC,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,EAAE,CAAA,SAAU,EAAE,UAAA,EAAY,IAAA,EAAM,MAAA,EAAQ,KAAA,EAAM;AACnE,EAAA,OAAO;AAAA,IACL,UAAA;AAAA,IACA,MAAA,EAAQ,QAAQ,EAAA,GAAK;AAAA,GACvB;AACF;AAEA,SAAS,0BAAA,CACP,UACA,IAAA,EACQ;AACR,EAAA,IAAI,QAAA,CAAS,MAAA,EAAQ,OAAO,IAAA,CAAK,WAAA;AACjC,EAAA,IAAI,CAAC,QAAA,CAAS,UAAA,EAAY,OAAO,IAAA,CAAK,cAAA;AACtC,EAAA,MAAM,GAAA,GAAM,qBAAA,CAAsB,QAAA,CAAS,UAAU,CAAA;AACrD,EAAA,IAAI,CAAC,GAAA,EAAK,OAAO,IAAA,CAAK,cAAA;AACtB,EAAA,OAAO,GAAA,KAAQ,UAAA,GAAa,oBAAA,GAAuB,CAAA,UAAA,EAAa,GAAG,CAAA,CAAA;AACrE;AAEA,SAAS,UAAA,CAAW,EAAE,SAAA,EAAU,EAA2B;AACzD,EAAA,uBACEA,GAAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,EAAA,CAAG,kEAAA,EAAoE,SAAS,CAAA;AAAA,MAC3F,aAAA,EAAY;AAAA;AAAA,GACd;AAEJ;AAGO,SAAS,qBAAA,CAAsB;AAAA,EACpC,UAAA;AAAA,EACA,WAAA,GAAc,QAAA;AAAA,EACd,cAAA,GAAiB,SAAA;AAAA,EACjB;AACF,CAAA,EAKG;AACD,EAAA,MAAM,GAAG,OAAO,CAAA,GAAI,SAAS,CAAC,CAAA;AAE9B,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,EAAA,GAAK,MAAA,CAAO,WAAA,CAAY,MAAM,OAAA,CAAQ,CAAC,CAAA,KAAM,CAAA,GAAI,CAAC,CAAA,EAAG,IAAM,CAAA;AACjE,IAAA,OAAO,MAAM,MAAA,CAAO,aAAA,CAAc,EAAE,CAAA;AAAA,EACtC,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,QAAA,GAAW,4BAA4B,UAAU,CAAA;AACvD,EAAA,MAAM,QAAQ,0BAAA,CAA2B,QAAA,EAAU,EAAE,WAAA,EAAa,gBAAgB,CAAA;AAElF,EAAA,uBACEC,IAAAA,CAAC,MAAA,EAAA,EAAK,WAAW,EAAA,CAAG,0CAAA,EAA4C,SAAS,CAAA,EACtE,QAAA,EAAA;AAAA,IAAA,QAAA,CAAS,yBAASD,GAAAA,CAAC,qBAAkB,CAAA,mBAAKA,IAAC,UAAA,EAAA,EAAW,CAAA;AAAA,oBACvDA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,YAAY,QAAA,EAAA,KAAA,EAAM;AAAA,GAAA,EACpC,CAAA;AAEJ","file":"support-presence-status.js","sourcesContent":["/** Parse `HH:mm` wall-clock time. */\nexport function parseWallClockHm(value: string): { h: number; m: number } | undefined {\n const m = /^([01]\\d|2[0-3]):([0-5]\\d)$/.exec(value.trim());\n if (!m) return undefined;\n const h = Number(m[1]);\n const min = Number(m[2]);\n if (h > 23 || min > 59) return undefined;\n return { h, m: min };\n}\n\nexport function toWallClockHmStr(h: number, m: number): string {\n return `${String(h).padStart(2, \"0\")}:${String(m).padStart(2, \"0\")}`;\n}\n\n/** Format stored `HH:mm` without timezone conversion. */\nexport function formatWallClockTime(value: string, timeFormat: \"12h\" | \"24h\"): string {\n const p = parseWallClockHm(value);\n if (!p) return value.trim() || \"—\";\n if (timeFormat === \"24h\") return toWallClockHmStr(p.h, p.m);\n const ap = p.h >= 12 ? \"PM\" : \"AM\";\n const h12 = p.h % 12 || 12;\n return `${h12}:${String(p.m).padStart(2, \"0\")} ${ap}`;\n}\n\n/** Add minutes to a wall-clock `HH:mm`, wrapping at 24h. */\nexport function addWallClockMinutes(value: string, minutes: number): string {\n const p = parseWallClockHm(value);\n if (!p) return value;\n const total = p.h * 60 + p.m + minutes;\n const wrapped = ((total % (24 * 60)) + 24 * 60) % (24 * 60);\n return toWallClockHmStr(Math.floor(wrapped / 60), wrapped % 60);\n}\n\n/** Format `YYYY-MM-DD` as a calendar date (no timezone shift). */\nexport function formatCalendarDate(ymd: string): string {\n if (!ymd || !/^\\d{4}-\\d{2}-\\d{2}$/.test(ymd)) return ymd || \"—\";\n const [y, m, d] = ymd.split(\"-\").map(Number);\n return new Date(y, m - 1, d).toLocaleDateString(\"en-US\", {\n month: \"short\",\n day: \"numeric\",\n year: \"numeric\",\n });\n}\n\n/** ISO `yyyy-mm-dd` for a local calendar date. */\nexport function toDateStr(date: Date): string {\n const y = date.getFullYear();\n const m = String(date.getMonth() + 1).padStart(2, \"0\");\n const d = String(date.getDate()).padStart(2, \"0\");\n return `${y}-${m}-${d}`;\n}\n\nexport function isSameDay(a: Date, b: Date): boolean {\n return (\n a.getFullYear() === b.getFullYear() &&\n a.getMonth() === b.getMonth() &&\n a.getDate() === b.getDate()\n );\n}\n\n/** Short label for a date; shows \"Today\" when it matches the current local day. */\nexport function formatDate(date: Date): string {\n if (isSameDay(date, new Date())) return \"Today\";\n return date.toLocaleDateString(\"en-US\", {\n weekday: \"short\",\n month: \"short\",\n day: \"numeric\",\n });\n}\n\nconst MS_MIN = 60_000;\nconst MS_HOUR = 60 * MS_MIN;\nconst MS_DAY = 24 * MS_HOUR;\n\n/**\n * Compact relative time for feeds (e.g. announcements, notifications): `2m ago`, `2d ago`.\n * Uses elapsed wall time from `now` (defaults to current time). Returns \"\" if `iso` is unparseable.\n */\nexport function formatRelativeTimeAgo(iso: string, now: Date = new Date()): string {\n try {\n const d = new Date(iso.trim());\n if (!Number.isFinite(d.getTime())) return \"\";\n let diffMs = now.getTime() - d.getTime();\n if (diffMs < 0) diffMs = 0;\n const sec = Math.floor(diffMs / 1000);\n if (sec < 60) return \"just now\";\n const min = Math.floor(diffMs / MS_MIN);\n if (min < 60) return `${min}m ago`;\n const hr = Math.floor(diffMs / MS_HOUR);\n if (hr < 24) return `${hr}h ago`;\n const day = Math.floor(diffMs / MS_DAY);\n if (day < 7) return `${day}d ago`;\n const week = Math.floor(day / 7);\n if (week < 5) return `${week}w ago`;\n const mo = Math.floor(day / 30);\n if (mo < 12) return `${mo}mo ago`;\n const yr = Math.floor(day / 365);\n return `${Math.max(1, yr)}y ago`;\n } catch {\n return \"\";\n }\n}\n","import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import { cn } from \"../ui/utils\";\n\n/** Ping + solid emerald marker used on Live space page title and sidebar nav. */\nexport function LiveSpacePulseDot({ className }: { className?: string }) {\n return (\n <span className={cn(\"relative flex h-2 w-2 shrink-0\", className)} aria-hidden=\"true\">\n <span className=\"absolute inline-flex h-full w-full animate-ping rounded-full bg-emerald-400 opacity-40\" />\n <span className=\"relative inline-flex h-2 w-2 rounded-full bg-emerald-500\" />\n </span>\n );\n}\n","import { useEffect, useState } from \"react\";\nimport { formatRelativeTimeAgo } from \"../lib/dateDisplay\";\nimport { LiveSpacePulseDot } from \"../live-space/live-space-pulse-dot\";\nimport { cn } from \"../ui/utils\";\n\nconst SUPPORT_PRESENCE_ONLINE_MS = 45_000;\n\nfunction supportPresenceFromLastSeen(\n lastSeenAt: string | null | undefined,\n nowMs = Date.now(),\n): { lastSeenAt: string | null; online: boolean } {\n if (!lastSeenAt) return { lastSeenAt: null, online: false };\n const ts = new Date(lastSeenAt).getTime();\n if (!Number.isFinite(ts)) return { lastSeenAt: null, online: false };\n return {\n lastSeenAt,\n online: nowMs - ts < SUPPORT_PRESENCE_ONLINE_MS,\n };\n}\n\nfunction formatSupportPresenceLabel(\n snapshot: { online: boolean; lastSeenAt: string | null },\n opts: { onlineLabel: string; neverSeenLabel: string },\n): string {\n if (snapshot.online) return opts.onlineLabel;\n if (!snapshot.lastSeenAt) return opts.neverSeenLabel;\n const ago = formatRelativeTimeAgo(snapshot.lastSeenAt);\n if (!ago) return opts.neverSeenLabel;\n return ago === \"just now\" ? \"Last seen just now\" : `Last seen ${ago}`;\n}\n\nfunction OfflineDot({ className }: { className?: string }) {\n return (\n <span\n className={cn(\"inline-flex h-2 w-2 shrink-0 rounded-full bg-muted-foreground/45\", className)}\n aria-hidden=\"true\"\n />\n );\n}\n\n/** Green pulse when online; gray dot + last-seen otherwise. Ticks so \"3m ago\" stays current. */\nexport function SupportPresenceStatus({\n lastSeenAt,\n onlineLabel = \"Online\",\n neverSeenLabel = \"Offline\",\n className,\n}: {\n lastSeenAt: string | null;\n onlineLabel?: string;\n neverSeenLabel?: string;\n className?: string;\n}) {\n const [, setTick] = useState(0);\n\n useEffect(() => {\n const id = window.setInterval(() => setTick((n) => n + 1), 15_000);\n return () => window.clearInterval(id);\n }, []);\n\n const snapshot = supportPresenceFromLastSeen(lastSeenAt);\n const label = formatSupportPresenceLabel(snapshot, { onlineLabel, neverSeenLabel });\n\n return (\n <span className={cn(\"inline-flex min-w-0 items-center gap-1.5\", className)}>\n {snapshot.online ? <LiveSpacePulseDot /> : <OfflineDot />}\n <span className=\"truncate\">{label}</span>\n </span>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/support/support-presence-status.tsx"],"names":[],"mappings":";;;;;;AAKA,IAAM,0BAAA,GAA6B,IAAA;AAEnC,SAAS,2BAAA,CACP,UAAA,EACA,KAAA,GAAQ,IAAA,CAAK,KAAI,EAC+B;AAChD,EAAA,IAAI,CAAC,UAAA,EAAY,OAAO,EAAE,UAAA,EAAY,IAAA,EAAM,QAAQ,KAAA,EAAM;AAC1D,EAAA,MAAM,EAAA,GAAK,IAAI,IAAA,CAAK,UAAU,EAAE,OAAA,EAAQ;AACxC,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,EAAE,CAAA,SAAU,EAAE,UAAA,EAAY,IAAA,EAAM,MAAA,EAAQ,KAAA,EAAM;AACnE,EAAA,OAAO;AAAA,IACL,UAAA;AAAA,IACA,MAAA,EAAQ,QAAQ,EAAA,GAAK;AAAA,GACvB;AACF;AAEA,SAAS,0BAAA,CACP,UACA,IAAA,EACQ;AACR,EAAA,IAAI,QAAA,CAAS,MAAA,EAAQ,OAAO,IAAA,CAAK,WAAA;AACjC,EAAA,IAAI,CAAC,QAAA,CAAS,UAAA,EAAY,OAAO,IAAA,CAAK,cAAA;AACtC,EAAA,MAAM,GAAA,GAAM,qBAAA,CAAsB,QAAA,CAAS,UAAU,CAAA;AACrD,EAAA,IAAI,CAAC,GAAA,EAAK,OAAO,IAAA,CAAK,cAAA;AACtB,EAAA,OAAO,GAAA,KAAQ,UAAA,GAAa,oBAAA,GAAuB,CAAA,UAAA,EAAa,GAAG,CAAA,CAAA;AACrE;AAEA,SAAS,UAAA,CAAW,EAAE,SAAA,EAAU,EAA2B;AACzD,EAAA,uBACE,GAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,EAAA,CAAG,kEAAA,EAAoE,SAAS,CAAA;AAAA,MAC3F,aAAA,EAAY;AAAA;AAAA,GACd;AAEJ;AAGO,SAAS,qBAAA,CAAsB;AAAA,EACpC,UAAA;AAAA,EACA,WAAA,GAAc,QAAA;AAAA,EACd,cAAA,GAAiB,SAAA;AAAA,EACjB;AACF,CAAA,EAKG;AACD,EAAA,MAAM,GAAG,OAAO,CAAA,GAAI,SAAS,CAAC,CAAA;AAE9B,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,EAAA,GAAK,MAAA,CAAO,WAAA,CAAY,MAAM,OAAA,CAAQ,CAAC,CAAA,KAAM,CAAA,GAAI,CAAC,CAAA,EAAG,IAAM,CAAA;AACjE,IAAA,OAAO,MAAM,MAAA,CAAO,aAAA,CAAc,EAAE,CAAA;AAAA,EACtC,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,QAAA,GAAW,4BAA4B,UAAU,CAAA;AACvD,EAAA,MAAM,QAAQ,0BAAA,CAA2B,QAAA,EAAU,EAAE,WAAA,EAAa,gBAAgB,CAAA;AAElF,EAAA,4BACG,MAAA,EAAA,EAAK,SAAA,EAAW,EAAA,CAAG,0CAAA,EAA4C,SAAS,CAAA,EACtE,QAAA,EAAA;AAAA,IAAA,QAAA,CAAS,MAAA,mBAAS,GAAA,CAAC,iBAAA,EAAA,EAAkB,CAAA,uBAAM,UAAA,EAAA,EAAW,CAAA;AAAA,oBACvD,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,UAAA,EAAY,QAAA,EAAA,KAAA,EAAM;AAAA,GAAA,EACpC,CAAA;AAEJ","file":"support-presence-status.js","sourcesContent":["import { useEffect, useState } from \"react\";\nimport { formatRelativeTimeAgo } from \"../lib/dateDisplay\";\nimport { LiveSpacePulseDot } from \"../live-space/live-space-pulse-dot\";\nimport { cn } from \"../ui/utils\";\n\nconst SUPPORT_PRESENCE_ONLINE_MS = 45_000;\n\nfunction supportPresenceFromLastSeen(\n lastSeenAt: string | null | undefined,\n nowMs = Date.now(),\n): { lastSeenAt: string | null; online: boolean } {\n if (!lastSeenAt) return { lastSeenAt: null, online: false };\n const ts = new Date(lastSeenAt).getTime();\n if (!Number.isFinite(ts)) return { lastSeenAt: null, online: false };\n return {\n lastSeenAt,\n online: nowMs - ts < SUPPORT_PRESENCE_ONLINE_MS,\n };\n}\n\nfunction formatSupportPresenceLabel(\n snapshot: { online: boolean; lastSeenAt: string | null },\n opts: { onlineLabel: string; neverSeenLabel: string },\n): string {\n if (snapshot.online) return opts.onlineLabel;\n if (!snapshot.lastSeenAt) return opts.neverSeenLabel;\n const ago = formatRelativeTimeAgo(snapshot.lastSeenAt);\n if (!ago) return opts.neverSeenLabel;\n return ago === \"just now\" ? \"Last seen just now\" : `Last seen ${ago}`;\n}\n\nfunction OfflineDot({ className }: { className?: string }) {\n return (\n <span\n className={cn(\"inline-flex h-2 w-2 shrink-0 rounded-full bg-muted-foreground/45\", className)}\n aria-hidden=\"true\"\n />\n );\n}\n\n/** Green pulse when online; gray dot + last-seen otherwise. Ticks so \"3m ago\" stays current. */\nexport function SupportPresenceStatus({\n lastSeenAt,\n onlineLabel = \"Online\",\n neverSeenLabel = \"Offline\",\n className,\n}: {\n lastSeenAt: string | null;\n onlineLabel?: string;\n neverSeenLabel?: string;\n className?: string;\n}) {\n const [, setTick] = useState(0);\n\n useEffect(() => {\n const id = window.setInterval(() => setTick((n) => n + 1), 15_000);\n return () => window.clearInterval(id);\n }, []);\n\n const snapshot = supportPresenceFromLastSeen(lastSeenAt);\n const label = formatSupportPresenceLabel(snapshot, { onlineLabel, neverSeenLabel });\n\n return (\n <span className={cn(\"inline-flex min-w-0 items-center gap-1.5\", className)}>\n {snapshot.online ? <LiveSpacePulseDot /> : <OfflineDot />}\n <span className=\"truncate\">{label}</span>\n </span>\n );\n}\n"]}
@@ -1,5 +1,5 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as React from 'react';
2
2
 
3
- declare function ThemeAppearanceControl(): react_jsx_runtime.JSX.Element;
3
+ declare function ThemeAppearanceControl(): React.JSX.Element;
4
4
 
5
5
  export { ThemeAppearanceControl };
@@ -1,69 +1,10 @@
1
+ import { useTheme } from './chunk-XU3EFSQX.js';
2
+ import './chunk-4Y5DBM6Z.js';
3
+ import { Label, RadioGroup, RadioGroupItem } from './chunk-RV5PMZYZ.js';
4
+ import './chunk-DMPSQ22Q.js';
1
5
  import { Monitor, Sun, Moon } from 'lucide-react';
2
- import * as LabelPrimitive from '@radix-ui/react-label';
3
- import { clsx } from 'clsx';
4
- import { twMerge } from 'tailwind-merge';
5
6
  import { jsxs, jsx } from 'react/jsx-runtime';
6
- import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
7
- import { useTheme } from 'next-themes';
8
7
 
9
- // src/theme/theme-appearance-control.tsx
10
- function cn(...inputs) {
11
- return twMerge(clsx(inputs));
12
- }
13
- function Label({ className, ...props }) {
14
- return /* @__PURE__ */ jsx(
15
- LabelPrimitive.Root,
16
- {
17
- "data-slot": "label",
18
- className: cn(
19
- "flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
20
- className
21
- ),
22
- ...props
23
- }
24
- );
25
- }
26
- function RadioGroup({
27
- className,
28
- ...props
29
- }) {
30
- return /* @__PURE__ */ jsx(
31
- RadioGroupPrimitive.Root,
32
- {
33
- "data-slot": "radio-group",
34
- className: cn("grid gap-3", className),
35
- ...props
36
- }
37
- );
38
- }
39
- function RadioGroupItem({
40
- className,
41
- ...props
42
- }) {
43
- return /* @__PURE__ */ jsx(
44
- RadioGroupPrimitive.Item,
45
- {
46
- "data-slot": "radio-group-item",
47
- className: cn(
48
- "flex size-[18px] shrink-0 items-center justify-center rounded-full border border-border bg-card shadow-sm outline-none transition-[border-color,box-shadow]",
49
- "focus-visible:border-blue-500 focus-visible:ring-[3px] focus-visible:ring-blue-500/25",
50
- "aria-invalid:border-red-400 aria-invalid:ring-red-500/20",
51
- "disabled:cursor-not-allowed disabled:opacity-50",
52
- "data-[state=checked]:border-blue-600",
53
- className
54
- ),
55
- ...props,
56
- children: /* @__PURE__ */ jsx(
57
- RadioGroupPrimitive.Indicator,
58
- {
59
- "data-slot": "radio-group-indicator",
60
- className: "flex items-center justify-center",
61
- children: /* @__PURE__ */ jsx("span", { className: "size-2.5 rounded-full bg-blue-600" })
62
- }
63
- )
64
- }
65
- );
66
- }
67
8
  var OPTIONS = [
68
9
  {
69
10
  value: "system",
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ui/utils.ts","../src/ui/label.tsx","../src/ui/radio-group.tsx","../src/theme/theme-appearance-control.tsx"],"names":["jsx"],"mappings":"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","file":"theme-appearance-control.js","sourcesContent":["import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","\"use client\";\n\nimport * as React from \"react\";\nimport * as LabelPrimitive from \"@radix-ui/react-label\";\n\nimport { cn } from \"./utils\";\n\nfunction Label({ className, ...props }: React.ComponentProps<typeof LabelPrimitive.Root>) {\n return (\n <LabelPrimitive.Root\n data-slot=\"label\"\n className={cn(\n \"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50\",\n className,\n )}\n {...props}\n />\n );\n}\n\nexport { Label };\n","\"use client\";\n\nimport * as React from \"react\";\nimport * as RadioGroupPrimitive from \"@radix-ui/react-radio-group\";\n\nimport { cn } from \"./utils\";\n\nfunction RadioGroup({\n className,\n ...props\n}: React.ComponentProps<typeof RadioGroupPrimitive.Root>) {\n return (\n <RadioGroupPrimitive.Root\n data-slot=\"radio-group\"\n className={cn(\"grid gap-3\", className)}\n {...props}\n />\n );\n}\n\nfunction RadioGroupItem({\n className,\n ...props\n}: React.ComponentProps<typeof RadioGroupPrimitive.Item>) {\n return (\n <RadioGroupPrimitive.Item\n data-slot=\"radio-group-item\"\n className={cn(\n \"flex size-[18px] shrink-0 items-center justify-center rounded-full border border-border bg-card shadow-sm outline-none transition-[border-color,box-shadow]\",\n \"focus-visible:border-blue-500 focus-visible:ring-[3px] focus-visible:ring-blue-500/25\",\n \"aria-invalid:border-red-400 aria-invalid:ring-red-500/20\",\n \"disabled:cursor-not-allowed disabled:opacity-50\",\n \"data-[state=checked]:border-blue-600\",\n className,\n )}\n {...props}\n >\n <RadioGroupPrimitive.Indicator\n data-slot=\"radio-group-indicator\"\n className=\"flex items-center justify-center\"\n >\n <span className=\"size-2.5 rounded-full bg-blue-600\" />\n </RadioGroupPrimitive.Indicator>\n </RadioGroupPrimitive.Item>\n );\n}\n\nexport { RadioGroup, RadioGroupItem };\n","import { Monitor, Moon, Sun } from \"lucide-react\";\nimport { Label } from \"../ui/label\";\nimport { RadioGroup, RadioGroupItem } from \"../ui/radio-group\";\nimport { useTheme } from \"./theme-provider\";\nimport type { WebThemeMode } from \"./constants\";\n\nconst OPTIONS: ReadonlyArray<{\n value: WebThemeMode;\n label: string;\n description: string;\n icon: typeof Sun;\n}> = [\n {\n value: \"system\",\n label: \"System\",\n description: \"Follow your device appearance\",\n icon: Monitor,\n },\n { value: \"light\", label: \"Light (default)\", description: \"Always use light mode\", icon: Sun },\n { value: \"dark\", label: \"Dark\", description: \"Always use dark mode\", icon: Moon },\n];\n\nexport function ThemeAppearanceControl() {\n const { theme, setTheme } = useTheme();\n const value = (theme ?? \"light\") as WebThemeMode;\n\n return (\n <div className=\"space-y-3\">\n <Label className=\"text-sm font-medium text-foreground\">Appearance</Label>\n <RadioGroup\n value={value}\n onValueChange={(next) => setTheme(next as WebThemeMode)}\n className=\"flex flex-col gap-2\"\n >\n {OPTIONS.map((opt) => {\n const Icon = opt.icon;\n return (\n <label\n key={opt.value}\n htmlFor={`theme-${opt.value}`}\n className=\"flex cursor-pointer items-start gap-3 rounded-lg border border-border bg-card px-3 py-2.5 transition-colors has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-ring/50 hover:bg-accent/50\"\n >\n <RadioGroupItem id={`theme-${opt.value}`} value={opt.value} className=\"mt-0.5\" />\n <Icon size={16} className=\"mt-0.5 shrink-0 text-muted-foreground\" strokeWidth={1.75} />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block text-sm font-medium text-foreground\">{opt.label}</span>\n <span className=\"block text-xs text-muted-foreground\">{opt.description}</span>\n </span>\n </label>\n );\n })}\n </RadioGroup>\n </div>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/theme/theme-appearance-control.tsx"],"names":[],"mappings":";;;;;;;AAMA,IAAM,OAAA,GAKD;AAAA,EACH;AAAA,IACE,KAAA,EAAO,QAAA;AAAA,IACP,KAAA,EAAO,QAAA;AAAA,IACP,WAAA,EAAa,+BAAA;AAAA,IACb,IAAA,EAAM;AAAA,GACR;AAAA,EACA,EAAE,OAAO,OAAA,EAAS,KAAA,EAAO,mBAAmB,WAAA,EAAa,uBAAA,EAAyB,MAAM,GAAA,EAAI;AAAA,EAC5F,EAAE,OAAO,MAAA,EAAQ,KAAA,EAAO,QAAQ,WAAA,EAAa,sBAAA,EAAwB,MAAM,IAAA;AAC7E,CAAA;AAEO,SAAS,sBAAA,GAAyB;AACvC,EAAA,MAAM,EAAE,KAAA,EAAO,QAAA,EAAS,GAAI,QAAA,EAAS;AACrC,EAAA,MAAM,QAAS,KAAA,IAAS,OAAA;AAExB,EAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,WAAA,EACb,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,KAAA,EAAA,EAAM,SAAA,EAAU,qCAAA,EAAsC,QAAA,EAAA,YAAA,EAAU,CAAA;AAAA,oBACjE,GAAA;AAAA,MAAC,UAAA;AAAA,MAAA;AAAA,QACC,KAAA;AAAA,QACA,aAAA,EAAe,CAAC,IAAA,KAAS,QAAA,CAAS,IAAoB,CAAA;AAAA,QACtD,SAAA,EAAU,qBAAA;AAAA,QAET,QAAA,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAC,GAAA,KAAQ;AACpB,UAAA,MAAM,OAAO,GAAA,CAAI,IAAA;AACjB,UAAA,uBACE,IAAA;AAAA,YAAC,OAAA;AAAA,YAAA;AAAA,cAEC,OAAA,EAAS,CAAA,MAAA,EAAS,GAAA,CAAI,KAAK,CAAA,CAAA;AAAA,cAC3B,SAAA,EAAU,8LAAA;AAAA,cAEV,QAAA,EAAA;AAAA,gCAAA,GAAA,CAAC,cAAA,EAAA,EAAe,EAAA,EAAI,CAAA,MAAA,EAAS,GAAA,CAAI,KAAK,IAAI,KAAA,EAAO,GAAA,CAAI,KAAA,EAAO,SAAA,EAAU,QAAA,EAAS,CAAA;AAAA,oCAC9E,IAAA,EAAA,EAAK,IAAA,EAAM,IAAI,SAAA,EAAU,uCAAA,EAAwC,aAAa,IAAA,EAAM,CAAA;AAAA,gCACrF,IAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,gBAAA,EACd,QAAA,EAAA;AAAA,kCAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,2CAAA,EAA6C,QAAA,EAAA,GAAA,CAAI,KAAA,EAAM,CAAA;AAAA,kCACvE,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,qCAAA,EAAuC,cAAI,WAAA,EAAY;AAAA,iBAAA,EACzE;AAAA;AAAA,aAAA;AAAA,YATK,GAAA,CAAI;AAAA,WAUX;AAAA,QAEJ,CAAC;AAAA;AAAA;AACH,GAAA,EACF,CAAA;AAEJ","file":"theme-appearance-control.js","sourcesContent":["import { Monitor, Moon, Sun } from \"lucide-react\";\nimport { Label } from \"../ui/label\";\nimport { RadioGroup, RadioGroupItem } from \"../ui/radio-group\";\nimport { useTheme } from \"./theme-provider\";\nimport type { WebThemeMode } from \"./constants\";\n\nconst OPTIONS: ReadonlyArray<{\n value: WebThemeMode;\n label: string;\n description: string;\n icon: typeof Sun;\n}> = [\n {\n value: \"system\",\n label: \"System\",\n description: \"Follow your device appearance\",\n icon: Monitor,\n },\n { value: \"light\", label: \"Light (default)\", description: \"Always use light mode\", icon: Sun },\n { value: \"dark\", label: \"Dark\", description: \"Always use dark mode\", icon: Moon },\n];\n\nexport function ThemeAppearanceControl() {\n const { theme, setTheme } = useTheme();\n const value = (theme ?? \"light\") as WebThemeMode;\n\n return (\n <div className=\"space-y-3\">\n <Label className=\"text-sm font-medium text-foreground\">Appearance</Label>\n <RadioGroup\n value={value}\n onValueChange={(next) => setTheme(next as WebThemeMode)}\n className=\"flex flex-col gap-2\"\n >\n {OPTIONS.map((opt) => {\n const Icon = opt.icon;\n return (\n <label\n key={opt.value}\n htmlFor={`theme-${opt.value}`}\n className=\"flex cursor-pointer items-start gap-3 rounded-lg border border-border bg-card px-3 py-2.5 transition-colors has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-ring/50 hover:bg-accent/50\"\n >\n <RadioGroupItem id={`theme-${opt.value}`} value={opt.value} className=\"mt-0.5\" />\n <Icon size={16} className=\"mt-0.5 shrink-0 text-muted-foreground\" strokeWidth={1.75} />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block text-sm font-medium text-foreground\">{opt.label}</span>\n <span className=\"block text-xs text-muted-foreground\">{opt.description}</span>\n </span>\n </label>\n );\n })}\n </RadioGroup>\n </div>\n );\n}\n"]}
@@ -1,5 +1,4 @@
1
- // src/theme/constants.ts
2
- var WEB_THEME_STORAGE_KEY = "coworking.web.theme";
1
+ import { WEB_THEME_STORAGE_KEY } from './chunk-4Y5DBM6Z.js';
3
2
 
4
3
  // src/theme/theme-boot-script.ts
5
4
  var THEME_BOOT_SCRIPT = `(function(){try{var k=${JSON.stringify(WEB_THEME_STORAGE_KEY)};var t=localStorage.getItem(k)||"light";var d=t==="dark"||(t==="system"&&window.matchMedia("(prefers-color-scheme: dark)").matches);document.documentElement.classList.toggle("dark",d);}catch(e){}})();`;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/theme/constants.ts","../src/theme/theme-boot-script.ts"],"names":[],"mappings":";AACO,IAAM,qBAAA,GAAwB,qBAAA;;;ACE9B,IAAM,iBAAA,GAAoB,CAAA,sBAAA,EAAyB,IAAA,CAAK,SAAA,CAAU,qBAAqB,CAAC,CAAA,wMAAA","file":"theme-boot-script.js","sourcesContent":["/** localStorage key used by next-themes and the index.html boot script */\nexport const WEB_THEME_STORAGE_KEY = \"coworking.web.theme\";\n\nexport type WebThemeMode = \"system\" | \"light\" | \"dark\";\n","import { WEB_THEME_STORAGE_KEY } from \"./constants\";\n\n/** Inline script for index.html — prevents light flash before React hydrates */\nexport const THEME_BOOT_SCRIPT = `(function(){try{var k=${JSON.stringify(WEB_THEME_STORAGE_KEY)};var t=localStorage.getItem(k)||\"light\";var d=t===\"dark\"||(t===\"system\"&&window.matchMedia(\"(prefers-color-scheme: dark)\").matches);document.documentElement.classList.toggle(\"dark\",d);}catch(e){}})();`;\n"]}
1
+ {"version":3,"sources":["../src/theme/theme-boot-script.ts"],"names":[],"mappings":";;;AAGO,IAAM,iBAAA,GAAoB,CAAA,sBAAA,EAAyB,IAAA,CAAK,SAAA,CAAU,qBAAqB,CAAC,CAAA,wMAAA","file":"theme-boot-script.js","sourcesContent":["import { WEB_THEME_STORAGE_KEY } from \"./constants\";\n\n/** Inline script for index.html — prevents light flash before React hydrates */\nexport const THEME_BOOT_SCRIPT = `(function(){try{var k=${JSON.stringify(WEB_THEME_STORAGE_KEY)};var t=localStorage.getItem(k)||\"light\";var d=t===\"dark\"||(t===\"system\"&&window.matchMedia(\"(prefers-color-scheme: dark)\").matches);document.documentElement.classList.toggle(\"dark\",d);}catch(e){}})();`;\n"]}
@@ -1,9 +1,9 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as React from 'react';
2
2
  import { ReactNode } from 'react';
3
3
  export { useTheme } from 'next-themes';
4
4
 
5
5
  declare function ThemeProvider({ children }: {
6
6
  children: ReactNode;
7
- }): react_jsx_runtime.JSX.Element;
7
+ }): React.JSX.Element;
8
8
 
9
9
  export { ThemeProvider };
@@ -1,25 +1,4 @@
1
- import { ThemeProvider as ThemeProvider$1 } from 'next-themes';
2
- export { useTheme } from 'next-themes';
3
- import { jsx } from 'react/jsx-runtime';
4
-
5
- // src/theme/theme-provider.tsx
6
-
7
- // src/theme/constants.ts
8
- var WEB_THEME_STORAGE_KEY = "coworking.web.theme";
9
- function ThemeProvider({ children }) {
10
- return /* @__PURE__ */ jsx(
11
- ThemeProvider$1,
12
- {
13
- attribute: "class",
14
- defaultTheme: "light",
15
- enableSystem: true,
16
- storageKey: WEB_THEME_STORAGE_KEY,
17
- disableTransitionOnChange: true,
18
- children
19
- }
20
- );
21
- }
22
-
23
- export { ThemeProvider };
1
+ export { ThemeProvider, useTheme } from './chunk-XU3EFSQX.js';
2
+ import './chunk-4Y5DBM6Z.js';
24
3
  //# sourceMappingURL=theme-provider.js.map
25
4
  //# sourceMappingURL=theme-provider.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/theme/constants.ts","../src/theme/theme-provider.tsx"],"names":["NextThemesProvider"],"mappings":";;;;;;;AACO,IAAM,qBAAA,GAAwB,qBAAA;ACG9B,SAAS,aAAA,CAAc,EAAE,QAAA,EAAS,EAA4B;AACnE,EAAA,uBACE,GAAA;AAAA,IAACA,eAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAU,OAAA;AAAA,MACV,YAAA,EAAa,OAAA;AAAA,MACb,YAAA,EAAY,IAAA;AAAA,MACZ,UAAA,EAAY,qBAAA;AAAA,MACZ,yBAAA,EAAyB,IAAA;AAAA,MAExB;AAAA;AAAA,GACH;AAEJ","file":"theme-provider.js","sourcesContent":["/** localStorage key used by next-themes and the index.html boot script */\nexport const WEB_THEME_STORAGE_KEY = \"coworking.web.theme\";\n\nexport type WebThemeMode = \"system\" | \"light\" | \"dark\";\n","import { ThemeProvider as NextThemesProvider } from \"next-themes\";\nimport type { ReactNode } from \"react\";\nimport { WEB_THEME_STORAGE_KEY } from \"./constants\";\n\nexport function ThemeProvider({ children }: { children: ReactNode }) {\n return (\n <NextThemesProvider\n attribute=\"class\"\n defaultTheme=\"light\"\n enableSystem\n storageKey={WEB_THEME_STORAGE_KEY}\n disableTransitionOnChange\n >\n {children}\n </NextThemesProvider>\n );\n}\n\nexport { useTheme } from \"next-themes\";\n"]}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"theme-provider.js"}