@xenide-io/the-old-ui-theme 0.4.4 → 0.4.6

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 (75) hide show
  1. package/dist/{chunk-54ZR4VL5.mjs → chunk-RZXHZWUB.mjs} +44 -17
  2. package/dist/{index-B5NOyoKS.d.mts → index-Od4pIP4F.d.mts} +7 -1
  3. package/dist/{index-B5NOyoKS.d.ts → index-Od4pIP4F.d.ts} +7 -1
  4. package/dist/index.d.mts +2 -2
  5. package/dist/index.d.ts +2 -2
  6. package/dist/index.js +37 -10
  7. package/dist/index.mjs +1 -1
  8. package/dist/suite.d.mts +152 -41
  9. package/dist/suite.d.ts +152 -41
  10. package/dist/suite.js +1184 -661
  11. package/dist/suite.mjs +1122 -600
  12. package/dist/ui.d.mts +1 -1
  13. package/dist/ui.d.ts +1 -1
  14. package/dist/ui.js +37 -10
  15. package/dist/ui.mjs +1 -1
  16. package/package.json +7 -3
  17. package/src/components/ui/Modal.tsx +70 -26
  18. package/src/styles/suite-skin.css +284 -24
  19. package/src/suite/components/ai-panel.tsx +269 -103
  20. package/src/suite/components/suite-app-layout.tsx +48 -28
  21. package/src/suite/components/suite-layout.tsx +84 -40
  22. package/src/suite/components/suite-mobile-drawer.tsx +35 -22
  23. package/src/suite/components/suite-notification-bell.tsx +9 -3
  24. package/src/suite/components/suite-settings-layout.tsx +82 -0
  25. package/src/suite/components/suite-settings-mobile-nav.tsx +18 -17
  26. package/src/suite/components/suite-skeleton.tsx +3 -3
  27. package/src/suite/components/today-calibrating.tsx +11 -35
  28. package/src/suite/components/today-page-frame.tsx +19 -11
  29. package/src/suite/components/today-ui.tsx +276 -19
  30. package/src/suite/index.ts +41 -25
  31. package/src/suite/lib/apps.ts +32 -2
  32. package/src/suite/lib/use-sidebar-width.ts +114 -0
  33. package/src/components/sections/AccordionShowcase.tsx +0 -45
  34. package/src/components/sections/AlertShowcase.tsx +0 -40
  35. package/src/components/sections/AvatarShowcase.tsx +0 -80
  36. package/src/components/sections/BadgeShowcase.tsx +0 -65
  37. package/src/components/sections/ButtonShowcase.tsx +0 -308
  38. package/src/components/sections/CalendarShowcase.tsx +0 -35
  39. package/src/components/sections/CardShowcase.tsx +0 -159
  40. package/src/components/sections/CodeMockupShowcase.tsx +0 -56
  41. package/src/components/sections/ColorPalette.tsx +0 -117
  42. package/src/components/sections/CommandPaletteShowcase.tsx +0 -48
  43. package/src/components/sections/CountdownShowcase.tsx +0 -43
  44. package/src/components/sections/DiffShowcase.tsx +0 -70
  45. package/src/components/sections/DrawerShowcase.tsx +0 -97
  46. package/src/components/sections/DropdownShowcase.tsx +0 -98
  47. package/src/components/sections/EmptyStateShowcase.tsx +0 -50
  48. package/src/components/sections/FilterChipsShowcase.tsx +0 -98
  49. package/src/components/sections/FormShowcase.tsx +0 -127
  50. package/src/components/sections/HoverCardShowcase.tsx +0 -50
  51. package/src/components/sections/IconShowcase.tsx +0 -121
  52. package/src/components/sections/IndicatorShowcase.tsx +0 -52
  53. package/src/components/sections/KbdShowcase.tsx +0 -57
  54. package/src/components/sections/ModalShowcase.tsx +0 -211
  55. package/src/components/sections/NavigationShowcase.tsx +0 -199
  56. package/src/components/sections/NewComponentsShowcase.tsx +0 -1052
  57. package/src/components/sections/ProductLayoutsShowcase.tsx +0 -78
  58. package/src/components/sections/ProgressShowcase.tsx +0 -82
  59. package/src/components/sections/QuillChartShowcase.tsx +0 -92
  60. package/src/components/sections/QuillDashboardShowcase.tsx +0 -149
  61. package/src/components/sections/SegmentedControlShowcase.tsx +0 -49
  62. package/src/components/sections/SetupThemeShowcase.tsx +0 -262
  63. package/src/components/sections/SidebarShowcase.tsx +0 -152
  64. package/src/components/sections/StackShowcase.tsx +0 -33
  65. package/src/components/sections/StepperShowcase.tsx +0 -37
  66. package/src/components/sections/SuiteShowcase.tsx +0 -669
  67. package/src/components/sections/SwapShowcase.tsx +0 -99
  68. package/src/components/sections/TabShowcase.tsx +0 -84
  69. package/src/components/sections/TableShowcase.tsx +0 -142
  70. package/src/components/sections/TimelineShowcase.tsx +0 -83
  71. package/src/components/sections/ToastShowcase.tsx +0 -108
  72. package/src/components/sections/TooltipShowcase.tsx +0 -38
  73. package/src/components/sections/UtilityShowcase.tsx +0 -81
  74. package/src/styles/excel-themes.css +0 -110
  75. package/src/styles/lemon-primitives.css +0 -550
package/dist/suite.js CHANGED
@@ -68,10 +68,16 @@ __export(suite_exports, {
68
68
  AppSwitcherMark: () => AppSwitcherMark,
69
69
  CommandPaletteHost: () => CommandPaletteHost,
70
70
  DeferredChrome: () => DeferredChrome,
71
+ SIDEBAR_COLLAPSE_THRESHOLD: () => SIDEBAR_COLLAPSE_THRESHOLD,
72
+ SIDEBAR_DEFAULT_WIDTH: () => SIDEBAR_DEFAULT_WIDTH,
73
+ SIDEBAR_MAX_WIDTH: () => SIDEBAR_MAX_WIDTH,
74
+ SIDEBAR_MIN_EXPANDED_WIDTH: () => SIDEBAR_MIN_EXPANDED_WIDTH,
75
+ SIDEBAR_RAIL_WIDTH: () => SIDEBAR_RAIL_WIDTH,
71
76
  SUITE_APPS: () => SUITE_APPS2,
72
77
  SUITE_APP_MAP: () => SUITE_APP_MAP,
73
78
  SUITE_GLYPHS: () => SUITE_GLYPHS,
74
79
  SUITE_ICON_NAMES: () => SUITE_ICON_NAMES,
80
+ SUITE_OPEN_ASK_AI_EVENT: () => SUITE_OPEN_ASK_AI_EVENT,
75
81
  SUITE_SPRINGS: () => SUITE_SPRINGS,
76
82
  SourceAppGlyph: () => SourceAppGlyph,
77
83
  SuiteAiPanel: () => SuiteAiPanel,
@@ -89,6 +95,7 @@ __export(suite_exports, {
89
95
  SuitePage: () => SuitePage,
90
96
  SuitePageHeader: () => SuitePageHeader,
91
97
  SuiteSectionHeader: () => SuiteSectionHeader,
98
+ SuiteSettingsLayout: () => SuiteSettingsLayout,
92
99
  SuiteSettingsMobileNav: () => SuiteSettingsMobileNav,
93
100
  SuiteSidebar: () => SuiteSidebar,
94
101
  SuiteSkeleton: () => SuiteSkeleton,
@@ -98,11 +105,15 @@ __export(suite_exports, {
98
105
  SuiteThemeProvider: () => SuiteThemeProvider,
99
106
  SuiteToolbar: () => SuiteToolbar,
100
107
  SuiteUserMenu: () => SuiteUserMenu,
108
+ TodayAskAiCard: () => TodayAskAiCard,
101
109
  TodayCalibrating: () => TodayCalibrating,
110
+ TodayEmptyAction: () => TodayEmptyAction,
102
111
  TodayEmptyState: () => TodayEmptyState,
103
112
  TodayHero: () => TodayHero,
113
+ TodayLayout: () => TodayLayout,
104
114
  TodayPageFrame: () => TodayPageFrame,
105
115
  TodayPanel: () => TodayPanel,
116
+ TodayPrimaryAction: () => TodayPrimaryAction,
106
117
  TodaySection: () => TodaySection,
107
118
  TodayTimeIcon: () => TodayTimeIcon,
108
119
  TodayTopBar: () => TodayTopBar,
@@ -111,11 +122,14 @@ __export(suite_exports, {
111
122
  appSwitcherTriggerClass: () => appSwitcherTriggerClass,
112
123
  cn: () => cn,
113
124
  getTodayGreeting: () => getTodayGreeting,
114
- m: () => import_react8.m,
125
+ m: () => import_react10.m,
126
+ openSuiteAskAi: () => openSuiteAskAi,
127
+ resolveSuiteNotificationHref: () => resolveSuiteNotificationHref,
115
128
  sourceToSuiteApp: () => sourceToSuiteApp,
116
129
  suiteAppBaseUrl: () => suiteAppBaseUrl,
117
130
  suiteAppLabel: () => suiteAppLabel,
118
131
  useIdleMount: () => useIdleMount,
132
+ useSidebarWidth: () => useSidebarWidth,
119
133
  useSuiteTheme: () => useSuiteTheme
120
134
  });
121
135
  module.exports = __toCommonJS(suite_exports);
@@ -127,24 +141,32 @@ function TodayPageFrame({ children }) {
127
141
  "div",
128
142
  {
129
143
  "data-test": "today-page",
130
- className: "today-page-frame relative flex min-h-0 flex-1 flex-col overflow-y-auto overflow-x-hidden",
144
+ className: "today-page-frame relative flex min-h-0 w-full flex-1 flex-col overflow-x-hidden",
131
145
  children: [
132
146
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
133
147
  "div",
134
148
  {
135
- className: "pointer-events-none absolute inset-x-0 top-0 h-[34rem] overflow-hidden",
149
+ className: "pointer-events-none absolute inset-0 overflow-hidden",
136
150
  "aria-hidden": true,
137
151
  children: [
138
152
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "today-page-frame__glow absolute inset-0" }),
139
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "today-page-frame__sun absolute -right-16 -top-16 h-72 w-72 rounded-full bg-gradient-to-br from-amber-300/30 via-rose-300/20 to-rose-400/10 blur-3xl opacity-60 motion-safe:animate-[pulse_8s_ease-in-out_infinite] motion-reduce:opacity-40" }),
140
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "today-page-frame__top-fade absolute inset-x-0 top-0 h-64" }),
141
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "today-page-frame__cloud today-page-frame__cloud--1 absolute -left-24 top-28 h-80 w-[26rem] rounded-[45%]" }),
142
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "today-page-frame__cloud today-page-frame__cloud--2 absolute -right-20 top-40 h-72 w-80 rounded-[40%]" }),
143
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "today-page-frame__cloud today-page-frame__cloud--3 absolute left-[28%] top-[58%] h-64 w-[22rem] rounded-[50%]" })
153
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "today-page-frame__top-fade absolute inset-x-0 top-0 h-[28rem]" }),
154
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "today-page-frame__cloud today-page-frame__cloud--1 absolute -left-28 top-16 h-96 w-[30rem] rounded-[45%]" }),
155
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "today-page-frame__cloud today-page-frame__cloud--2 absolute -right-24 top-24 h-80 w-[22rem] rounded-[40%]" }),
156
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "today-page-frame__cloud today-page-frame__cloud--3 absolute left-[22%] top-48 h-72 w-[24rem] rounded-[50%]" }),
157
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "today-page-frame__cloud today-page-frame__cloud--4 absolute right-[18%] top-[42%] h-64 w-[20rem] rounded-[48%]" }),
158
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "today-page-frame__cloud today-page-frame__cloud--5 absolute left-[8%] top-[68%] h-56 w-[18rem] rounded-[42%]" })
144
159
  ]
145
160
  }
146
161
  ),
147
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "relative flex-1 px-4 pb-5 pt-2 sm:px-6 sm:pb-6 sm:pt-3 lg:px-8 [&_.list-row]:min-h-[52px] [&_.list-row]:sm:min-h-[44px]", children })
162
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
163
+ "div",
164
+ {
165
+ "data-width": "full",
166
+ className: "suite-page-stage suite-page-inset relative z-[1] flex w-full min-w-0 flex-1 flex-col [&_.list-row]:min-h-[52px] [&_.list-row]:sm:min-h-[44px]",
167
+ children
168
+ }
169
+ )
148
170
  ]
149
171
  }
150
172
  );
@@ -597,15 +619,15 @@ function AnimatedSun({ className }) {
597
619
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("stop", { stopColor: "#f59e0b" }),
598
620
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("stop", { offset: "1", stopColor: "#fb923c" })
599
621
  ] }) }),
600
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("g", { className: "origin-center motion-safe:animate-[spin_20s_linear_infinite] motion-reduce:animate-none", children: [0, 45, 90, 135, 180, 225, 270, 315].map((angle) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
622
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("g", { className: "origin-center opacity-80 motion-safe:animate-[pulse_8s_ease-in-out_infinite] motion-reduce:animate-none", children: [0, 45, 90, 135, 180, 225, 270, 315].map((angle) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
601
623
  "line",
602
624
  {
603
625
  x1: "20",
604
- y1: "4",
626
+ y1: "5",
605
627
  x2: "20",
606
628
  y2: "9",
607
629
  stroke: "#fbbf24",
608
- strokeWidth: "2",
630
+ strokeWidth: "1.75",
609
631
  strokeLinecap: "round",
610
632
  transform: `rotate(${angle} 20 20)`
611
633
  },
@@ -639,10 +661,9 @@ function AnimatedMoon({ className }) {
639
661
  fill: "url(#animatedMoonBody)"
640
662
  }
641
663
  ),
642
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("g", { className: "motion-safe:animate-[pulse_4s_ease-in-out_infinite] motion-reduce:animate-none", children: [
643
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("circle", { cx: "29", cy: "10", r: "1.4", fill: "#c7d2fe" }),
644
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("circle", { cx: "34", cy: "16", r: "1", fill: "#c7d2fe" }),
645
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("circle", { cx: "25", cy: "5.5", r: "0.9", fill: "#c7d2fe" })
664
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("g", { className: "opacity-70 motion-safe:animate-[pulse_10s_ease-in-out_infinite] motion-reduce:animate-none", children: [
665
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("circle", { cx: "29", cy: "10", r: "1.2", fill: "#c7d2fe" }),
666
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("circle", { cx: "34", cy: "16", r: "0.9", fill: "#c7d2fe" })
646
667
  ] })
647
668
  ]
648
669
  }
@@ -704,30 +725,193 @@ function getTodayGreeting(user, stats) {
704
725
  const overdueCount = (_d = stats == null ? void 0 : stats.overdueCount) != null ? _d : 0;
705
726
  const hours = (_e = stats == null ? void 0 : stats.hours) != null ? _e : 0;
706
727
  if (overdueCount > 0) {
707
- return `${greeting}. You have ${taskCount} task${taskCount === 1 ? "" : "s"} due today, ${overdueCount} overdue.`;
728
+ return `${greeting}. ${taskCount} task${taskCount === 1 ? "" : "s"} due today, ${overdueCount} overdue.`;
708
729
  }
709
730
  if (taskCount > 0) {
710
- return `${greeting}. You have ${taskCount} task${taskCount === 1 ? "" : "s"} due today.`;
731
+ return `${greeting}. ${taskCount} task${taskCount === 1 ? "" : "s"} due today.`;
711
732
  }
712
733
  if (hours > 0) {
713
- return `${greeting}. You logged ${hours} hour${hours === 1 ? "" : "s"} today.`;
734
+ return `${greeting}. ${hours} hour${hours === 1 ? "" : "s"} logged today.`;
714
735
  }
715
736
  if (period === "evening" || period === "night") {
716
- return `${greeting}. Time to wrap up.`;
737
+ return `${greeting}. Nice work \u2014 time to wrap up.`;
717
738
  }
718
- return `${greeting}. Nothing overdue \u2014 take a nice, deep breath.`;
739
+ return `${greeting}. Clear queue \u2014 take a nice, deep breath.`;
719
740
  }
720
741
  function TodayHero({
721
- message = "Take a nice, deep breath."
742
+ message = "Take a nice, deep breath.",
743
+ brief,
744
+ briefMeta
745
+ }) {
746
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "mt-4 sm:mt-6", children: [
747
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
748
+ "p",
749
+ {
750
+ className: "today-hero max-w-2xl font-display text-lg font-semibold tracking-tight text-ph-ink sm:text-xl sm:leading-snug",
751
+ children: message
752
+ },
753
+ typeof message === "string" ? message : "hero"
754
+ ),
755
+ brief ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "mt-4 max-w-2xl", "data-test": "today-focus-brief", children: [
756
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-[15px] leading-[1.65] text-ph-ink", children: brief }),
757
+ briefMeta ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "mt-1.5 text-xs text-ph-mutedtext", children: briefMeta }) : null
758
+ ] }) : null
759
+ ] });
760
+ }
761
+ function TodayPrimaryAction({
762
+ label,
763
+ description,
764
+ icon,
765
+ accent = "neutral",
766
+ onClick,
767
+ href,
768
+ loading = false,
769
+ active = false,
770
+ className,
771
+ dataTest = "today-primary-action"
722
772
  }) {
723
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "mt-8 text-center sm:mt-10", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
724
- "p",
773
+ const classes = cn(
774
+ "today-primary-action group relative flex w-full max-w-md items-center gap-3 overflow-hidden rounded-xl px-3.5 py-2.5 text-left transition sm:px-4 sm:py-3",
775
+ `today-primary-action--${accent}`,
776
+ active && "today-primary-action--active",
777
+ loading && "pointer-events-none opacity-70",
778
+ className
779
+ );
780
+ const body = /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
781
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "today-primary-action__icon inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-lg sm:h-10 sm:w-10", children: icon }),
782
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "min-w-0 flex-1", children: [
783
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "block text-sm font-semibold tracking-tight sm:text-base", children: label }),
784
+ description ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "mt-0.5 block text-xs opacity-80 sm:text-sm", children: description }) : null
785
+ ] }),
786
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
787
+ "span",
788
+ {
789
+ className: "today-primary-action__chevron shrink-0 text-base opacity-60 transition group-hover:translate-x-0.5 group-hover:opacity-100",
790
+ "aria-hidden": true,
791
+ children: "\u2192"
792
+ }
793
+ )
794
+ ] });
795
+ if (href && !onClick) {
796
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
797
+ "a",
798
+ {
799
+ href,
800
+ className: classes,
801
+ "data-test": dataTest,
802
+ "aria-busy": loading,
803
+ children: body
804
+ }
805
+ );
806
+ }
807
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
808
+ "button",
725
809
  {
726
- className: "today-hero font-display text-2xl font-bold tracking-tight text-ph-ink sm:text-[1.75rem] sm:leading-tight",
727
- children: message
728
- },
729
- typeof message === "string" ? message : "hero"
730
- ) });
810
+ type: "button",
811
+ onClick,
812
+ disabled: loading,
813
+ className: classes,
814
+ "data-test": dataTest,
815
+ "aria-busy": loading,
816
+ children: body
817
+ }
818
+ );
819
+ }
820
+ function TodayEmptyAction({
821
+ title,
822
+ description,
823
+ actionLabel,
824
+ href,
825
+ onClick,
826
+ dataTest
827
+ }) {
828
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
829
+ "div",
830
+ {
831
+ className: "rounded-lg border border-dashed border-ph-border/80 bg-ph-muted/30 px-4 py-4 text-center",
832
+ "data-test": dataTest,
833
+ children: [
834
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "text-sm font-semibold text-ph-ink", children: title }),
835
+ description ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "mx-auto mt-1 max-w-sm text-xs leading-relaxed text-ph-subtle sm:text-sm", children: description }) : null,
836
+ actionLabel && (href || onClick) ? href ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
837
+ "a",
838
+ {
839
+ href,
840
+ className: "mt-2.5 inline-flex text-sm font-semibold text-ph-brand hover:underline",
841
+ children: actionLabel
842
+ }
843
+ ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
844
+ "button",
845
+ {
846
+ type: "button",
847
+ onClick,
848
+ className: "mt-2.5 inline-flex text-sm font-semibold text-ph-brand hover:underline",
849
+ children: actionLabel
850
+ }
851
+ ) : null
852
+ ]
853
+ }
854
+ );
855
+ }
856
+ function TodayLayout({
857
+ primary,
858
+ main,
859
+ aside,
860
+ className
861
+ }) {
862
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
863
+ "div",
864
+ {
865
+ className: cn("mt-5 space-y-6 sm:mt-6", className),
866
+ "data-test": "today-layout",
867
+ children: [
868
+ primary ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "max-w-md", children: primary }) : null,
869
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "grid gap-6 lg:grid-cols-[minmax(0,1fr)_minmax(16rem,20rem)] lg:items-start lg:gap-8", children: [
870
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "min-w-0 space-y-8", children: main }),
871
+ aside ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("aside", { className: "space-y-3 lg:sticky lg:top-6 lg:self-start", children: aside }) : null
872
+ ] })
873
+ ]
874
+ }
875
+ );
876
+ }
877
+ function TodayAskAiCard({
878
+ title = "Ask AI",
879
+ description = "Ask about your workspace, draft something, or look a fact up online.",
880
+ cta = "Ask",
881
+ className,
882
+ onClick,
883
+ href
884
+ }) {
885
+ const classes = cn(
886
+ "group flex w-full items-start gap-3.5 rounded-2xl border border-ph-border/70 bg-ph-surface px-4 py-3.5 text-left shadow-[0_1px_12px_-8px_rgba(15,23,42,0.1)] transition hover:border-ph-brand/35 hover:bg-[color-mix(in_oklab,var(--ph-accent)_6%,var(--ph-surface))] sm:px-5",
887
+ className
888
+ );
889
+ const body = /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
890
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-2xl bg-ph-brand/15 text-ph-brand shadow-sm ring-1 ring-black/[0.06]", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SuiteIcon, { name: "stack-hex", accent: "shellstack", className: "h-5 w-5" }) }),
891
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "min-w-0 flex-1", children: [
892
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "flex flex-wrap items-baseline justify-between gap-x-3 gap-y-1", children: [
893
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "font-display text-sm font-bold tracking-tight text-ph-ink", children: title }),
894
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-sm font-medium text-ph-brand transition group-hover:underline", children: cta })
895
+ ] }),
896
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "mt-1 block text-sm leading-relaxed text-ph-subtle", children: description })
897
+ ] })
898
+ ] });
899
+ if (onClick) {
900
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
901
+ "button",
902
+ {
903
+ type: "button",
904
+ onClick,
905
+ className: classes,
906
+ "data-test": "today-ask-ai",
907
+ children: body
908
+ }
909
+ );
910
+ }
911
+ if (href) {
912
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("a", { href, className: classes, "data-test": "today-ask-ai", children: body });
913
+ }
914
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: classes, "data-test": "today-ask-ai", children: body });
731
915
  }
732
916
  function TodaySection({
733
917
  icon: Icon,
@@ -738,7 +922,7 @@ function TodaySection({
738
922
  testId,
739
923
  children
740
924
  }) {
741
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { "data-test": testId, className: "space-y-4", children: [
925
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { "data-test": testId, className: "space-y-5", children: [
742
926
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex items-start justify-between gap-4", children: [
743
927
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "flex min-w-0 items-start gap-3.5", children: [
744
928
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
@@ -769,8 +953,7 @@ function TodayPanel({
769
953
  "div",
770
954
  {
771
955
  className: cn(
772
- "border-ph-border/70 rounded-2xl border bg-ph-surface p-6 shadow-[0_2px_28px_-10px_rgba(15,23,42,0.14)] transition-all duration-200 ease-out sm:p-6",
773
- "hover:shadow-[0_8px_32px_-12px_rgba(15,23,42,0.18)] hover:-translate-y-0.5 motion-reduce:transition-none motion-reduce:hover:transform-none",
956
+ "border-ph-border/70 rounded-2xl border bg-ph-surface p-5 shadow-[0_1px_16px_-8px_rgba(15,23,42,0.12)] sm:p-5",
774
957
  className
775
958
  ),
776
959
  children
@@ -948,6 +1131,70 @@ function AppSwitcher({
948
1131
  var import_react2 = require("react");
949
1132
  var import_navigation = require("next/navigation");
950
1133
  var import_iconoir_react3 = require("iconoir-react");
1134
+
1135
+ // src/suite/lib/apps.ts
1136
+ var SUITE_APPS2 = [
1137
+ {
1138
+ slug: "shellstack",
1139
+ name: "ShellStack",
1140
+ description: "Organisation and billing",
1141
+ icon: "/icon-shellstack.svg",
1142
+ landing: "/home",
1143
+ baseUrlEnv: "NEXT_PUBLIC_SHELLSTACK_URL",
1144
+ baseUrlFallback: "http://localhost:3002"
1145
+ },
1146
+ {
1147
+ slug: "tides",
1148
+ name: "Tides",
1149
+ description: "Projects and tasks",
1150
+ icon: "/tides-icon.svg",
1151
+ landing: "/today",
1152
+ baseUrlEnv: "NEXT_PUBLIC_TIDES_URL",
1153
+ baseUrlFallback: "http://localhost:3001"
1154
+ },
1155
+ {
1156
+ slug: "turtletime",
1157
+ name: "TurtleTime",
1158
+ description: "Time tracking",
1159
+ icon: "/turtletime-icon.svg",
1160
+ landing: "/today",
1161
+ baseUrlEnv: "NEXT_PUBLIC_TURTLETIME_URL",
1162
+ baseUrlFallback: "http://localhost:3000"
1163
+ },
1164
+ {
1165
+ slug: "kraken",
1166
+ name: "Kraken",
1167
+ description: "Documents and knowledge",
1168
+ icon: "/kraken-icon.svg",
1169
+ landing: "/today",
1170
+ baseUrlEnv: "NEXT_PUBLIC_KRAKEN_URL",
1171
+ baseUrlFallback: "http://localhost:3003"
1172
+ }
1173
+ ];
1174
+ var SUITE_APP_MAP = Object.fromEntries(SUITE_APPS2.map((app) => [app.slug, app]));
1175
+ function suiteAppBaseUrl(slug) {
1176
+ const def = SUITE_APP_MAP[slug];
1177
+ const fromEnv = typeof process !== "undefined" ? process.env[def.baseUrlEnv] : void 0;
1178
+ return (fromEnv || def.baseUrlFallback).replace(/\/$/, "");
1179
+ }
1180
+ var SOURCE_APP_SLUG = {
1181
+ turtletime: "turtletime",
1182
+ tides: "tides",
1183
+ kraken: "kraken",
1184
+ portal: "shellstack",
1185
+ shellstack: "shellstack"
1186
+ };
1187
+ function resolveSuiteNotificationHref(href, sourceApp) {
1188
+ const value = (href || "").trim();
1189
+ if (!value) return "";
1190
+ if (/^(https?:|mailto:|\/\/)/i.test(value)) return value;
1191
+ const path = value.startsWith("/") ? value : `/${value}`;
1192
+ const slug = SOURCE_APP_SLUG[(sourceApp || "").toLowerCase()];
1193
+ if (!slug) return path;
1194
+ return `${suiteAppBaseUrl(slug)}${path}`;
1195
+ }
1196
+
1197
+ // src/suite/components/suite-notification-bell.tsx
951
1198
  var import_jsx_runtime7 = require("react/jsx-runtime");
952
1199
  var POLL_MS = 6e4;
953
1200
  function timeAgo(iso) {
@@ -1038,9 +1285,13 @@ function SuiteNotificationBell({
1038
1285
  } catch (e) {
1039
1286
  }
1040
1287
  }
1041
- if (!n.href) return;
1042
- if (/^https?:\/\//i.test(n.href)) window.location.assign(n.href);
1043
- else router.push(n.href);
1288
+ const target = resolveSuiteNotificationHref(n.href, n.source_app);
1289
+ if (!target) return;
1290
+ if (/^https?:\/\//i.test(target)) {
1291
+ window.location.assign(target);
1292
+ return;
1293
+ }
1294
+ router.push(target);
1044
1295
  },
1045
1296
  [router, markRead]
1046
1297
  );
@@ -1193,6 +1444,7 @@ function SuiteMobileDrawer({
1193
1444
  children,
1194
1445
  side = "left",
1195
1446
  showCloseButton = false,
1447
+ title,
1196
1448
  closeLabel = "Close navigation",
1197
1449
  backdropLabel = "Close navigation",
1198
1450
  dialogLabel = "Navigation",
@@ -1270,23 +1522,35 @@ function SuiteMobileDrawer({
1270
1522
  tabIndex: -1,
1271
1523
  "data-test": panelDataTest,
1272
1524
  className: cn(
1273
- "suite-scroll-lock relative flex h-full w-[86%] max-w-64 flex-col overflow-hidden bg-ph-surface shadow-xl outline-none motion-safe:transition-transform motion-safe:ease-spring-fast",
1525
+ "suite-scroll-lock relative flex h-full w-[86%] max-w-72 flex-col overflow-hidden bg-ph-surface shadow-xl outline-none motion-safe:transition-transform motion-safe:ease-spring-fast",
1274
1526
  side === "right" && "ml-auto",
1275
1527
  shown ? "translate-x-0" : side === "right" ? "translate-x-full" : "-translate-x-full",
1276
1528
  panelClassName
1277
1529
  ),
1278
1530
  style: { transitionDuration: `${durationMs}ms` },
1279
1531
  children: [
1280
- showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex h-14 shrink-0 items-center justify-end border-b border-ph-border px-3", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1281
- "button",
1532
+ showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1533
+ "div",
1282
1534
  {
1283
- type: "button",
1284
- onClick: onClose,
1285
- className: "-mr-1.5 inline-flex h-11 w-11 items-center justify-center rounded-lg text-ph-mutedtext transition-colors hover:bg-ph-muted hover:text-ph-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-brand",
1286
- "aria-label": closeLabel,
1287
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_iconoir_react4.Xmark, { className: "h-4 w-4", "aria-hidden": true })
1535
+ className: cn(
1536
+ "flex h-14 shrink-0 items-center border-b border-ph-border px-3",
1537
+ title ? "justify-between" : "justify-end"
1538
+ ),
1539
+ children: [
1540
+ title ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "truncate text-sm font-semibold text-ph-ink", children: title }) : null,
1541
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1542
+ "button",
1543
+ {
1544
+ type: "button",
1545
+ onClick: onClose,
1546
+ className: "-mr-1.5 inline-flex h-11 w-11 items-center justify-center rounded-lg text-ph-mutedtext transition-colors hover:bg-ph-muted hover:text-ph-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-brand",
1547
+ "aria-label": closeLabel,
1548
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_iconoir_react4.Xmark, { className: "h-4 w-4", "aria-hidden": true })
1549
+ }
1550
+ )
1551
+ ]
1288
1552
  }
1289
- ) }) : null,
1553
+ ) : null,
1290
1554
  children
1291
1555
  ]
1292
1556
  }
@@ -1343,95 +1607,378 @@ function SuiteMobileHeader({
1343
1607
  );
1344
1608
  }
1345
1609
 
1346
- // src/suite/components/suite-user-menu.tsx
1347
- var import_image2 = __toESM(require("next/image"));
1348
- var import_navigation2 = require("next/navigation");
1349
- var import_iconoir_react6 = require("iconoir-react");
1350
-
1351
- // src/components/ui/DropdownMenu.tsx
1352
- var DropdownPrimitive = __toESM(require("@radix-ui/react-dropdown-menu"));
1353
-
1354
- // src/lib/cn.ts
1355
- function cn2(...parts) {
1356
- return parts.filter(Boolean).join(" ");
1357
- }
1358
-
1359
- // src/components/ui/DropdownMenu.tsx
1610
+ // src/suite/components/suite-layout.tsx
1611
+ var import_react6 = require("react");
1360
1612
  var import_jsx_runtime12 = require("react/jsx-runtime");
1361
- function DropdownContent({
1613
+ function SuiteBreadcrumbs({ items, className }) {
1614
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("nav", { "aria-label": "Breadcrumb", className, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("ol", { className: "flex min-w-0 items-center gap-1.5", children: items.map((item, index) => {
1615
+ const isLast = index === items.length - 1;
1616
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("li", { className: "flex min-w-0 items-center gap-1.5", children: [
1617
+ index > 0 ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "select-none text-ph-border", "aria-hidden": "true", children: "/" }) : null,
1618
+ item.href && !isLast ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1619
+ "a",
1620
+ {
1621
+ href: item.href,
1622
+ className: "truncate transition hover:text-ph-ink",
1623
+ children: item.label
1624
+ }
1625
+ ) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1626
+ "span",
1627
+ {
1628
+ className: cn(
1629
+ "truncate",
1630
+ isLast ? "font-medium text-ph-ink" : "text-ph-subtle"
1631
+ ),
1632
+ "aria-current": isLast ? "page" : void 0,
1633
+ children: item.label
1634
+ }
1635
+ )
1636
+ ] }, index);
1637
+ }) }) });
1638
+ }
1639
+ function SuitePage({
1362
1640
  children,
1363
- align = "start",
1364
- side = "bottom",
1365
- sideOffset = 7,
1366
- alignOffset = 0,
1367
- collisionPadding = 8,
1368
- avoidCollisions = true,
1369
- panelClassName
1641
+ width = "full",
1642
+ inset = true,
1643
+ className,
1644
+ as: Component = "div",
1645
+ dataTest,
1646
+ id,
1647
+ role,
1648
+ "aria-live": ariaLive
1370
1649
  }) {
1371
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(DropdownPrimitive.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1372
- DropdownPrimitive.Content,
1650
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1651
+ Component,
1373
1652
  {
1374
- className: cn2("ph-dropdown-panel", panelClassName),
1375
- align,
1376
- side,
1377
- sideOffset,
1378
- alignOffset,
1379
- collisionPadding,
1380
- avoidCollisions,
1381
- sticky: "partial",
1382
- children: [
1383
- children,
1384
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(DropdownPrimitive.Arrow, { className: "ph-dropdown-arrow", width: 12, height: 6 })
1385
- ]
1653
+ id,
1654
+ "data-test": dataTest,
1655
+ "data-width": width,
1656
+ role,
1657
+ "aria-live": ariaLive,
1658
+ className: cn(
1659
+ "suite-page-stage flex w-full min-w-0 flex-col",
1660
+ inset && "suite-page-inset",
1661
+ className
1662
+ ),
1663
+ children
1386
1664
  }
1387
- ) });
1665
+ );
1388
1666
  }
1389
- function DropdownMenu(_a) {
1390
- var _b = _a, {
1391
- trigger,
1392
- children,
1393
- align,
1394
- side,
1395
- sideOffset,
1396
- alignOffset,
1397
- collisionPadding,
1398
- avoidCollisions,
1399
- className,
1400
- panelClassName,
1401
- "aria-label": ariaLabel,
1402
- open,
1403
- defaultOpen,
1404
- onOpenChange,
1405
- modal = false,
1406
- disabled
1407
- } = _b, props = __objRest(_b, [
1408
- "trigger",
1409
- "children",
1410
- "align",
1411
- "side",
1412
- "sideOffset",
1413
- "alignOffset",
1414
- "collisionPadding",
1415
- "avoidCollisions",
1416
- "className",
1417
- "panelClassName",
1418
- "aria-label",
1419
- "open",
1420
- "defaultOpen",
1421
- "onOpenChange",
1422
- "modal",
1423
- "disabled"
1424
- ]);
1425
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", __spreadProps(__spreadValues({ className: cn2("ph-dropdown", className) }, props), { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1426
- DropdownPrimitive.Root,
1427
- {
1667
+ function SuitePageHeader({
1668
+ title,
1669
+ description,
1670
+ eyebrow,
1671
+ actions,
1672
+ className,
1673
+ titleClassName,
1674
+ dataTest,
1675
+ /** Optional icon rendered before the title. */
1676
+ icon,
1677
+ /** Use the animated sun/moon icon from the Today page. */
1678
+ todayIcon,
1679
+ todayIconClassName,
1680
+ /** Small badge/pill next to the title (e.g. "Beta", org name). */
1681
+ badge,
1682
+ /** Breadcrumb line rendered above the title. */
1683
+ breadcrumb,
1684
+ /** Stick to the top of the scrollport (desktop page titles). */
1685
+ sticky = false
1686
+ }) {
1687
+ const headerRef = (0, import_react6.useRef)(null);
1688
+ const [stuck, setStuck] = (0, import_react6.useState)(false);
1689
+ (0, import_react6.useEffect)(() => {
1690
+ var _a;
1691
+ if (!sticky) return;
1692
+ const el = headerRef.current;
1693
+ if (!el) return;
1694
+ const sentinel = document.createElement("div");
1695
+ sentinel.setAttribute("aria-hidden", "true");
1696
+ sentinel.style.cssText = "position:relative;height:1px;width:100%;margin:0;padding:0;pointer-events:none";
1697
+ (_a = el.parentElement) == null ? void 0 : _a.insertBefore(sentinel, el);
1698
+ const observer = new IntersectionObserver(
1699
+ ([entry]) => {
1700
+ setStuck(!entry.isIntersecting);
1701
+ },
1702
+ { threshold: [1], root: null }
1703
+ );
1704
+ observer.observe(sentinel);
1705
+ return () => {
1706
+ observer.disconnect();
1707
+ sentinel.remove();
1708
+ };
1709
+ }, [sticky]);
1710
+ const resolvedIcon = todayIcon ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1711
+ TodayTimeIcon,
1712
+ {
1713
+ className: cn(
1714
+ "h-7 w-7 text-amber-500 sm:h-8 sm:w-8",
1715
+ todayIconClassName
1716
+ )
1717
+ }
1718
+ ) : icon;
1719
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1720
+ "header",
1721
+ {
1722
+ ref: headerRef,
1723
+ "data-test": dataTest,
1724
+ "data-stuck": sticky ? stuck ? "true" : "false" : void 0,
1725
+ className: cn(
1726
+ "flex items-start justify-between gap-4 pb-2 sm:pb-3",
1727
+ // No extra pt here — page inset sets the shared title baseline.
1728
+ // Stuck state adds pad via .suite-page-header-sticky[data-stuck].
1729
+ sticky && "suite-page-header-sticky",
1730
+ className
1731
+ ),
1732
+ children: [
1733
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "min-w-0 flex-1", children: [
1734
+ eyebrow ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "mb-0.5 flex min-w-0 items-center gap-1.5 text-xs text-ph-subtle", children: eyebrow }) : null,
1735
+ breadcrumb ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "mb-0.5 flex min-w-0 items-center gap-1.5 text-xs text-ph-subtle", children: breadcrumb }) : null,
1736
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex min-w-0 items-center gap-3", children: [
1737
+ resolvedIcon ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1738
+ "div",
1739
+ {
1740
+ className: "hidden shrink-0 sm:flex sm:items-center [&_svg]:h-7 [&_svg]:w-7 sm:[&_svg]:h-8 sm:[&_svg]:w-8",
1741
+ "aria-hidden": "true",
1742
+ children: resolvedIcon
1743
+ }
1744
+ ) : null,
1745
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1", children: [
1746
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1747
+ "h1",
1748
+ {
1749
+ className: cn(
1750
+ "font-display text-[1.625rem] font-bold leading-none tracking-tight text-ph-ink sm:text-[2.25rem]",
1751
+ titleClassName
1752
+ ),
1753
+ children: title
1754
+ }
1755
+ ),
1756
+ badge ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "rounded-md bg-ph-muted px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wide text-ph-subtle", children: badge }) : null
1757
+ ] })
1758
+ ] }),
1759
+ description ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1760
+ "div",
1761
+ {
1762
+ className: cn(
1763
+ "mt-1.5 max-w-2xl text-pretty text-sm leading-5 text-ph-subtle",
1764
+ resolvedIcon && "sm:pl-11"
1765
+ ),
1766
+ children: description
1767
+ }
1768
+ ) : null
1769
+ ] }),
1770
+ actions ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "flex shrink-0 items-center gap-2 self-center", children: actions }) : null
1771
+ ]
1772
+ }
1773
+ );
1774
+ }
1775
+ function SuiteToolbar({
1776
+ children,
1777
+ className,
1778
+ label = "Page tools",
1779
+ dataTest
1780
+ }) {
1781
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1782
+ "div",
1783
+ {
1784
+ role: "toolbar",
1785
+ "aria-label": label,
1786
+ "data-test": dataTest,
1787
+ className: cn("flex min-w-0 flex-wrap items-center gap-2", className),
1788
+ children
1789
+ }
1790
+ );
1791
+ }
1792
+ function SuiteTabList({
1793
+ children,
1794
+ className,
1795
+ label,
1796
+ dataTest
1797
+ }) {
1798
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1799
+ "nav",
1800
+ {
1801
+ "aria-label": label,
1802
+ "data-test": dataTest,
1803
+ className: cn(
1804
+ "flex min-w-0 flex-wrap gap-2 [&_a]:min-h-[48px] [&_button]:min-h-[48px] sm:[&_a]:min-h-[44px] sm:[&_button]:min-h-[44px]",
1805
+ className
1806
+ ),
1807
+ children
1808
+ }
1809
+ );
1810
+ }
1811
+ function SuiteSectionHeader({
1812
+ title,
1813
+ description,
1814
+ action,
1815
+ className
1816
+ }) {
1817
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1818
+ "div",
1819
+ {
1820
+ className: cn(
1821
+ "flex min-w-0 flex-col gap-4 sm:flex-row sm:items-end sm:justify-between",
1822
+ className
1823
+ ),
1824
+ children: [
1825
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "min-w-0", children: [
1826
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h2", { className: "font-display text-balance text-lg font-semibold tracking-tight text-ph-ink sm:text-xl", children: title }),
1827
+ description ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "mt-1 max-w-2xl text-pretty text-sm leading-5 text-ph-subtle", children: description }) : null
1828
+ ] }),
1829
+ action ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "flex min-h-[44px] shrink-0 items-center", children: action }) : null
1830
+ ]
1831
+ }
1832
+ );
1833
+ }
1834
+
1835
+ // src/suite/components/suite-settings-layout.tsx
1836
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1837
+ function SuiteSettingsLayout({
1838
+ children,
1839
+ sidebar,
1840
+ mobileNav,
1841
+ loading,
1842
+ title = "Settings",
1843
+ description,
1844
+ header,
1845
+ dataTest = "settings-page",
1846
+ headerDataTest = "settings-page-header",
1847
+ className,
1848
+ contentClassName
1849
+ }) {
1850
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1851
+ SuitePage,
1852
+ {
1853
+ dataTest,
1854
+ className: cn("flex h-full flex-col overflow-hidden", className),
1855
+ children: [
1856
+ header != null ? header : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1857
+ SuitePageHeader,
1858
+ {
1859
+ sticky: true,
1860
+ dataTest: headerDataTest,
1861
+ title,
1862
+ description
1863
+ }
1864
+ ),
1865
+ loading != null ? loading : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "suite-page-body mt-6 flex min-h-0 flex-1 flex-col", children: [
1866
+ mobileNav ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "sticky top-0 z-20 mb-2 shrink-0 bg-ph-canvas/95 backdrop-blur lg:hidden", children: mobileNav }) : null,
1867
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex min-h-0 flex-1 flex-col gap-6 lg:flex-row lg:gap-8", children: [
1868
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1869
+ "aside",
1870
+ {
1871
+ "aria-label": "Settings",
1872
+ className: "hidden w-56 shrink-0 bg-transparent lg:block lg:self-stretch lg:overflow-y-auto lg:overscroll-contain",
1873
+ children: sidebar
1874
+ }
1875
+ ),
1876
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1877
+ "div",
1878
+ {
1879
+ className: cn(
1880
+ "min-h-0 min-w-0 flex-1 overflow-y-auto overscroll-contain pb-6",
1881
+ contentClassName
1882
+ ),
1883
+ children
1884
+ }
1885
+ )
1886
+ ] })
1887
+ ] })
1888
+ ]
1889
+ }
1890
+ );
1891
+ }
1892
+
1893
+ // src/suite/components/suite-user-menu.tsx
1894
+ var import_image2 = __toESM(require("next/image"));
1895
+ var import_navigation2 = require("next/navigation");
1896
+ var import_iconoir_react6 = require("iconoir-react");
1897
+
1898
+ // src/components/ui/DropdownMenu.tsx
1899
+ var DropdownPrimitive = __toESM(require("@radix-ui/react-dropdown-menu"));
1900
+
1901
+ // src/lib/cn.ts
1902
+ function cn2(...parts) {
1903
+ return parts.filter(Boolean).join(" ");
1904
+ }
1905
+
1906
+ // src/components/ui/DropdownMenu.tsx
1907
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1908
+ function DropdownContent({
1909
+ children,
1910
+ align = "start",
1911
+ side = "bottom",
1912
+ sideOffset = 7,
1913
+ alignOffset = 0,
1914
+ collisionPadding = 8,
1915
+ avoidCollisions = true,
1916
+ panelClassName
1917
+ }) {
1918
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DropdownPrimitive.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1919
+ DropdownPrimitive.Content,
1920
+ {
1921
+ className: cn2("ph-dropdown-panel", panelClassName),
1922
+ align,
1923
+ side,
1924
+ sideOffset,
1925
+ alignOffset,
1926
+ collisionPadding,
1927
+ avoidCollisions,
1928
+ sticky: "partial",
1929
+ children: [
1930
+ children,
1931
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DropdownPrimitive.Arrow, { className: "ph-dropdown-arrow", width: 12, height: 6 })
1932
+ ]
1933
+ }
1934
+ ) });
1935
+ }
1936
+ function DropdownMenu(_a) {
1937
+ var _b = _a, {
1938
+ trigger,
1939
+ children,
1940
+ align,
1941
+ side,
1942
+ sideOffset,
1943
+ alignOffset,
1944
+ collisionPadding,
1945
+ avoidCollisions,
1946
+ className,
1947
+ panelClassName,
1948
+ "aria-label": ariaLabel,
1949
+ open,
1950
+ defaultOpen,
1951
+ onOpenChange,
1952
+ modal = false,
1953
+ disabled
1954
+ } = _b, props = __objRest(_b, [
1955
+ "trigger",
1956
+ "children",
1957
+ "align",
1958
+ "side",
1959
+ "sideOffset",
1960
+ "alignOffset",
1961
+ "collisionPadding",
1962
+ "avoidCollisions",
1963
+ "className",
1964
+ "panelClassName",
1965
+ "aria-label",
1966
+ "open",
1967
+ "defaultOpen",
1968
+ "onOpenChange",
1969
+ "modal",
1970
+ "disabled"
1971
+ ]);
1972
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", __spreadProps(__spreadValues({ className: cn2("ph-dropdown", className) }, props), { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1973
+ DropdownPrimitive.Root,
1974
+ {
1428
1975
  open,
1429
1976
  defaultOpen,
1430
1977
  onOpenChange,
1431
1978
  modal,
1432
1979
  children: [
1433
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(DropdownPrimitive.Trigger, { asChild: true, disabled, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", className: "ph-dropdown-trigger", "aria-label": ariaLabel, children: trigger }) }),
1434
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1980
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DropdownPrimitive.Trigger, { asChild: true, disabled, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: "ph-dropdown-trigger", "aria-label": ariaLabel, children: trigger }) }),
1981
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1435
1982
  DropdownContent,
1436
1983
  {
1437
1984
  align,
@@ -1450,7 +1997,7 @@ function DropdownMenu(_a) {
1450
1997
  }
1451
1998
  function DropdownItem(_a) {
1452
1999
  var _b = _a, { className, children, disabled } = _b, props = __objRest(_b, ["className", "children", "disabled"]);
1453
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(DropdownPrimitive.Item, { asChild: true, disabled, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2000
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DropdownPrimitive.Item, { asChild: true, disabled, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1454
2001
  "button",
1455
2002
  __spreadProps(__spreadValues({
1456
2003
  type: "button",
@@ -1463,7 +2010,7 @@ function DropdownItem(_a) {
1463
2010
  }
1464
2011
 
1465
2012
  // src/suite/components/suite-user-menu.tsx
1466
- var import_jsx_runtime13 = require("react/jsx-runtime");
2013
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1467
2014
  function computeInitials(name, email) {
1468
2015
  const source = (name || email || "?").trim();
1469
2016
  return source.split(/[\s@]+/).filter(Boolean).slice(0, 2).map((part) => part[0]).join("").toUpperCase();
@@ -1480,7 +2027,7 @@ function SuiteUserMenu({
1480
2027
  }) {
1481
2028
  const router = (0, import_navigation2.useRouter)();
1482
2029
  const initials = fallbackInitials != null ? fallbackInitials : computeInitials(name, email);
1483
- const avatar = /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "inline-flex h-11 w-11 items-center justify-center rounded-full transition-colors hover:bg-ph-muted", children: image ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2030
+ const avatar = /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "inline-flex h-11 w-11 items-center justify-center rounded-full transition-colors hover:bg-ph-muted", children: image ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1484
2031
  import_image2.default,
1485
2032
  {
1486
2033
  src: image,
@@ -1490,8 +2037,8 @@ function SuiteUserMenu({
1490
2037
  className: "h-8 w-8 rounded-full object-cover",
1491
2038
  unoptimized: true
1492
2039
  }
1493
- ) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "flex h-8 w-8 items-center justify-center rounded-full bg-ph-muted text-sm font-semibold text-ph-brand", children: initials }) });
1494
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2040
+ ) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "flex h-8 w-8 items-center justify-center rounded-full bg-ph-muted text-sm font-semibold text-ph-brand", children: initials }) });
2041
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1495
2042
  DropdownMenu,
1496
2043
  {
1497
2044
  trigger: avatar,
@@ -1504,29 +2051,29 @@ function SuiteUserMenu({
1504
2051
  className,
1505
2052
  "data-test": dataTest,
1506
2053
  children: [
1507
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "px-2 py-1.5", children: [
1508
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "truncate text-sm font-medium text-ph-ink", children: name || email || "Account" }),
1509
- email ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "truncate text-xs text-ph-mutedtext", children: email }) : null
2054
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "px-2 py-1.5", children: [
2055
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "truncate text-sm font-medium text-ph-ink", children: name || email || "Account" }),
2056
+ email ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "truncate text-xs text-ph-mutedtext", children: email }) : null
1510
2057
  ] }),
1511
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "my-1 border-t border-ph-border" }),
1512
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2058
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "my-1 border-t border-ph-border" }),
2059
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1513
2060
  DropdownItem,
1514
2061
  {
1515
2062
  "data-test": `${dataTest}-settings`,
1516
2063
  onClick: () => router.push(settingsHref),
1517
2064
  children: [
1518
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_iconoir_react6.Settings, { className: "h-4 w-4 text-ph-mutedtext", "aria-hidden": true }),
2065
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_iconoir_react6.Settings, { className: "h-4 w-4 text-ph-mutedtext", "aria-hidden": true }),
1519
2066
  "Profile settings"
1520
2067
  ]
1521
2068
  }
1522
2069
  ),
1523
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2070
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1524
2071
  DropdownItem,
1525
2072
  {
1526
2073
  "data-test": `${dataTest}-sign-out`,
1527
2074
  onClick: onSignOut,
1528
2075
  children: [
1529
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_iconoir_react6.LogOut, { className: "h-4 w-4 text-ph-mutedtext", "aria-hidden": true }),
2076
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_iconoir_react6.LogOut, { className: "h-4 w-4 text-ph-mutedtext", "aria-hidden": true }),
1530
2077
  "Sign out"
1531
2078
  ]
1532
2079
  }
@@ -1538,7 +2085,7 @@ function SuiteUserMenu({
1538
2085
 
1539
2086
  // src/suite/components/suite-bottom-nav.tsx
1540
2087
  var import_link = __toESM(require("next/link"));
1541
- var import_jsx_runtime14 = require("react/jsx-runtime");
2088
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1542
2089
  function SuiteBottomNav({
1543
2090
  items,
1544
2091
  ariaLabel = "Primary navigation",
@@ -1551,8 +2098,8 @@ function SuiteBottomNav({
1551
2098
  );
1552
2099
  }
1553
2100
  const activeIndex = items.findIndex((item) => item.active);
1554
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
1555
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2101
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
2102
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1556
2103
  "div",
1557
2104
  {
1558
2105
  "aria-hidden": true,
@@ -1560,7 +2107,7 @@ function SuiteBottomNav({
1560
2107
  style: { height: "calc(60px + env(safe-area-inset-bottom))" }
1561
2108
  }
1562
2109
  ),
1563
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
2110
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
1564
2111
  "nav",
1565
2112
  {
1566
2113
  "aria-label": ariaLabel,
@@ -1575,12 +2122,12 @@ function SuiteBottomNav({
1575
2122
  "--suite-nav-active": activeIndex >= 0 ? activeIndex : 0
1576
2123
  },
1577
2124
  children: [
1578
- activeIndex >= 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { "aria-hidden": true, className: "suite-bottom-nav__indicator" }) : null,
2125
+ activeIndex >= 0 ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { "aria-hidden": true, className: "suite-bottom-nav__indicator" }) : null,
1579
2126
  items.map((item) => {
1580
2127
  var _a;
1581
2128
  const Icon = item.icon;
1582
2129
  const active = Boolean(item.active);
1583
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
2130
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
1584
2131
  import_link.default,
1585
2132
  {
1586
2133
  href: item.href,
@@ -1591,14 +2138,14 @@ function SuiteBottomNav({
1591
2138
  active && "font-semibold text-ph-brand"
1592
2139
  ),
1593
2140
  children: [
1594
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2141
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1595
2142
  "span",
1596
2143
  {
1597
2144
  className: cn(
1598
2145
  "suite-bottom-nav__icon relative z-10 inline-flex items-center justify-center",
1599
2146
  active && "suite-bottom-nav__icon--active"
1600
2147
  ),
1601
- children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2148
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1602
2149
  Icon,
1603
2150
  {
1604
2151
  className: "h-6 w-6",
@@ -1608,7 +2155,7 @@ function SuiteBottomNav({
1608
2155
  )
1609
2156
  }
1610
2157
  ),
1611
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "relative z-10 max-w-full truncate", children: item.label })
2158
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "relative z-10 max-w-full truncate", children: item.label })
1612
2159
  ]
1613
2160
  },
1614
2161
  item.href
@@ -1620,117 +2167,39 @@ function SuiteBottomNav({
1620
2167
  ] });
1621
2168
  }
1622
2169
 
1623
- // src/suite/lib/apps.ts
1624
- var SUITE_APPS2 = [
1625
- {
1626
- slug: "shellstack",
1627
- name: "ShellStack",
1628
- description: "Organisation and billing",
1629
- icon: "/icon-shellstack.svg",
1630
- landing: "/home",
1631
- baseUrlEnv: "NEXT_PUBLIC_SHELLSTACK_URL",
1632
- baseUrlFallback: "http://localhost:3002"
1633
- },
1634
- {
1635
- slug: "tides",
1636
- name: "Tides",
1637
- description: "Projects and tasks",
1638
- icon: "/tides-icon.svg",
1639
- landing: "/today",
1640
- baseUrlEnv: "NEXT_PUBLIC_TIDES_URL",
1641
- baseUrlFallback: "http://localhost:3001"
1642
- },
1643
- {
1644
- slug: "turtletime",
1645
- name: "TurtleTime",
1646
- description: "Time tracking",
1647
- icon: "/turtletime-icon.svg",
1648
- landing: "/tracker",
1649
- baseUrlEnv: "NEXT_PUBLIC_TURTLETIME_URL",
1650
- baseUrlFallback: "http://localhost:3000"
1651
- },
1652
- {
1653
- slug: "kraken",
1654
- name: "Kraken",
1655
- description: "Documents and knowledge",
1656
- icon: "/kraken-icon.svg",
1657
- landing: "/today",
1658
- baseUrlEnv: "NEXT_PUBLIC_KRAKEN_URL",
1659
- baseUrlFallback: "http://localhost:3003"
1660
- }
1661
- ];
1662
- var SUITE_APP_MAP = Object.fromEntries(SUITE_APPS2.map((app) => [app.slug, app]));
1663
- function suiteAppBaseUrl(slug) {
1664
- const def = SUITE_APP_MAP[slug];
1665
- const fromEnv = typeof process !== "undefined" ? process.env[def.baseUrlEnv] : void 0;
1666
- return (fromEnv || def.baseUrlFallback).replace(/\/$/, "");
1667
- }
1668
-
1669
2170
  // src/suite/components/today-calibrating.tsx
1670
2171
  var import_iconoir_react7 = require("iconoir-react");
1671
- var import_jsx_runtime15 = require("react/jsx-runtime");
2172
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1672
2173
  function TodayCalibrating({
1673
2174
  onRetry,
1674
2175
  retrying = false,
1675
2176
  className,
1676
2177
  spinner: Spinner,
1677
- variant = "ring",
2178
+ variant: _variant = "ring",
1678
2179
  retrySpinnerClassName = "text-ph-brand"
1679
2180
  }) {
1680
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2181
+ void _variant;
2182
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
1681
2183
  "div",
1682
2184
  {
1683
2185
  className: cn(
1684
- "relative flex min-h-[14rem] flex-col items-center justify-center overflow-hidden rounded-2xl border border-ph-border bg-ph-surface px-5 py-8 text-center shadow-sm",
2186
+ "suite-auth-handoff relative flex min-h-[14rem] flex-col items-center justify-center overflow-hidden rounded-2xl border border-ph-border bg-ph-surface px-5 py-8 text-center shadow-sm",
1685
2187
  className
1686
2188
  ),
1687
2189
  "data-test": "today-calibrating",
1688
2190
  children: [
1689
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2191
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1690
2192
  "div",
1691
2193
  {
1692
- className: "pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_50%_35%,rgba(251,191,36,0.12),transparent_55%)]",
2194
+ className: "pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_50%_35%,rgba(251,191,36,0.1),transparent_55%)]",
1693
2195
  "aria-hidden": true
1694
2196
  }
1695
2197
  ),
1696
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "relative mb-6 flex h-24 w-24 items-center justify-center", children: [
1697
- variant === "ring" ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
1698
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1699
- Spinner,
1700
- {
1701
- size: "lg",
1702
- className: "absolute inset-0 m-auto opacity-40",
1703
- label: "Loading today"
1704
- }
1705
- ),
1706
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1707
- "span",
1708
- {
1709
- className: "bg-ph-muted/30 absolute inset-2 animate-ping rounded-full",
1710
- "aria-hidden": true
1711
- }
1712
- )
1713
- ] }) : null,
1714
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "relative flex h-14 w-14 items-center justify-center rounded-2xl border border-ph-border bg-ph-surface text-ph-ink shadow-sm", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1715
- import_iconoir_react7.SunLight,
1716
- {
1717
- className: cn("h-9 w-9", variant === "pulse" && "animate-pulse"),
1718
- strokeWidth: 2,
1719
- "aria-hidden": true
1720
- }
1721
- ) })
1722
- ] }),
1723
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h2", { className: "relative text-base font-semibold tracking-tight text-ph-ink sm:text-lg md:text-xl", children: "Calibrating your day" }),
1724
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "relative mt-1.5 max-w-sm text-sm sm:text-[15px] leading-relaxed text-ph-subtle", children: "Pulling together tasks, time and updates from your workspace\u2026" }),
1725
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "relative mt-5 flex gap-1.5", "aria-hidden": true, children: [0, 1, 2, 3, 4].map((i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1726
- "span",
1727
- {
1728
- className: "h-1.5 w-5 animate-pulse rounded-full bg-ph-muted",
1729
- style: { animationDelay: `${i * 120}ms` }
1730
- },
1731
- i
1732
- )) }),
1733
- onRetry ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2198
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "relative mb-5 flex h-14 w-14 items-center justify-center rounded-2xl border border-ph-border bg-ph-surface text-ph-ink shadow-sm", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_iconoir_react7.SunLight, { className: "h-8 w-8", strokeWidth: 2, "aria-hidden": true }) }),
2199
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("h2", { className: "relative text-base font-semibold tracking-tight text-ph-ink sm:text-lg md:text-xl", children: "Calibrating your day" }),
2200
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "relative mt-1.5 max-w-sm text-sm sm:text-[15px] leading-relaxed text-ph-subtle", children: "Pulling together tasks, time and updates from your workspace\u2026" }),
2201
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "relative mt-5 flex justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Spinner, { size: "sm", className: "opacity-70", label: "Loading today" }) }),
2202
+ onRetry ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
1734
2203
  "button",
1735
2204
  {
1736
2205
  type: "button",
@@ -1738,7 +2207,7 @@ function TodayCalibrating({
1738
2207
  disabled: retrying,
1739
2208
  className: "relative mt-6 inline-flex items-center gap-2 rounded-xl border border-ph-border bg-ph-canvas px-4 py-2 text-sm font-medium text-ph-ink transition hover:bg-ph-muted disabled:opacity-60",
1740
2209
  children: [
1741
- retrying ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Spinner, { size: "sm", className: retrySpinnerClassName }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_iconoir_react7.Refresh, { className: "h-4 w-4", "aria-hidden": true }),
2210
+ retrying ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Spinner, { size: "sm", className: retrySpinnerClassName }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_iconoir_react7.Refresh, { className: "h-4 w-4", "aria-hidden": true }),
1742
2211
  "Try again"
1743
2212
  ]
1744
2213
  }
@@ -1749,9 +2218,9 @@ function TodayCalibrating({
1749
2218
  }
1750
2219
 
1751
2220
  // src/suite/components/theme-provider.tsx
1752
- var import_react6 = require("react");
1753
- var import_jsx_runtime16 = require("react/jsx-runtime");
1754
- var SuiteThemeContext = (0, import_react6.createContext)(null);
2221
+ var import_react7 = require("react");
2222
+ var import_jsx_runtime18 = require("react/jsx-runtime");
2223
+ var SuiteThemeContext = (0, import_react7.createContext)(null);
1755
2224
  function systemTheme(fallback) {
1756
2225
  if (typeof window === "undefined") return fallback;
1757
2226
  return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
@@ -1788,7 +2257,7 @@ function SuiteThemeProvider({
1788
2257
  config,
1789
2258
  children
1790
2259
  }) {
1791
- const [state, setState] = (0, import_react6.useState)(() => {
2260
+ const [state, setState] = (0, import_react7.useState)(() => {
1792
2261
  const theme2 = readStoredTheme(config.storageKey);
1793
2262
  if (typeof document === "undefined") {
1794
2263
  return { theme: theme2, resolvedTheme: config.fallbackTheme };
@@ -1798,7 +2267,7 @@ function SuiteThemeProvider({
1798
2267
  return { theme: theme2, resolvedTheme: resolvedTheme2 };
1799
2268
  });
1800
2269
  const { theme, resolvedTheme } = state;
1801
- (0, import_react6.useEffect)(() => {
2270
+ (0, import_react7.useEffect)(() => {
1802
2271
  if (theme !== "system") return;
1803
2272
  const media = window.matchMedia("(prefers-color-scheme: dark)");
1804
2273
  const update = () => {
@@ -1808,7 +2277,7 @@ function SuiteThemeProvider({
1808
2277
  media.addEventListener("change", update);
1809
2278
  return () => media.removeEventListener("change", update);
1810
2279
  }, [theme, config]);
1811
- const setTheme = (0, import_react6.useCallback)(
2280
+ const setTheme = (0, import_react7.useCallback)(
1812
2281
  (next) => {
1813
2282
  const resolved = applyTheme(next, config);
1814
2283
  setState({ theme: next, resolvedTheme: resolved });
@@ -1816,7 +2285,7 @@ function SuiteThemeProvider({
1816
2285
  },
1817
2286
  [config]
1818
2287
  );
1819
- const toggleTheme = (0, import_react6.useCallback)(() => {
2288
+ const toggleTheme = (0, import_react7.useCallback)(() => {
1820
2289
  setState((prev) => {
1821
2290
  const next = resolveTheme(prev.theme, config.fallbackTheme) === "dark" ? "light" : "dark";
1822
2291
  const resolved = applyTheme(next, config);
@@ -1824,52 +2293,119 @@ function SuiteThemeProvider({
1824
2293
  return { theme: next, resolvedTheme: resolved };
1825
2294
  });
1826
2295
  }, [config]);
1827
- const value = (0, import_react6.useMemo)(
2296
+ const value = (0, import_react7.useMemo)(
1828
2297
  () => ({ theme, resolvedTheme, setTheme, toggleTheme }),
1829
2298
  [theme, resolvedTheme, setTheme, toggleTheme]
1830
2299
  );
1831
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SuiteThemeContext.Provider, { value, children });
2300
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SuiteThemeContext.Provider, { value, children });
1832
2301
  }
1833
2302
  function useSuiteTheme() {
1834
- const ctx = (0, import_react6.useContext)(SuiteThemeContext);
2303
+ const ctx = (0, import_react7.useContext)(SuiteThemeContext);
1835
2304
  if (!ctx) throw new Error("useTheme must be used within ThemeProvider");
1836
2305
  return ctx;
1837
2306
  }
1838
2307
 
1839
2308
  // src/suite/components/ai-panel.tsx
1840
- var import_react7 = require("react");
2309
+ var import_react8 = require("react");
1841
2310
  var import_iconoir_react8 = require("iconoir-react");
1842
- var import_jsx_runtime17 = require("react/jsx-runtime");
2311
+ var import_jsx_runtime19 = require("react/jsx-runtime");
2312
+ var SUITE_OPEN_ASK_AI_EVENT = "shellstack:open-ask-ai";
2313
+ function openSuiteAskAi(detail) {
2314
+ if (typeof window === "undefined") return;
2315
+ window.dispatchEvent(
2316
+ new CustomEvent(SUITE_OPEN_ASK_AI_EVENT, {
2317
+ detail: detail != null ? detail : {}
2318
+ })
2319
+ );
2320
+ }
1843
2321
  function SuiteAiPanel({
1844
- presets,
1845
- emptyState,
1846
- fetchStatus,
1847
- complete,
2322
+ presets = [],
2323
+ emptyState = "Ask anything about your workspace, or look something up online.",
2324
+ title = "Ask AI",
2325
+ fetchChat,
2326
+ sendMessage,
2327
+ clearChat,
1848
2328
  brandIcon: BrandIcon,
1849
- spinner: Spinner
2329
+ spinner: Spinner,
2330
+ hideLauncher = false
1850
2331
  }) {
1851
- const [open, setOpen] = (0, import_react7.useState)(false);
1852
- const [prompt, setPrompt] = (0, import_react7.useState)("");
1853
- const [loading, setLoading] = (0, import_react7.useState)(false);
1854
- const [answer, setAnswer] = (0, import_react7.useState)("");
1855
- const [error, setError] = (0, import_react7.useState)("");
1856
- const [copied, setCopied] = (0, import_react7.useState)(false);
2332
+ const [open, setOpen] = (0, import_react8.useState)(false);
2333
+ const [prompt, setPrompt] = (0, import_react8.useState)("");
2334
+ const [messages, setMessages] = (0, import_react8.useState)([]);
2335
+ const [loading, setLoading] = (0, import_react8.useState)(false);
2336
+ const [hydrating, setHydrating] = (0, import_react8.useState)(false);
2337
+ const [error, setError] = (0, import_react8.useState)("");
2338
+ const [copiedId, setCopiedId] = (0, import_react8.useState)(null);
2339
+ const scrollerRef = (0, import_react8.useRef)(null);
2340
+ const pendingPromptRef = (0, import_react8.useRef)(null);
2341
+ const scrollToBottom = (0, import_react8.useCallback)(() => {
2342
+ const el = scrollerRef.current;
2343
+ if (!el) return;
2344
+ el.scrollTop = el.scrollHeight;
2345
+ }, []);
2346
+ const hydrate = (0, import_react8.useCallback)(async () => {
2347
+ var _a;
2348
+ setHydrating(true);
2349
+ setError("");
2350
+ try {
2351
+ const data = await fetchChat();
2352
+ setMessages((_a = data.messages) != null ? _a : []);
2353
+ if (!data.configured) {
2354
+ setError("ShellStack AI is not configured for this workspace yet.");
2355
+ }
2356
+ } catch (err) {
2357
+ setError(
2358
+ err instanceof Error ? err.message : "Could not load your Ask AI chat."
2359
+ );
2360
+ } finally {
2361
+ setHydrating(false);
2362
+ }
2363
+ }, [fetchChat]);
2364
+ (0, import_react8.useEffect)(() => {
2365
+ function onOpen(event) {
2366
+ var _a;
2367
+ const detail = event.detail;
2368
+ setOpen(true);
2369
+ if ((_a = detail == null ? void 0 : detail.prompt) == null ? void 0 : _a.trim()) {
2370
+ pendingPromptRef.current = detail.prompt.trim();
2371
+ setPrompt(detail.prompt.trim());
2372
+ }
2373
+ }
2374
+ window.addEventListener(SUITE_OPEN_ASK_AI_EVENT, onOpen);
2375
+ return () => window.removeEventListener(SUITE_OPEN_ASK_AI_EVENT, onOpen);
2376
+ }, []);
2377
+ (0, import_react8.useEffect)(() => {
2378
+ if (!open) return;
2379
+ void hydrate().then(() => {
2380
+ const pending = pendingPromptRef.current;
2381
+ pendingPromptRef.current = null;
2382
+ if (pending) {
2383
+ setPrompt(pending);
2384
+ }
2385
+ });
2386
+ }, [open, hydrate]);
2387
+ (0, import_react8.useEffect)(() => {
2388
+ if (open) scrollToBottom();
2389
+ }, [messages, loading, open, scrollToBottom]);
1857
2390
  async function ask(text) {
2391
+ var _a;
1858
2392
  const trimmed = text.trim();
1859
2393
  if (!trimmed || loading) return;
1860
2394
  setLoading(true);
1861
2395
  setError("");
1862
- setAnswer("");
1863
- setCopied(false);
2396
+ setPrompt("");
2397
+ setMessages((prev) => [...prev, { role: "user", content: trimmed }]);
1864
2398
  try {
1865
- const status = await fetchStatus();
1866
- if (!status.configured) {
1867
- setError("ShellStack AI is not configured for this workspace yet.");
1868
- return;
1869
- }
1870
- const result = await complete({ prompt: trimmed });
1871
- setAnswer(result.text);
2399
+ const result = await sendMessage({ prompt: trimmed });
2400
+ setMessages((_a = result.messages) != null ? _a : []);
1872
2401
  } catch (err) {
2402
+ setMessages(
2403
+ (prev) => {
2404
+ var _a2, _b;
2405
+ return ((_a2 = prev[prev.length - 1]) == null ? void 0 : _a2.role) === "user" && ((_b = prev[prev.length - 1]) == null ? void 0 : _b.content) === trimmed ? prev.slice(0, -1) : prev;
2406
+ }
2407
+ );
2408
+ setPrompt(trimmed);
1873
2409
  setError(
1874
2410
  err instanceof Error ? err.message : "The AI request failed. Try again."
1875
2411
  );
@@ -1877,133 +2413,278 @@ function SuiteAiPanel({
1877
2413
  setLoading(false);
1878
2414
  }
1879
2415
  }
1880
- async function copyAnswer() {
1881
- if (!answer) return;
2416
+ async function handleClear() {
2417
+ if (loading) return;
1882
2418
  try {
1883
- await navigator.clipboard.writeText(answer);
1884
- setCopied(true);
1885
- window.setTimeout(() => setCopied(false), 1500);
2419
+ await clearChat();
2420
+ setMessages([]);
2421
+ setError("");
2422
+ } catch (err) {
2423
+ setError(
2424
+ err instanceof Error ? err.message : "Could not clear this chat."
2425
+ );
2426
+ }
2427
+ }
2428
+ async function copyMessage(index, content) {
2429
+ try {
2430
+ await navigator.clipboard.writeText(content);
2431
+ setCopiedId(index);
2432
+ window.setTimeout(() => setCopiedId(null), 1500);
1886
2433
  } catch (e) {
1887
2434
  }
1888
2435
  }
1889
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
1890
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
2436
+ const Icon = BrandIcon != null ? BrandIcon : import_iconoir_react8.Sparks;
2437
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
2438
+ !hideLauncher ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
1891
2439
  "button",
1892
2440
  {
1893
2441
  type: "button",
1894
2442
  "data-test": "ai-panel-launcher",
1895
2443
  onClick: () => setOpen(true),
1896
2444
  className: "fixed bottom-5 right-5 z-30 flex items-center gap-2 rounded-full border border-ph-border bg-ph-surface px-4 py-2.5 text-sm font-medium text-ph-ink shadow-ph hover:bg-ph-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-brand",
1897
- "aria-label": "Open ShellStack AI",
2445
+ "aria-label": "Open Ask AI",
1898
2446
  children: [
1899
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(BrandIcon, { className: "h-4 w-4 text-ph-brand" }),
2447
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Icon, { className: "h-4 w-4 text-ph-brand" }),
1900
2448
  "Ask AI"
1901
2449
  ]
1902
2450
  }
1903
- ),
1904
- open && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "fixed inset-0 z-40", role: "dialog", "aria-modal": "true", children: [
1905
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2451
+ ) : null,
2452
+ open ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "fixed inset-0 z-40", role: "dialog", "aria-modal": "true", children: [
2453
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1906
2454
  "button",
1907
2455
  {
1908
2456
  type: "button",
1909
2457
  className: "absolute inset-0 bg-black/25",
1910
2458
  onClick: () => setOpen(false),
1911
- "aria-label": "Close AI panel"
2459
+ "aria-label": "Close Ask AI"
1912
2460
  }
1913
2461
  ),
1914
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("aside", { className: "absolute inset-y-0 right-0 flex w-full max-w-md flex-col border-l border-ph-border bg-ph-surface shadow-2xl", children: [
1915
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center justify-between border-b border-ph-border px-4 py-3", children: [
1916
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center gap-2", children: [
1917
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(BrandIcon, { className: "h-4 w-4 text-ph-brand" }),
1918
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "text-sm font-semibold text-ph-ink", children: "ShellStack AI" })
1919
- ] }),
1920
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1921
- "button",
1922
- {
1923
- type: "button",
1924
- onClick: () => setOpen(false),
1925
- className: "rounded p-1 hover:bg-ph-muted",
1926
- "aria-label": "Close",
1927
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_iconoir_react8.Xmark, { className: "h-4 w-4" })
1928
- }
1929
- )
1930
- ] }),
1931
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "flex flex-wrap gap-1.5 border-b border-ph-border px-4 py-2", children: presets.map((preset) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1932
- "button",
1933
- {
1934
- type: "button",
1935
- onClick: () => {
1936
- setPrompt(preset.prompt);
1937
- void ask(preset.prompt);
1938
- },
1939
- disabled: loading,
1940
- className: "rounded-md border border-ph-border px-2 py-1 text-xs text-ph-ink hover:bg-ph-muted disabled:opacity-50",
1941
- children: preset.label
1942
- },
1943
- preset.label
1944
- )) }),
1945
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex-1 space-y-3 overflow-y-auto p-4", children: [
1946
- error && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "bg-ph-danger/10 rounded-lg px-3 py-2 text-sm text-ph-danger", children: error }),
1947
- loading && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center gap-2 text-sm text-ph-mutedtext", children: [
1948
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Spinner, { className: "h-4 w-4 animate-spin" }),
1949
- "Thinking\u2026"
1950
- ] }),
1951
- answer && !loading && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "rounded-lg bg-ph-muted px-3 py-2 text-sm text-ph-ink", children: [
1952
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "whitespace-pre-wrap", children: answer }),
1953
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
2462
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
2463
+ "aside",
2464
+ {
2465
+ className: "absolute inset-y-0 right-0 flex w-full max-w-md flex-col border-l border-ph-border bg-ph-surface shadow-2xl",
2466
+ "data-test": "suite-ask-ai-panel",
2467
+ children: [
2468
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center justify-between border-b border-ph-border px-4 py-3", children: [
2469
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "min-w-0", children: [
2470
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-2", children: [
2471
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Icon, { className: "h-4 w-4 shrink-0 text-ph-brand" }),
2472
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-sm font-semibold text-ph-ink", children: title })
2473
+ ] }),
2474
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "mt-0.5 text-[11px] text-ph-mutedtext", children: "Shared across your suite \xB7 same chat in every app" })
2475
+ ] }),
2476
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-1", children: [
2477
+ messages.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2478
+ "button",
2479
+ {
2480
+ type: "button",
2481
+ onClick: () => void handleClear(),
2482
+ disabled: loading,
2483
+ className: "rounded-md px-2 py-1 text-xs text-ph-mutedtext hover:bg-ph-muted hover:text-ph-ink disabled:opacity-50",
2484
+ "data-test": "ask-ai-clear",
2485
+ children: "Clear"
2486
+ }
2487
+ ) : null,
2488
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2489
+ "button",
2490
+ {
2491
+ type: "button",
2492
+ onClick: () => setOpen(false),
2493
+ className: "rounded p-1 hover:bg-ph-muted",
2494
+ "aria-label": "Close",
2495
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_iconoir_react8.Xmark, { className: "h-4 w-4" })
2496
+ }
2497
+ )
2498
+ ] })
2499
+ ] }),
2500
+ presets.length > 0 && messages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "flex flex-wrap gap-1.5 border-b border-ph-border px-4 py-2", children: presets.map((preset) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1954
2501
  "button",
1955
2502
  {
1956
2503
  type: "button",
1957
- onClick: () => void copyAnswer(),
1958
- className: "mt-2 inline-flex items-center gap-1 text-xs text-ph-mutedtext hover:text-ph-ink",
2504
+ onClick: () => void ask(preset.prompt),
2505
+ disabled: loading || hydrating,
2506
+ className: "rounded-full border border-ph-border px-2.5 py-1 text-xs text-ph-ink hover:bg-ph-muted disabled:opacity-50",
2507
+ children: preset.label
2508
+ },
2509
+ preset.label
2510
+ )) }) : null,
2511
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
2512
+ "div",
2513
+ {
2514
+ ref: scrollerRef,
2515
+ className: "flex-1 space-y-3 overflow-y-auto p-4",
1959
2516
  children: [
1960
- copied ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_iconoir_react8.Check, { className: "h-3 w-3" }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_iconoir_react8.Copy, { className: "h-3 w-3" }),
1961
- copied ? "Copied" : "Copy"
2517
+ error ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "bg-ph-danger/10 rounded-lg px-3 py-2 text-sm text-ph-danger", children: error }) : null,
2518
+ hydrating && messages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-2 text-sm text-ph-mutedtext", children: [
2519
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Spinner, { className: "h-4 w-4 animate-spin" }),
2520
+ "Loading chat\u2026"
2521
+ ] }) : null,
2522
+ !hydrating && messages.length === 0 && !error ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "mt-10 px-2 text-center", children: [
2523
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "font-display text-base font-semibold text-ph-ink", children: "How can I help?" }),
2524
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "mt-2 text-sm leading-relaxed text-ph-subtle", children: emptyState })
2525
+ ] }) : null,
2526
+ messages.map((message, index) => {
2527
+ const isUser = message.role === "user";
2528
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
2529
+ "div",
2530
+ {
2531
+ className: isUser ? "ml-8 rounded-2xl bg-ph-brand/10 px-3.5 py-2.5 text-sm text-ph-ink" : "mr-4 rounded-2xl bg-ph-muted px-3.5 py-2.5 text-sm text-ph-ink",
2532
+ "data-test": isUser ? "ask-ai-user" : "ask-ai-assistant",
2533
+ children: [
2534
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "whitespace-pre-wrap", children: message.content }),
2535
+ !isUser ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
2536
+ "button",
2537
+ {
2538
+ type: "button",
2539
+ onClick: () => void copyMessage(index, message.content),
2540
+ className: "mt-2 inline-flex items-center gap-1 text-xs text-ph-mutedtext hover:text-ph-ink",
2541
+ children: [
2542
+ copiedId === index ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_iconoir_react8.Check, { className: "h-3 w-3" }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_iconoir_react8.Copy, { className: "h-3 w-3" }),
2543
+ copiedId === index ? "Copied" : "Copy"
2544
+ ]
2545
+ }
2546
+ ) : null
2547
+ ]
2548
+ },
2549
+ `${message.role}-${index}-${message.content.slice(0, 24)}`
2550
+ );
2551
+ }),
2552
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex items-center gap-2 text-sm text-ph-mutedtext", children: [
2553
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Spinner, { className: "h-4 w-4 animate-spin" }),
2554
+ "Thinking\u2026"
2555
+ ] }) : null
1962
2556
  ]
1963
2557
  }
1964
- )
1965
- ] }),
1966
- !answer && !loading && !error && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "mt-8 text-center text-xs text-ph-mutedtext", children: emptyState })
1967
- ] }),
1968
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "border-t border-ph-border p-3", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex gap-2", children: [
1969
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1970
- "textarea",
1971
- {
1972
- value: prompt,
1973
- onChange: (e) => setPrompt(e.target.value),
1974
- onKeyDown: (e) => {
1975
- if (e.key === "Enter" && !e.shiftKey) {
1976
- e.preventDefault();
1977
- void ask(prompt);
2558
+ ),
2559
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "border-t border-ph-border p-3", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex gap-2", children: [
2560
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2561
+ "textarea",
2562
+ {
2563
+ value: prompt,
2564
+ onChange: (e) => setPrompt(e.target.value),
2565
+ onKeyDown: (e) => {
2566
+ if (e.key === "Enter" && !e.shiftKey) {
2567
+ e.preventDefault();
2568
+ void ask(prompt);
2569
+ }
2570
+ },
2571
+ placeholder: "Ask anything\u2026",
2572
+ rows: 2,
2573
+ disabled: loading,
2574
+ "data-test": "ask-ai-input",
2575
+ className: "flex-1 resize-none rounded-xl border border-ph-border bg-ph-canvas p-2.5 text-sm text-ph-ink outline-none focus:ring-1 focus:ring-ph-brand"
1978
2576
  }
1979
- },
1980
- placeholder: "Ask anything\u2026",
1981
- rows: 2,
1982
- disabled: loading,
1983
- className: "flex-1 resize-none rounded-lg border border-ph-border bg-ph-canvas p-2 text-sm text-ph-ink outline-none focus:ring-1 focus:ring-ph-brand"
1984
- }
1985
- ),
1986
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1987
- "button",
1988
- {
1989
- type: "button",
1990
- onClick: () => void ask(prompt),
1991
- disabled: loading || !prompt.trim(),
1992
- className: "self-end rounded-lg bg-ph-brand px-3 py-2 text-sm font-medium text-white disabled:opacity-50",
1993
- children: "Ask"
1994
- }
1995
- )
1996
- ] }) })
1997
- ] })
1998
- ] })
2577
+ ),
2578
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2579
+ "button",
2580
+ {
2581
+ type: "button",
2582
+ onClick: () => void ask(prompt),
2583
+ disabled: loading || !prompt.trim(),
2584
+ "data-test": "ask-ai-send",
2585
+ className: "self-end rounded-xl bg-ph-brand px-3.5 py-2 text-sm font-medium text-white disabled:opacity-50",
2586
+ children: "Ask"
2587
+ }
2588
+ )
2589
+ ] }) })
2590
+ ]
2591
+ }
2592
+ )
2593
+ ] }) : null
1999
2594
  ] });
2000
2595
  }
2001
2596
 
2597
+ // src/suite/lib/use-sidebar-width.ts
2598
+ var import_react9 = require("react");
2599
+ var SIDEBAR_RAIL_WIDTH = 56;
2600
+ var SIDEBAR_COLLAPSE_THRESHOLD = 80;
2601
+ var SIDEBAR_MIN_EXPANDED_WIDTH = 180;
2602
+ var SIDEBAR_MAX_WIDTH = 320;
2603
+ var SIDEBAR_DEFAULT_WIDTH = 320;
2604
+ function clampWidth(width) {
2605
+ return Math.min(SIDEBAR_MAX_WIDTH, Math.max(SIDEBAR_RAIL_WIDTH, width));
2606
+ }
2607
+ function snapWidth(width) {
2608
+ if (width <= SIDEBAR_COLLAPSE_THRESHOLD) return SIDEBAR_RAIL_WIDTH;
2609
+ if (width < SIDEBAR_MIN_EXPANDED_WIDTH) return SIDEBAR_MIN_EXPANDED_WIDTH;
2610
+ return Math.min(SIDEBAR_MAX_WIDTH, width);
2611
+ }
2612
+ function useSidebarWidth(storageKey) {
2613
+ const [width, setWidth] = (0, import_react9.useState)(SIDEBAR_DEFAULT_WIDTH);
2614
+ const [narrowViewport, setNarrowViewport] = (0, import_react9.useState)(false);
2615
+ const collapsed = narrowViewport || width <= SIDEBAR_COLLAPSE_THRESHOLD;
2616
+ (0, import_react9.useEffect)(() => {
2617
+ let stored = null;
2618
+ try {
2619
+ stored = localStorage.getItem(storageKey);
2620
+ } catch (e) {
2621
+ }
2622
+ if (!stored) return;
2623
+ const parsed = Number.parseInt(stored, 10);
2624
+ if (!Number.isNaN(parsed)) {
2625
+ queueMicrotask(() => setWidth(snapWidth(clampWidth(parsed))));
2626
+ }
2627
+ }, [storageKey]);
2628
+ (0, import_react9.useEffect)(() => {
2629
+ const media = window.matchMedia("(max-width: 639px)");
2630
+ const sync = () => setNarrowViewport(media.matches);
2631
+ sync();
2632
+ media.addEventListener("change", sync);
2633
+ return () => media.removeEventListener("change", sync);
2634
+ }, []);
2635
+ const persist = (0, import_react9.useCallback)(
2636
+ (value) => {
2637
+ try {
2638
+ localStorage.setItem(storageKey, String(value));
2639
+ } catch (e) {
2640
+ }
2641
+ },
2642
+ [storageKey]
2643
+ );
2644
+ const setCollapsed = (0, import_react9.useCallback)(
2645
+ (value) => {
2646
+ setWidth((current) => {
2647
+ const next = value ? SIDEBAR_RAIL_WIDTH : current <= SIDEBAR_COLLAPSE_THRESHOLD ? SIDEBAR_DEFAULT_WIDTH : snapWidth(current);
2648
+ persist(next);
2649
+ return next;
2650
+ });
2651
+ },
2652
+ [persist]
2653
+ );
2654
+ const resetWidth = (0, import_react9.useCallback)(() => {
2655
+ setWidth(SIDEBAR_DEFAULT_WIDTH);
2656
+ persist(SIDEBAR_DEFAULT_WIDTH);
2657
+ }, [persist]);
2658
+ const startResize = (0, import_react9.useCallback)(
2659
+ (event) => {
2660
+ event.preventDefault();
2661
+ const startX = event.clientX;
2662
+ const startWidth = width;
2663
+ const onMove = (moveEvent) => {
2664
+ setWidth(clampWidth(startWidth + moveEvent.clientX - startX));
2665
+ };
2666
+ const onUp = () => {
2667
+ document.removeEventListener("pointermove", onMove);
2668
+ document.removeEventListener("pointerup", onUp);
2669
+ setWidth((current) => {
2670
+ const snapped = snapWidth(current);
2671
+ persist(snapped);
2672
+ return snapped;
2673
+ });
2674
+ };
2675
+ document.addEventListener("pointermove", onMove);
2676
+ document.addEventListener("pointerup", onUp);
2677
+ },
2678
+ [persist, width]
2679
+ );
2680
+ return { width, collapsed, setCollapsed, resetWidth, startResize };
2681
+ }
2682
+
2002
2683
  // src/suite/lib/motion.tsx
2003
- var import_react8 = require("motion/react");
2004
- var import_jsx_runtime18 = require("react/jsx-runtime");
2684
+ var import_react10 = require("motion/react");
2685
+ var import_jsx_runtime20 = require("react/jsx-runtime");
2005
2686
  function SuiteMotionProvider({ children }) {
2006
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react8.LazyMotion, { features: import_react8.domAnimation, strict: true, children });
2687
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react10.LazyMotion, { features: import_react10.domAnimation, strict: true, children });
2007
2688
  }
2008
2689
  var SUITE_SPRINGS = {
2009
2690
  /** Snappy panel/sheet entrances — small overshoot. */
@@ -2014,217 +2695,25 @@ var SUITE_SPRINGS = {
2014
2695
  press: { type: "spring", stiffness: 600, damping: 35, mass: 0.5 }
2015
2696
  };
2016
2697
 
2017
- // src/suite/components/suite-layout.tsx
2018
- var import_jsx_runtime19 = require("react/jsx-runtime");
2019
- var WIDTHS = {
2020
- full: "max-w-none",
2021
- wide: "max-w-7xl",
2022
- content: "max-w-6xl",
2023
- narrow: "max-w-4xl"
2024
- };
2025
- function SuiteBreadcrumbs({ items, className }) {
2026
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("nav", { "aria-label": "Breadcrumb", className, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("ol", { className: "flex min-w-0 items-center gap-1.5", children: items.map((item, index) => {
2027
- const isLast = index === items.length - 1;
2028
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("li", { className: "flex min-w-0 items-center gap-1.5", children: [
2029
- index > 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "select-none text-ph-border", "aria-hidden": "true", children: "/" }) : null,
2030
- item.href && !isLast ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2031
- "a",
2032
- {
2033
- href: item.href,
2034
- className: "truncate transition hover:text-ph-ink",
2035
- children: item.label
2036
- }
2037
- ) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2038
- "span",
2039
- {
2040
- className: cn(
2041
- "truncate",
2042
- isLast ? "font-medium text-ph-ink" : "text-ph-subtle"
2043
- ),
2044
- "aria-current": isLast ? "page" : void 0,
2045
- children: item.label
2046
- }
2047
- )
2048
- ] }, index);
2049
- }) }) });
2050
- }
2051
- function SuitePage({
2052
- children,
2053
- width = "wide",
2054
- inset = true,
2055
- className,
2056
- as: Component = "div",
2057
- dataTest,
2058
- id,
2059
- role,
2060
- "aria-live": ariaLive
2061
- }) {
2062
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2063
- Component,
2064
- {
2065
- id,
2066
- "data-test": dataTest,
2067
- role,
2068
- "aria-live": ariaLive,
2069
- className: cn(
2070
- "mx-auto flex w-full min-w-0 flex-col",
2071
- WIDTHS[width],
2072
- // Tight inset keeps page titles aligned without excessive whitespace.
2073
- inset && "px-4 pb-5 pt-2 sm:px-6 sm:pb-6 sm:pt-3 lg:px-8",
2074
- className
2075
- ),
2076
- children
2077
- }
2078
- );
2079
- }
2080
- function SuitePageHeader({
2081
- title,
2082
- description,
2083
- eyebrow,
2084
- actions,
2085
- className,
2086
- titleClassName,
2087
- dataTest,
2088
- /** Optional icon rendered before the title. */
2089
- icon,
2090
- /** Use the animated sun/moon icon from the Today page. */
2091
- todayIcon,
2092
- todayIconClassName,
2093
- /** Small badge/pill next to the title (e.g. "Beta", org name). */
2094
- badge,
2095
- /** Breadcrumb line rendered above the title. */
2096
- breadcrumb
2097
- }) {
2098
- const resolvedIcon = todayIcon ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2099
- TodayTimeIcon,
2100
- {
2101
- className: cn(
2102
- "h-6 w-6 sm:h-7 sm:w-7 text-amber-500",
2103
- todayIconClassName
2104
- )
2105
- }
2106
- ) : icon;
2107
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
2108
- "header",
2109
- {
2110
- "data-test": dataTest,
2111
- className: cn(
2112
- "flex items-start justify-between gap-4 pb-2 sm:pb-3",
2113
- className
2114
- ),
2115
- children: [
2116
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex min-w-0 items-start gap-3", children: [
2117
- resolvedIcon ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2118
- "div",
2119
- {
2120
- className: "hidden shrink-0 pt-1 sm:block",
2121
- "aria-hidden": "true",
2122
- children: resolvedIcon
2123
- }
2124
- ) : null,
2125
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex min-w-0 flex-col gap-1", children: [
2126
- eyebrow ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "mb-0.5 flex min-w-0 items-center gap-1.5 text-xs text-ph-subtle", children: eyebrow }) : null,
2127
- breadcrumb ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "mb-0.5 flex min-w-0 items-center gap-1.5 text-xs text-ph-subtle", children: breadcrumb }) : null,
2128
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1", children: [
2129
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2130
- "h1",
2131
- {
2132
- className: cn(
2133
- "font-display text-[1.625rem] font-bold leading-tight tracking-tight text-ph-ink sm:text-[2.25rem]",
2134
- titleClassName
2135
- ),
2136
- children: title
2137
- }
2138
- ),
2139
- badge ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "rounded-md bg-ph-muted px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wide text-ph-subtle", children: badge }) : null
2140
- ] }),
2141
- description ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "mt-1 max-w-2xl text-pretty text-sm leading-5 text-ph-subtle", children: description }) : null
2142
- ] })
2143
- ] }),
2144
- actions ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "flex shrink-0 items-center gap-2 pt-1", children: actions }) : null
2145
- ]
2146
- }
2147
- );
2148
- }
2149
- function SuiteToolbar({
2150
- children,
2151
- className,
2152
- label = "Page tools",
2153
- dataTest
2154
- }) {
2155
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2156
- "div",
2157
- {
2158
- role: "toolbar",
2159
- "aria-label": label,
2160
- "data-test": dataTest,
2161
- className: cn("flex min-w-0 flex-wrap items-center gap-2", className),
2162
- children
2163
- }
2164
- );
2165
- }
2166
- function SuiteTabList({
2167
- children,
2168
- className,
2169
- label,
2170
- dataTest
2171
- }) {
2172
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2173
- "nav",
2174
- {
2175
- "aria-label": label,
2176
- "data-test": dataTest,
2177
- className: cn(
2178
- "flex min-w-0 flex-wrap gap-2 [&_a]:min-h-[48px] [&_button]:min-h-[48px] sm:[&_a]:min-h-[44px] sm:[&_button]:min-h-[44px]",
2179
- className
2180
- ),
2181
- children
2182
- }
2183
- );
2184
- }
2185
- function SuiteSectionHeader({
2186
- title,
2187
- description,
2188
- action,
2189
- className
2190
- }) {
2191
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
2192
- "div",
2193
- {
2194
- className: cn(
2195
- "flex min-w-0 flex-col gap-4 sm:flex-row sm:items-end sm:justify-between",
2196
- className
2197
- ),
2198
- children: [
2199
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "min-w-0", children: [
2200
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("h2", { className: "font-display text-balance text-lg font-semibold tracking-tight text-ph-ink sm:text-xl", children: title }),
2201
- description ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "mt-1 max-w-2xl text-pretty text-sm leading-5 text-ph-subtle", children: description }) : null
2202
- ] }),
2203
- action ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "flex min-h-[44px] shrink-0 items-center", children: action }) : null
2204
- ]
2205
- }
2206
- );
2207
- }
2208
-
2209
2698
  // src/suite/components/suite-skeleton.tsx
2210
- var import_jsx_runtime20 = require("react/jsx-runtime");
2699
+ var import_jsx_runtime21 = require("react/jsx-runtime");
2211
2700
  function SuiteSkeleton({
2212
2701
  className,
2213
2702
  lines = 1,
2214
2703
  circle,
2215
2704
  width
2216
2705
  }) {
2217
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2706
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2218
2707
  "div",
2219
2708
  {
2220
2709
  className: cn("space-y-2", circle ? "flex flex-col items-center" : ""),
2221
2710
  "aria-hidden": true,
2222
- children: Array.from({ length: lines }).map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2711
+ children: Array.from({ length: lines }).map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2223
2712
  "div",
2224
2713
  {
2225
2714
  className: "animate-[skeleton-stagger_0.6s_ease-out_both]",
2226
2715
  style: { animationDelay: `${index * 80}ms` },
2227
- children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2716
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2228
2717
  "div",
2229
2718
  {
2230
2719
  className: cn(
@@ -2248,35 +2737,35 @@ function SuiteSkeletonCard({
2248
2737
  rows = 3,
2249
2738
  header = true
2250
2739
  }) {
2251
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
2740
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
2252
2741
  "div",
2253
2742
  {
2254
2743
  className: cn(
2255
- "ph-skeleton-card animate-[skeleton-stagger_0.5s_ease-out_both] rounded-2xl border border-ph-border/70 bg-ph-surface p-6 shadow-sm",
2744
+ "ph-skeleton-card animate-[skeleton-stagger_0.5s_ease-out_both] rounded-2xl border border-ph-border bg-ph-surface p-6 shadow-sm",
2256
2745
  className
2257
2746
  ),
2258
2747
  "aria-hidden": true,
2259
2748
  children: [
2260
- header ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
2749
+ header ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
2261
2750
  "div",
2262
2751
  {
2263
2752
  className: "mb-5 flex items-center gap-3 animate-[skeleton-stagger_0.5s_ease-out_both]",
2264
2753
  style: { animationDelay: "100ms" },
2265
2754
  children: [
2266
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "ph-skeleton h-10 w-10 rounded-xl" }),
2267
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex-1 space-y-2", children: [
2268
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "ph-skeleton h-4 w-1/3" }),
2269
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "ph-skeleton h-3 w-1/2" })
2755
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "ph-skeleton h-10 w-10 rounded-xl" }),
2756
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex-1 space-y-2", children: [
2757
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "ph-skeleton h-4 w-1/3" }),
2758
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "ph-skeleton h-3 w-1/2" })
2270
2759
  ] })
2271
2760
  ]
2272
2761
  }
2273
2762
  ) : null,
2274
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "space-y-3", children: Array.from({ length: rows }).map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2763
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "space-y-3", children: Array.from({ length: rows }).map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2275
2764
  "div",
2276
2765
  {
2277
2766
  className: "animate-[skeleton-stagger_0.5s_ease-out_both]",
2278
2767
  style: { animationDelay: `${200 + index * 80}ms` },
2279
- children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2768
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2280
2769
  "div",
2281
2770
  {
2282
2771
  className: "ph-skeleton h-3",
@@ -2294,16 +2783,16 @@ function SuiteSkeletonList({
2294
2783
  className,
2295
2784
  items = 4
2296
2785
  }) {
2297
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: cn("space-y-3", className), "aria-hidden": true, children: Array.from({ length: items }).map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2786
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: cn("space-y-3", className), "aria-hidden": true, children: Array.from({ length: items }).map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2298
2787
  "div",
2299
2788
  {
2300
2789
  className: "animate-[skeleton-stagger_0.6s_ease-out_both]",
2301
2790
  style: { animationDelay: `${index * 100}ms` },
2302
- children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-3 rounded-xl border border-ph-border/60 bg-ph-surface p-4", children: [
2303
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "ph-skeleton h-10 w-10 rounded-lg" }),
2304
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "min-w-0 flex-1 space-y-2", children: [
2305
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "ph-skeleton h-3.5 w-3/4" }),
2306
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "ph-skeleton h-3 w-1/2" })
2791
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-3 rounded-xl border border-ph-border bg-ph-surface p-4", children: [
2792
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "ph-skeleton h-10 w-10 rounded-lg" }),
2793
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "min-w-0 flex-1 space-y-2", children: [
2794
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "ph-skeleton h-3.5 w-3/4" }),
2795
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "ph-skeleton h-3 w-1/2" })
2307
2796
  ] })
2308
2797
  ] })
2309
2798
  },
@@ -2318,22 +2807,22 @@ function SuiteEmptyState({
2318
2807
  className,
2319
2808
  size = "md"
2320
2809
  }) {
2321
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
2810
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
2322
2811
  "div",
2323
2812
  {
2324
2813
  className: cn(
2325
- "relative overflow-hidden rounded-2xl border border-ph-border/80 bg-ph-surface text-center",
2814
+ "relative overflow-hidden rounded-2xl border border-ph-border bg-ph-surface text-center",
2326
2815
  size === "sm" ? "px-5 py-8" : "px-6 py-12 sm:px-10 sm:py-16",
2327
2816
  className
2328
2817
  ),
2329
2818
  children: [
2330
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "pointer-events-none absolute inset-0 overflow-hidden opacity-60", "aria-hidden": true, children: [
2331
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "absolute -left-10 -top-10 h-40 w-40 rounded-full bg-ph-brand/10 blur-3xl" }),
2332
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "absolute -bottom-10 -right-10 h-40 w-40 rounded-full bg-ph-accent/10 blur-3xl" })
2819
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "pointer-events-none absolute inset-0 overflow-hidden opacity-60", "aria-hidden": true, children: [
2820
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "absolute -left-10 -top-10 h-40 w-40 rounded-full bg-ph-brand/10 blur-3xl" }),
2821
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "absolute -bottom-10 -right-10 h-40 w-40 rounded-full bg-ph-accent/10 blur-3xl" })
2333
2822
  ] }),
2334
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "relative", children: [
2335
- icon ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "mx-auto mb-4 inline-flex items-center justify-center rounded-2xl bg-ph-muted p-3 shadow-sm ring-1 ring-black/[0.06]", children: icon }) : null,
2336
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2823
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "relative", children: [
2824
+ icon ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "mx-auto mb-4 inline-flex items-center justify-center rounded-2xl bg-ph-muted p-3 shadow-sm ring-1 ring-black/[0.06]", children: icon }) : null,
2825
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2337
2826
  "h3",
2338
2827
  {
2339
2828
  className: cn(
@@ -2343,8 +2832,8 @@ function SuiteEmptyState({
2343
2832
  children: title
2344
2833
  }
2345
2834
  ),
2346
- description ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "mx-auto mt-2 max-w-sm text-sm leading-relaxed text-ph-subtle", children: description }) : null,
2347
- action ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "mt-5 flex flex-wrap items-center justify-center gap-2", children: action }) : null
2835
+ description ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "mx-auto mt-2 max-w-sm text-sm leading-relaxed text-ph-subtle", children: description }) : null,
2836
+ action ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "mt-5 flex flex-wrap items-center justify-center gap-2", children: action }) : null
2348
2837
  ] })
2349
2838
  ]
2350
2839
  }
@@ -2352,24 +2841,26 @@ function SuiteEmptyState({
2352
2841
  }
2353
2842
 
2354
2843
  // src/suite/components/suite-settings-mobile-nav.tsx
2355
- var import_react9 = require("react");
2356
- var import_jsx_runtime21 = require("react/jsx-runtime");
2844
+ var import_react11 = require("react");
2845
+ var import_jsx_runtime22 = require("react/jsx-runtime");
2357
2846
  function SuiteSettingsMobileNav({
2358
2847
  items,
2359
2848
  activeHref,
2360
2849
  onSelect,
2361
- dataTest
2850
+ dataTest,
2851
+ ariaLabel = "Settings sections",
2852
+ className
2362
2853
  }) {
2363
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2854
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2364
2855
  "nav",
2365
2856
  {
2366
2857
  "data-test": dataTest,
2367
- "aria-label": "Settings sections",
2368
- className: "-mx-4 px-4 lg:hidden",
2369
- children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex snap-x gap-2 overflow-x-auto pb-3 pt-1 scrollbar-hide [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", children: items.map((item) => {
2858
+ "aria-label": ariaLabel,
2859
+ className: cn("suite-settings-mobile-nav lg:hidden", className),
2860
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "flex snap-x gap-2 overflow-x-auto pb-3 pt-1 scrollbar-hide [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", children: items.map((item) => {
2370
2861
  const Icon = item.icon;
2371
2862
  const active = activeHref === item.href || activeHref.startsWith(`${item.href}/`);
2372
- const iconNode = (0, import_react9.isValidElement)(item.icon) ? item.icon : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2863
+ const iconNode = (0, import_react11.isValidElement)(item.icon) ? item.icon : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2373
2864
  Icon,
2374
2865
  {
2375
2866
  className: cn(
@@ -2379,7 +2870,7 @@ function SuiteSettingsMobileNav({
2379
2870
  "aria-hidden": true
2380
2871
  }
2381
2872
  );
2382
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
2873
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
2383
2874
  "button",
2384
2875
  {
2385
2876
  type: "button",
@@ -2387,14 +2878,14 @@ function SuiteSettingsMobileNav({
2387
2878
  onClick: () => onSelect(item.href),
2388
2879
  "aria-current": active ? "page" : void 0,
2389
2880
  className: cn(
2390
- "group relative flex shrink-0 snap-start items-center gap-2 rounded-full px-3.5 py-2.5 text-sm font-medium transition",
2881
+ "group relative flex shrink-0 snap-start items-center gap-2 rounded-full px-3.5 py-2.5 text-sm font-medium transition-colors",
2391
2882
  "min-h-[44px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-brand",
2392
2883
  active ? "bg-ph-ink text-ph-surface shadow-sm" : "bg-ph-surface text-ph-subtle ring-1 ring-ph-border hover:bg-ph-muted hover:text-ph-ink"
2393
2884
  ),
2394
2885
  children: [
2395
2886
  iconNode,
2396
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "whitespace-nowrap", children: item.label }),
2397
- active ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "absolute inset-x-0 -bottom-3 h-0.5 rounded-full bg-ph-ink lg:hidden" }) : null
2887
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "whitespace-nowrap", children: item.label }),
2888
+ active ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "absolute inset-x-0 -bottom-3 h-0.5 rounded-full bg-ph-ink lg:hidden" }) : null
2398
2889
  ]
2399
2890
  },
2400
2891
  item.href
@@ -2408,10 +2899,10 @@ function SuiteSettingsMobileNav({
2408
2899
  var import_link2 = __toESM(require("next/link"));
2409
2900
 
2410
2901
  // src/components/ui/Tooltip.tsx
2411
- var import_react10 = require("react");
2902
+ var import_react12 = require("react");
2412
2903
  var import_react_dom = require("react-dom");
2413
- var import_jsx_runtime22 = require("react/jsx-runtime");
2414
- var TooltipDelayContext = (0, import_react10.createContext)(0);
2904
+ var import_jsx_runtime23 = require("react/jsx-runtime");
2905
+ var TooltipDelayContext = (0, import_react12.createContext)(0);
2415
2906
  function tooltipPosition(trigger, side, align, offset) {
2416
2907
  const horizontal = align === "start" ? trigger.left : align === "end" ? trigger.right : trigger.left + trigger.width / 2;
2417
2908
  const vertical = align === "start" ? trigger.top : align === "end" ? trigger.bottom : trigger.top + trigger.height / 2;
@@ -2451,12 +2942,12 @@ function Tooltip({
2451
2942
  onOpenChange,
2452
2943
  delayDuration
2453
2944
  }) {
2454
- const providerDelay = (0, import_react10.useContext)(TooltipDelayContext);
2455
- const generatedId = (0, import_react10.useId)().replace(/:/g, "");
2456
- const triggerRef = (0, import_react10.useRef)(null);
2457
- const timerRef = (0, import_react10.useRef)(null);
2458
- const [internalOpen, setInternalOpen] = (0, import_react10.useState)(defaultOpen);
2459
- const [position, setPosition] = (0, import_react10.useState)(null);
2945
+ const providerDelay = (0, import_react12.useContext)(TooltipDelayContext);
2946
+ const generatedId = (0, import_react12.useId)().replace(/:/g, "");
2947
+ const triggerRef = (0, import_react12.useRef)(null);
2948
+ const timerRef = (0, import_react12.useRef)(null);
2949
+ const [internalOpen, setInternalOpen] = (0, import_react12.useState)(defaultOpen);
2950
+ const [position, setPosition] = (0, import_react12.useState)(null);
2460
2951
  const isOpen = open != null ? open : internalOpen;
2461
2952
  const triggerId = children.props.id;
2462
2953
  const tooltipId = triggerId ? `${triggerId}-tooltip` : `ph-tooltip-${generatedId}`;
@@ -2490,7 +2981,7 @@ function Tooltip({
2490
2981
  clearTimer();
2491
2982
  setOpen(false);
2492
2983
  }
2493
- (0, import_react10.useEffect)(() => {
2984
+ (0, import_react12.useEffect)(() => {
2494
2985
  if (!isOpen) return;
2495
2986
  const reposition = () => updatePosition();
2496
2987
  window.addEventListener("resize", reposition);
@@ -2500,11 +2991,11 @@ function Tooltip({
2500
2991
  window.removeEventListener("scroll", reposition, true);
2501
2992
  };
2502
2993
  });
2503
- (0, import_react10.useEffect)(() => () => clearTimer(), []);
2994
+ (0, import_react12.useEffect)(() => () => clearTimer(), []);
2504
2995
  const describedBy = [children.props["aria-describedby"], tooltipId].filter(Boolean).join(" ");
2505
- const trigger = (0, import_react10.cloneElement)(children, { "aria-describedby": describedBy });
2506
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
2507
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2996
+ const trigger = (0, import_react12.cloneElement)(children, { "aria-describedby": describedBy });
2997
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
2998
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2508
2999
  "span",
2509
3000
  {
2510
3001
  ref: triggerRef,
@@ -2520,12 +3011,12 @@ function Tooltip({
2520
3011
  }
2521
3012
  ),
2522
3013
  isOpen && position && typeof document !== "undefined" ? (0, import_react_dom.createPortal)(
2523
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3014
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2524
3015
  "span",
2525
3016
  {
2526
3017
  style: __spreadValues({ position: "fixed" }, position),
2527
3018
  className: "pointer-events-none z-[200]",
2528
- children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3019
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2529
3020
  "span",
2530
3021
  {
2531
3022
  id: tooltipId,
@@ -2543,7 +3034,7 @@ function Tooltip({
2543
3034
  }
2544
3035
 
2545
3036
  // src/suite/components/suite-sidebar.tsx
2546
- var import_jsx_runtime23 = require("react/jsx-runtime");
3037
+ var import_jsx_runtime24 = require("react/jsx-runtime");
2547
3038
  function renderNode(node, collapsed) {
2548
3039
  if (typeof node === "function") return node(collapsed);
2549
3040
  return node;
@@ -2560,7 +3051,7 @@ function SuiteSidebar({
2560
3051
  className,
2561
3052
  surface = false
2562
3053
  }) {
2563
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
3054
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
2564
3055
  "div",
2565
3056
  {
2566
3057
  className: cn(
@@ -2569,7 +3060,7 @@ function SuiteSidebar({
2569
3060
  className
2570
3061
  ),
2571
3062
  children: [
2572
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
3063
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
2573
3064
  "div",
2574
3065
  {
2575
3066
  className: cn(
@@ -2578,12 +3069,12 @@ function SuiteSidebar({
2578
3069
  collapsed ? "flex-col items-center gap-1 px-1 py-2" : "h-14 items-center justify-between gap-2 px-3"
2579
3070
  ),
2580
3071
  children: [
2581
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: cn("min-w-0", collapsed ? "shrink-0" : "flex-1"), children: renderNode(appSwitcher, collapsed) }),
2582
- collapsed ? null : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "shrink-0", children: renderNode(notificationBell, collapsed) })
3072
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: cn("min-w-0", collapsed ? "shrink-0" : "flex-1"), children: renderNode(appSwitcher, collapsed) }),
3073
+ collapsed ? null : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "shrink-0", children: renderNode(notificationBell, collapsed) })
2583
3074
  ]
2584
3075
  }
2585
3076
  ),
2586
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
3077
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
2587
3078
  "div",
2588
3079
  {
2589
3080
  className: cn(
@@ -2592,17 +3083,17 @@ function SuiteSidebar({
2592
3083
  collapsed ? "px-1.5 py-2" : "p-2"
2593
3084
  ),
2594
3085
  children: [
2595
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
3086
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
2596
3087
  "nav",
2597
3088
  {
2598
3089
  "aria-label": "Pages",
2599
3090
  className: "shrink-0 space-y-0.5",
2600
3091
  children: [
2601
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: cn("mb-3", collapsed && "flex justify-center"), children: renderNode(contextSwitcher, collapsed) }),
2602
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "space-y-0.5", children: navItems.map((item) => {
3092
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: cn("mb-3", collapsed && "flex justify-center"), children: renderNode(contextSwitcher, collapsed) }),
3093
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "space-y-0.5", children: navItems.map((item) => {
2603
3094
  const Icon = item.icon;
2604
3095
  const active = Boolean(item.active);
2605
- const link = /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
3096
+ const link = /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
2606
3097
  import_link2.default,
2607
3098
  {
2608
3099
  href: item.href,
@@ -2615,7 +3106,7 @@ function SuiteSidebar({
2615
3106
  collapsed ? "mx-auto size-10 shrink-0 justify-center gap-0 px-0 py-0" : "w-full px-2.5 py-2"
2616
3107
  ),
2617
3108
  children: [
2618
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3109
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2619
3110
  "span",
2620
3111
  {
2621
3112
  className: cn(
@@ -2623,7 +3114,7 @@ function SuiteSidebar({
2623
3114
  item.iconClassName
2624
3115
  ),
2625
3116
  "aria-hidden": true,
2626
- children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3117
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2627
3118
  Icon,
2628
3119
  {
2629
3120
  className: "h-full w-full",
@@ -2632,7 +3123,7 @@ function SuiteSidebar({
2632
3123
  )
2633
3124
  }
2634
3125
  ),
2635
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3126
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2636
3127
  "span",
2637
3128
  {
2638
3129
  className: cn(
@@ -2643,17 +3134,17 @@ function SuiteSidebar({
2643
3134
  children: item.label
2644
3135
  }
2645
3136
  ),
2646
- !collapsed && item.badge ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "relative ml-auto shrink-0", children: item.badge }) : null
3137
+ !collapsed && item.badge ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "relative ml-auto shrink-0", children: item.badge }) : null
2647
3138
  ]
2648
3139
  },
2649
3140
  item.label
2650
3141
  );
2651
- return collapsed ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Tooltip, { content: item.label, side: "right", children: link }, item.label) : link;
3142
+ return collapsed ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Tooltip, { content: item.label, side: "right", children: link }, item.label) : link;
2652
3143
  }) })
2653
3144
  ]
2654
3145
  }
2655
3146
  ),
2656
- secondaryNav ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3147
+ secondaryNav ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2657
3148
  "div",
2658
3149
  {
2659
3150
  className: "min-h-0 flex-1",
@@ -2664,7 +3155,7 @@ function SuiteSidebar({
2664
3155
  ]
2665
3156
  }
2666
3157
  ),
2667
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
3158
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2668
3159
  "div",
2669
3160
  {
2670
3161
  className: cn(
@@ -2672,7 +3163,7 @@ function SuiteSidebar({
2672
3163
  surface ? "bg-ph-surface" : "bg-ph-canvas",
2673
3164
  collapsed ? "p-1.5" : "p-3"
2674
3165
  ),
2675
- children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
3166
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
2676
3167
  "div",
2677
3168
  {
2678
3169
  className: cn(
@@ -2681,7 +3172,7 @@ function SuiteSidebar({
2681
3172
  ),
2682
3173
  children: [
2683
3174
  renderNode(userMenu, collapsed),
2684
- !collapsed && footerExtras ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "ml-auto shrink-0", children: renderNode(footerExtras, collapsed) }) : null
3175
+ !collapsed && footerExtras ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "ml-auto shrink-0", children: renderNode(footerExtras, collapsed) }) : null
2685
3176
  ]
2686
3177
  }
2687
3178
  )
@@ -2693,7 +3184,7 @@ function SuiteSidebar({
2693
3184
  }
2694
3185
 
2695
3186
  // src/suite/components/suite-app-layout.tsx
2696
- var import_jsx_runtime24 = require("react/jsx-runtime");
3187
+ var import_jsx_runtime25 = require("react/jsx-runtime");
2697
3188
  function SuiteAppLayout({
2698
3189
  sidebar,
2699
3190
  children,
@@ -2701,41 +3192,59 @@ function SuiteAppLayout({
2701
3192
  bottomNav,
2702
3193
  sidebarWidth = 240,
2703
3194
  collapsed = false,
3195
+ lockMainScroll = false,
2704
3196
  onStartResize,
2705
3197
  onResetWidth,
2706
3198
  className
2707
3199
  }) {
2708
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { "data-test": "app-shell", className: cn("min-h-screen", className), children: [
2709
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "hidden lg:flex h-screen overflow-hidden", children: [
2710
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
2711
- "aside",
2712
- {
2713
- className: "relative flex shrink-0 flex-col border-r border-ph-border transition-[width] duration-200 ease-out",
2714
- style: { width: `${sidebarWidth}px` },
2715
- children: [
2716
- sidebar,
2717
- onStartResize ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2718
- "div",
2719
- {
2720
- role: "separator",
2721
- "aria-orientation": "vertical",
2722
- "aria-label": "Resize sidebar",
2723
- onPointerDown: onStartResize,
2724
- onDoubleClick: onResetWidth,
2725
- className: "absolute inset-y-0 right-0 z-10 w-1 cursor-col-resize transition-colors hover:bg-[color-mix(in_oklab,var(--ph-accent)_30%,transparent)]"
2726
- }
2727
- ) : null
2728
- ]
2729
- }
2730
- ),
2731
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("main", { className: "min-w-0 flex-1 overflow-y-auto bg-ph-canvas", children })
2732
- ] }),
2733
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex min-h-screen flex-col lg:hidden", children: [
2734
- mobileHeader ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "shrink-0", children: mobileHeader }) : null,
2735
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("main", { className: "min-w-0 flex-1 overflow-y-auto bg-ph-canvas", children }),
2736
- bottomNav ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "shrink-0", children: bottomNav }) : null
2737
- ] })
2738
- ] });
3200
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
3201
+ "div",
3202
+ {
3203
+ "data-test": "app-shell",
3204
+ className: cn("flex min-h-dvh lg:h-screen lg:overflow-hidden", className),
3205
+ children: [
3206
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
3207
+ "aside",
3208
+ {
3209
+ className: "relative hidden shrink-0 flex-col overflow-hidden border-r border-ph-border transition-[width] duration-200 ease-out lg:flex",
3210
+ style: { width: `${sidebarWidth}px` },
3211
+ "data-collapsed": collapsed ? "true" : "false",
3212
+ children: [
3213
+ sidebar,
3214
+ onStartResize ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3215
+ "div",
3216
+ {
3217
+ role: "separator",
3218
+ "aria-orientation": "vertical",
3219
+ "aria-label": "Resize sidebar",
3220
+ onPointerDown: onStartResize,
3221
+ onDoubleClick: onResetWidth,
3222
+ className: "absolute inset-y-0 right-0 z-10 w-1 cursor-col-resize transition-colors hover:bg-[color-mix(in_oklab,var(--ph-accent)_30%,transparent)]"
3223
+ }
3224
+ ) : null
3225
+ ]
3226
+ }
3227
+ ),
3228
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex min-h-0 min-w-0 flex-1 flex-col", children: [
3229
+ mobileHeader ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "shrink-0 lg:hidden", children: mobileHeader }) : null,
3230
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3231
+ "main",
3232
+ {
3233
+ id: "main-content",
3234
+ tabIndex: -1,
3235
+ "data-lock-scroll": lockMainScroll ? "true" : void 0,
3236
+ className: cn(
3237
+ "flex min-h-0 min-w-0 flex-1 flex-col overflow-x-hidden overscroll-contain bg-ph-canvas focus:outline-none",
3238
+ lockMainScroll ? "overflow-hidden" : "overflow-y-auto"
3239
+ ),
3240
+ children
3241
+ }
3242
+ ),
3243
+ bottomNav ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "shrink-0 lg:hidden", children: bottomNav }) : null
3244
+ ] })
3245
+ ]
3246
+ }
3247
+ );
2739
3248
  }
2740
3249
  // Annotate the CommonJS export names for ESM import in node:
2741
3250
  0 && (module.exports = {
@@ -2748,10 +3257,16 @@ function SuiteAppLayout({
2748
3257
  AppSwitcherMark,
2749
3258
  CommandPaletteHost,
2750
3259
  DeferredChrome,
3260
+ SIDEBAR_COLLAPSE_THRESHOLD,
3261
+ SIDEBAR_DEFAULT_WIDTH,
3262
+ SIDEBAR_MAX_WIDTH,
3263
+ SIDEBAR_MIN_EXPANDED_WIDTH,
3264
+ SIDEBAR_RAIL_WIDTH,
2751
3265
  SUITE_APPS,
2752
3266
  SUITE_APP_MAP,
2753
3267
  SUITE_GLYPHS,
2754
3268
  SUITE_ICON_NAMES,
3269
+ SUITE_OPEN_ASK_AI_EVENT,
2755
3270
  SUITE_SPRINGS,
2756
3271
  SourceAppGlyph,
2757
3272
  SuiteAiPanel,
@@ -2769,6 +3284,7 @@ function SuiteAppLayout({
2769
3284
  SuitePage,
2770
3285
  SuitePageHeader,
2771
3286
  SuiteSectionHeader,
3287
+ SuiteSettingsLayout,
2772
3288
  SuiteSettingsMobileNav,
2773
3289
  SuiteSidebar,
2774
3290
  SuiteSkeleton,
@@ -2778,11 +3294,15 @@ function SuiteAppLayout({
2778
3294
  SuiteThemeProvider,
2779
3295
  SuiteToolbar,
2780
3296
  SuiteUserMenu,
3297
+ TodayAskAiCard,
2781
3298
  TodayCalibrating,
3299
+ TodayEmptyAction,
2782
3300
  TodayEmptyState,
2783
3301
  TodayHero,
3302
+ TodayLayout,
2784
3303
  TodayPageFrame,
2785
3304
  TodayPanel,
3305
+ TodayPrimaryAction,
2786
3306
  TodaySection,
2787
3307
  TodayTimeIcon,
2788
3308
  TodayTopBar,
@@ -2792,9 +3312,12 @@ function SuiteAppLayout({
2792
3312
  cn,
2793
3313
  getTodayGreeting,
2794
3314
  m,
3315
+ openSuiteAskAi,
3316
+ resolveSuiteNotificationHref,
2795
3317
  sourceToSuiteApp,
2796
3318
  suiteAppBaseUrl,
2797
3319
  suiteAppLabel,
2798
3320
  useIdleMount,
3321
+ useSidebarWidth,
2799
3322
  useSuiteTheme
2800
3323
  });