@xenide-io/the-old-ui-theme 0.5.2 → 0.5.4

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 (59) hide show
  1. package/README.md +47 -34
  2. package/dist/{index-Od4pIP4F.d.mts → Chip-C5hRFAhe.d.mts} +10 -606
  3. package/dist/{index-Od4pIP4F.d.ts → Chip-C5hRFAhe.d.ts} +10 -606
  4. package/dist/{chunk-G53YLHVE.mjs → chunk-E5ZBQYEX.mjs} +59 -9
  5. package/dist/{chunk-RZXHZWUB.mjs → chunk-SBBKXV35.mjs} +174 -222
  6. package/dist/index.d.mts +4 -80
  7. package/dist/index.d.ts +4 -80
  8. package/dist/index.js +562 -3746
  9. package/dist/index.mjs +3 -765
  10. package/dist/suite.d.mts +56 -25
  11. package/dist/suite.d.ts +56 -25
  12. package/dist/suite.js +248 -107
  13. package/dist/suite.mjs +217 -105
  14. package/dist/ui.d.mts +608 -2
  15. package/dist/ui.d.ts +608 -2
  16. package/dist/ui.js +232 -230
  17. package/dist/ui.mjs +2 -2
  18. package/package.json +2 -6
  19. package/scripts/install-theme-dev.sh +60 -0
  20. package/scripts/sync-posthog-icons.mjs +75 -0
  21. package/src/app/globals.css +1 -0
  22. package/src/components/ui/Chip.tsx +36 -18
  23. package/src/components/ui/CommandPalette.test.tsx +41 -0
  24. package/src/components/ui/CommandPalette.tsx +58 -9
  25. package/src/components/ui/DropdownMenu.tsx +50 -11
  26. package/src/components/ui/SegmentedControl.tsx +2 -1
  27. package/src/components/ui/SettingsLayout.tsx +19 -5
  28. package/src/components/ui/ThemeSwitcher.tsx +12 -3
  29. package/src/components/ui/interaction-primitives.test.tsx +52 -0
  30. package/src/styles/suite-skin.css +53 -1
  31. package/src/styles/themes.css +445 -1656
  32. package/src/suite/components/app-switcher.tsx +32 -25
  33. package/src/suite/components/command-palette-host.tsx +20 -8
  34. package/src/suite/components/suite-app-layout.tsx +31 -10
  35. package/src/suite/components/suite-bottom-nav.tsx +23 -18
  36. package/src/suite/components/suite-layout.test.tsx +44 -0
  37. package/src/suite/components/suite-layout.tsx +3 -3
  38. package/src/suite/components/suite-mobile-drawer.tsx +12 -0
  39. package/src/suite/components/suite-mobile-header.tsx +15 -9
  40. package/src/suite/components/suite-notification-bell.tsx +23 -11
  41. package/src/suite/components/suite-settings-mobile-nav.tsx +2 -0
  42. package/src/suite/components/suite-sidebar.tsx +54 -43
  43. package/src/suite/components/suite-user-menu.tsx +54 -26
  44. package/src/suite/components/today-page-frame.tsx +1 -1
  45. package/src/suite/icons/app-accents.ts +38 -43
  46. package/src/suite/icons/glyph-parts.tsx +16 -9
  47. package/src/suite/icons/glyphs.ts +130 -99
  48. package/src/suite/lib/apps.ts +1 -1
  49. package/src/suite/lib/injected.ts +12 -11
  50. package/src/suite/lib/use-sidebar-width.ts +23 -8
  51. package/src/components/charts/index.ts +0 -9
  52. package/src/components/charts/quill/BarChart.tsx +0 -85
  53. package/src/components/charts/quill/FunnelChart.tsx +0 -49
  54. package/src/components/charts/quill/InsightShell.tsx +0 -27
  55. package/src/components/charts/quill/MetricCard.tsx +0 -44
  56. package/src/components/charts/quill/PieChart.tsx +0 -81
  57. package/src/components/charts/quill/Sparkline.tsx +0 -57
  58. package/src/components/charts/quill/TimeSeriesLineChart.tsx +0 -62
  59. package/src/components/charts/quill/index.ts +0 -9
package/dist/suite.js CHANGED
@@ -386,10 +386,10 @@ var APP_ACCENTS = {
386
386
  },
387
387
  nakama: {
388
388
  label: "Nakama",
389
- accent: "#0891b2",
390
- tile: "#155e75",
391
- onTile: "#ffffff",
392
- onTileAccent: "#a5f3fc"
389
+ accent: "#b8eb44",
390
+ tile: "#17101f",
391
+ onTile: "#fff2e2",
392
+ onTileAccent: "#f54b87"
393
393
  }
394
394
  };
395
395
  var APP_GLYPHS = {
@@ -398,7 +398,7 @@ var APP_GLYPHS = {
398
398
  kraken: "squid-doc",
399
399
  shellstack: "stack-hex",
400
400
  crew: "crew-bot",
401
- nakama: "crew-bot"
401
+ nakama: "nakama-fist"
402
402
  };
403
403
 
404
404
  // src/suite/icons/glyph-parts.tsx
@@ -408,7 +408,15 @@ function GlyphElement({ element }) {
408
408
  const stroke = element.filled ? "none" : void 0;
409
409
  switch (element.kind) {
410
410
  case "path":
411
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: element.d, fill, stroke });
411
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
412
+ "path",
413
+ {
414
+ d: element.d,
415
+ fill,
416
+ stroke,
417
+ transform: element.transform
418
+ }
419
+ );
412
420
  case "circle":
413
421
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
414
422
  "circle",
@@ -513,6 +521,24 @@ var SUITE_GLYPHS = {
513
521
  { kind: "path", d: "M9.6 14.6q2.4 1.7 4.8 0", accent: true }
514
522
  ]
515
523
  },
524
+ "nakama-fist": {
525
+ description: "Nakama \u2014 raised fist with neon crew signal lines",
526
+ elements: [
527
+ {
528
+ kind: "path",
529
+ d: "M192 0c17.7 0 32 14.3 32 32v112h-64V32c0-17.7 14.3-32 32-32zM64 64c0-17.7-32-32 32-32s32 14.3 32 32v80H64V64zm192 0c0-17.7 14.3-32 32-32s32 14.3 32 32v96c0 17.7-14.3 32-32 32s-32-14.3-32-32V64zm96 64c0-17.7 14.3-32 32-32s32 14.3 32 32v64c0 17.7-14.3 32-32 32s-32-14.3-32-32v-64zm-96 88v-.6c9.4 5.4 20.3 8.6 32 8.6 13.2 0 25.4-4 35.6-10.8 8.7 24.9 32.5 42.8 60.4 42.8 11.7 0 22.6-3.1 32-8.6v8.6c0 52.3-25.1 98.8-64 128v96c0 17.7-14.3 32-32 32H160c-17.7 0-32-14.3-32-32v-78.4c-17.3-7.9-33.2-18.8-46.9-32.5L69.5 357.5C45.5 333.5 32 300.9 32 267v-27c0-35.3 28.7-64 64-64h88c22.1 0 40 17.9 40 40s-17.9 40-40 40h-56c-8.8 0-16 7.2-16 16s7.2 16 16 16h56c39.8 0 72-32.2 72-72z",
530
+ filled: true,
531
+ transform: "translate(2.5 1.75) scale(.0425 .0375)"
532
+ },
533
+ { kind: "path", d: "M7 18h3.5M12.2 18h3M8.5 19.5h6", accent: true },
534
+ {
535
+ kind: "path",
536
+ d: "M4.8 5.8h2.7M4.8 7.4h1.4M18.5 17.1h1.7",
537
+ accent: true
538
+ },
539
+ { kind: "circle", cx: 18.5, cy: 4.5, r: 0.8, accent: true, filled: true }
540
+ ]
541
+ },
516
542
  workspace: {
517
543
  description: "Workspace container \u2014 panel with header bar and content",
518
544
  elements: [
@@ -526,7 +552,15 @@ var SUITE_GLYPHS = {
526
552
  organisation: {
527
553
  description: "Organisation chart \u2014 root node with two members",
528
554
  elements: [
529
- { kind: "rect", x: 9.5, y: 3.5, width: 5, height: 5, rx: 1.4, accent: true },
555
+ {
556
+ kind: "rect",
557
+ x: 9.5,
558
+ y: 3.5,
559
+ width: 5,
560
+ height: 5,
561
+ rx: 1.4,
562
+ accent: true
563
+ },
530
564
  { kind: "path", d: "M12 8.5v2.5" },
531
565
  { kind: "path", d: "M6.75 13.5v-2.5h10.5v2.5" },
532
566
  { kind: "rect", x: 4.25, y: 13.5, width: 5, height: 5, rx: 1.4 },
@@ -570,7 +604,10 @@ var SUITE_GLYPHS = {
570
604
  "bell-wave": {
571
605
  description: "Notifications \u2014 bell with sound waves",
572
606
  elements: [
573
- { kind: "path", d: "M7 9.2a5 5 0 0 1 10 0c0 5.3 2.4 7.3 2.4 7.3H4.6S7 14.5 7 9.2" },
607
+ {
608
+ kind: "path",
609
+ d: "M7 9.2a5 5 0 0 1 10 0c0 5.3 2.4 7.3 2.4 7.3H4.6S7 14.5 7 9.2"
610
+ },
574
611
  { kind: "path", d: "M10.7 19.3a1.5 1.5 0 0 0 2.6 0" },
575
612
  { kind: "path", d: "M17.9 6.4a5.5 5.5 0 0 1 1.4 3.7", accent: true },
576
613
  { kind: "path", d: "M15.7 4a9.4 9.4 0 0 1 2.4 6", accent: true }
@@ -1229,13 +1266,17 @@ function AppSwitcher({
1229
1266
  title,
1230
1267
  collapsed = false,
1231
1268
  dropdownMenu: DropdownMenu2,
1232
- dropdownItem: DropdownItem2
1269
+ dropdownItem: DropdownItem2,
1270
+ triggerId,
1271
+ triggerDataTest
1233
1272
  }) {
1234
1273
  const [open, setOpen] = (0, import_react.useState)(false);
1235
1274
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1236
1275
  DropdownMenu2,
1237
1276
  {
1238
1277
  "aria-label": "Switch application",
1278
+ triggerId: triggerId != null ? triggerId : "app-switcher-trigger",
1279
+ triggerDataTest: triggerDataTest != null ? triggerDataTest : "app-switcher-trigger",
1239
1280
  className: collapsed ? "w-11 shrink-0" : "min-w-0 flex-1",
1240
1281
  panelClassName: "w-64",
1241
1282
  align: "start",
@@ -1257,11 +1298,12 @@ function AppSwitcher({
1257
1298
  ]
1258
1299
  }
1259
1300
  ),
1260
- children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "p-1", "data-test": "app-switcher-menu", children: [
1301
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { id: "app-switcher-menu", className: "p-1", "data-test": "app-switcher-menu", children: [
1261
1302
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "px-3 py-2 text-[10px] font-semibold uppercase tracking-[0.14em] text-ph-mutedtext", children: "Switch application" }),
1262
1303
  apps.map((app) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1263
1304
  DropdownItem2,
1264
1305
  {
1306
+ id: `switch-app-${app.slug}`,
1265
1307
  "data-test": `switch-app-${app.slug}`,
1266
1308
  onMouseDown: (e) => e.preventDefault(),
1267
1309
  onClick: () => {
@@ -1396,7 +1438,10 @@ function SuiteNotificationBell({
1396
1438
  markRead,
1397
1439
  markAllRead,
1398
1440
  dropdownMenu: DropdownMenu2,
1399
- cacheKey = "suite-notifications-cache"
1441
+ cacheKey = "suite-notifications-cache",
1442
+ dataTest = "suite-notifications",
1443
+ triggerId,
1444
+ triggerDataTest
1400
1445
  }) {
1401
1446
  const router = (0, import_navigation.useRouter)();
1402
1447
  const [open, setOpen] = (0, import_react2.useState)(false);
@@ -1497,11 +1542,13 @@ function SuiteNotificationBell({
1497
1542
  DropdownMenu2,
1498
1543
  {
1499
1544
  "aria-label": "Notifications",
1545
+ triggerId: triggerId != null ? triggerId : `${dataTest}-trigger`,
1546
+ triggerDataTest: triggerDataTest != null ? triggerDataTest : `${dataTest}-trigger`,
1500
1547
  align: "end",
1501
1548
  panelClassName: "w-80 overflow-hidden p-0",
1502
1549
  open,
1503
1550
  onOpenChange,
1504
- trigger: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "relative inline-flex h-9 w-9 items-center justify-center rounded-full text-ph-mutedtext transition hover:bg-ph-muted hover:text-ph-ink", children: [
1551
+ trigger: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "relative inline-flex h-11 w-11 items-center justify-center rounded-full text-ph-mutedtext transition hover:bg-ph-muted hover:text-ph-ink", children: [
1505
1552
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_iconoir_react3.Bell, { className: "h-5 w-5", strokeWidth: 1.75, "aria-hidden": true }),
1506
1553
  unread > 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "absolute -right-0.5 -top-0.5 flex h-4 min-w-4 items-center justify-center rounded-full bg-ph-brand px-1 text-[10px] font-semibold leading-none text-white ring-2 ring-ph-surface", children: unread > 9 ? "9+" : unread }) : null
1507
1554
  ] }),
@@ -1512,6 +1559,8 @@ function SuiteNotificationBell({
1512
1559
  "button",
1513
1560
  {
1514
1561
  type: "button",
1562
+ id: `${dataTest}-mark-all`,
1563
+ "data-test": `${dataTest}-mark-all`,
1515
1564
  onClick: markAll,
1516
1565
  className: "text-xs font-medium text-ph-brand hover:underline",
1517
1566
  children: "Mark all read"
@@ -1522,6 +1571,8 @@ function SuiteNotificationBell({
1522
1571
  "button",
1523
1572
  {
1524
1573
  type: "button",
1574
+ id: `${dataTest}-item-${n.id}`,
1575
+ "data-test": `${dataTest}-item-${n.id}`,
1525
1576
  onClick: () => void openItem(n),
1526
1577
  className: "flex w-full flex-col gap-0.5 px-3 py-2 text-left transition hover:bg-ph-muted",
1527
1578
  children: [
@@ -1566,6 +1617,10 @@ function CommandPaletteHost({
1566
1617
  items,
1567
1618
  isAuthenticated = true,
1568
1619
  placeholder = "Type a command or search\u2026",
1620
+ id,
1621
+ dataTest,
1622
+ inputId,
1623
+ inputDataTest,
1569
1624
  commandPalette: CommandPalette
1570
1625
  }) {
1571
1626
  const [open, setOpen] = (0, import_react3.useState)(false);
@@ -1586,7 +1641,11 @@ function CommandPaletteHost({
1586
1641
  items,
1587
1642
  isOpen: open,
1588
1643
  onClose: () => setOpen(false),
1589
- placeholder
1644
+ placeholder,
1645
+ id,
1646
+ dataTest,
1647
+ inputId,
1648
+ inputDataTest
1590
1649
  }
1591
1650
  );
1592
1651
  }
@@ -1634,6 +1693,10 @@ function SuiteMobileDrawer({
1634
1693
  durationMs = 200,
1635
1694
  dataTest,
1636
1695
  panelDataTest,
1696
+ backdropId,
1697
+ backdropDataTest,
1698
+ closeButtonId,
1699
+ closeButtonDataTest,
1637
1700
  panelClassName
1638
1701
  }) {
1639
1702
  const [rendered, setRendered] = (0, import_react5.useState)(open);
@@ -1685,6 +1748,8 @@ function SuiteMobileDrawer({
1685
1748
  "button",
1686
1749
  {
1687
1750
  type: "button",
1751
+ id: backdropId,
1752
+ "data-test": backdropDataTest,
1688
1753
  tabIndex: -1,
1689
1754
  className: cn(
1690
1755
  "absolute inset-0 bg-black/25 backdrop-blur-sm motion-safe:transition-opacity motion-safe:ease-spring-subtle",
@@ -1725,6 +1790,8 @@ function SuiteMobileDrawer({
1725
1790
  "button",
1726
1791
  {
1727
1792
  type: "button",
1793
+ id: closeButtonId,
1794
+ "data-test": closeButtonDataTest,
1728
1795
  onClick: onClose,
1729
1796
  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",
1730
1797
  "aria-label": closeLabel,
@@ -1750,6 +1817,7 @@ function SuiteMobileHeader({
1750
1817
  title,
1751
1818
  actions,
1752
1819
  menuLabel = "Open navigation",
1820
+ menuId,
1753
1821
  menuDataTest,
1754
1822
  dataTest,
1755
1823
  className
@@ -1767,6 +1835,7 @@ function SuiteMobileHeader({
1767
1835
  "button",
1768
1836
  {
1769
1837
  type: "button",
1838
+ id: menuId,
1770
1839
  "data-test": menuDataTest,
1771
1840
  className: "suite-press inline-flex h-11 w-11 shrink-0 items-center justify-center rounded-xl text-ph-ink transition-colors hover:bg-ph-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-brand",
1772
1841
  onClick: onMenuClick,
@@ -1906,7 +1975,7 @@ function SuitePageHeader({
1906
1975
  "data-test": dataTest,
1907
1976
  "data-stuck": sticky ? stuck ? "true" : "false" : void 0,
1908
1977
  className: cn(
1909
- "flex items-start justify-between gap-4 pb-2 sm:pb-3",
1978
+ "flex min-w-0 flex-col items-start gap-3 pb-2 sm:flex-row sm:justify-between sm:gap-4 sm:pb-3",
1910
1979
  // No extra pt here — page inset sets the shared title baseline.
1911
1980
  // Stuck state adds pad via .suite-page-header-sticky[data-stuck].
1912
1981
  sticky && "suite-page-header-sticky",
@@ -1930,7 +1999,7 @@ function SuitePageHeader({
1930
1999
  "h1",
1931
2000
  {
1932
2001
  className: cn(
1933
- "font-display text-[1.625rem] font-bold leading-none tracking-tight text-ph-ink sm:text-[2.25rem]",
2002
+ "min-w-0 break-words font-display text-[1.625rem] font-bold leading-none tracking-tight text-ph-ink text-balance sm:text-[2.25rem]",
1934
2003
  titleClassName
1935
2004
  ),
1936
2005
  children: title
@@ -1950,7 +2019,7 @@ function SuitePageHeader({
1950
2019
  }
1951
2020
  ) : null
1952
2021
  ] }),
1953
- actions ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "flex shrink-0 items-center gap-2 self-center", children: actions }) : null
2022
+ actions ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "flex max-w-full items-center gap-2 self-stretch overflow-x-auto pb-1 sm:shrink-0 sm:self-center sm:overflow-visible sm:pb-0", children: actions }) : null
1954
2023
  ]
1955
2024
  }
1956
2025
  );
@@ -2111,7 +2180,14 @@ function DropdownContent({
2111
2180
  sticky: "partial",
2112
2181
  children: [
2113
2182
  children,
2114
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DropdownPrimitive.Arrow, { className: "ph-dropdown-arrow", width: 12, height: 6 })
2183
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2184
+ DropdownPrimitive.Arrow,
2185
+ {
2186
+ className: "ph-dropdown-arrow",
2187
+ width: 12,
2188
+ height: 6
2189
+ }
2190
+ )
2115
2191
  ]
2116
2192
  }
2117
2193
  ) });
@@ -2119,6 +2195,8 @@ function DropdownContent({
2119
2195
  function DropdownMenu(_a) {
2120
2196
  var _b = _a, {
2121
2197
  trigger,
2198
+ triggerId,
2199
+ triggerDataTest,
2122
2200
  children,
2123
2201
  align,
2124
2202
  side,
@@ -2136,6 +2214,8 @@ function DropdownMenu(_a) {
2136
2214
  disabled
2137
2215
  } = _b, props = __objRest(_b, [
2138
2216
  "trigger",
2217
+ "triggerId",
2218
+ "triggerDataTest",
2139
2219
  "children",
2140
2220
  "align",
2141
2221
  "side",
@@ -2160,7 +2240,17 @@ function DropdownMenu(_a) {
2160
2240
  onOpenChange,
2161
2241
  modal,
2162
2242
  children: [
2163
- /* @__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 }) }),
2243
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DropdownPrimitive.Trigger, { asChild: true, disabled, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2244
+ "button",
2245
+ {
2246
+ type: "button",
2247
+ id: triggerId,
2248
+ "data-test": triggerDataTest,
2249
+ className: "ph-dropdown-trigger",
2250
+ "aria-label": ariaLabel,
2251
+ children: trigger
2252
+ }
2253
+ ) }),
2164
2254
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2165
2255
  DropdownContent,
2166
2256
  {
@@ -2179,7 +2269,15 @@ function DropdownMenu(_a) {
2179
2269
  ) }));
2180
2270
  }
2181
2271
  function DropdownItem(_a) {
2182
- var _b = _a, { className, children, disabled } = _b, props = __objRest(_b, ["className", "children", "disabled"]);
2272
+ var _b = _a, {
2273
+ className,
2274
+ children,
2275
+ disabled
2276
+ } = _b, props = __objRest(_b, [
2277
+ "className",
2278
+ "children",
2279
+ "disabled"
2280
+ ]);
2183
2281
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DropdownPrimitive.Item, { asChild: true, disabled, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2184
2282
  "button",
2185
2283
  __spreadProps(__spreadValues({
@@ -2205,33 +2303,38 @@ function SuiteUserMenu({
2205
2303
  settingsHref,
2206
2304
  onSignOut,
2207
2305
  fallbackInitials,
2306
+ showSignOutAction = false,
2208
2307
  dataTest = "suite-user-menu",
2308
+ triggerId,
2309
+ triggerDataTest,
2209
2310
  className
2210
2311
  }) {
2211
2312
  const router = (0, import_navigation2.useRouter)();
2212
2313
  const initials = fallbackInitials != null ? fallbackInitials : computeInitials(name, email);
2213
- 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)(
2314
+ const avatar = /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "inline-flex h-11 w-11 items-center justify-center rounded-full ring-2 ring-ph-border ring-offset-1 ring-offset-ph-canvas transition-colors hover:bg-ph-muted", children: image ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2214
2315
  import_image2.default,
2215
2316
  {
2216
2317
  src: image,
2217
2318
  alt: "",
2218
- width: 32,
2219
- height: 32,
2220
- className: "h-8 w-8 rounded-full object-cover",
2319
+ width: 40,
2320
+ height: 40,
2321
+ className: "h-10 w-10 rounded-full object-cover",
2221
2322
  unoptimized: true
2222
2323
  }
2223
- ) : /* @__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 }) });
2224
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2324
+ ) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "flex h-10 w-10 items-center justify-center rounded-full bg-ph-muted text-sm font-semibold text-ph-brand", children: initials }) });
2325
+ const accountMenu = /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2225
2326
  DropdownMenu,
2226
2327
  {
2227
2328
  trigger: avatar,
2329
+ triggerId: triggerId != null ? triggerId : `${dataTest}-trigger`,
2330
+ triggerDataTest: triggerDataTest != null ? triggerDataTest : `${dataTest}-trigger`,
2228
2331
  "aria-label": "Account menu",
2229
2332
  align: "end",
2230
2333
  side: "bottom",
2231
2334
  sideOffset: 6,
2232
2335
  collisionPadding: 16,
2233
2336
  modal: false,
2234
- className,
2337
+ className: showSignOutAction ? void 0 : className,
2235
2338
  "data-test": dataTest,
2236
2339
  children: [
2237
2340
  /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "px-2 py-1.5", children: [
@@ -2250,20 +2353,31 @@ function SuiteUserMenu({
2250
2353
  ]
2251
2354
  }
2252
2355
  ),
2253
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2254
- DropdownItem,
2255
- {
2256
- "data-test": `${dataTest}-sign-out`,
2257
- onClick: onSignOut,
2258
- children: [
2259
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_iconoir_react6.LogOut, { className: "h-4 w-4 text-ph-mutedtext", "aria-hidden": true }),
2260
- "Sign out"
2261
- ]
2262
- }
2263
- )
2356
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(DropdownItem, { "data-test": `${dataTest}-sign-out`, onClick: onSignOut, children: [
2357
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_iconoir_react6.LogOut, { className: "h-4 w-4 text-ph-mutedtext", "aria-hidden": true }),
2358
+ "Sign out"
2359
+ ] })
2264
2360
  ]
2265
2361
  }
2266
2362
  );
2363
+ if (!showSignOutAction) {
2364
+ return accountMenu;
2365
+ }
2366
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: cn("flex min-w-0 items-center gap-2", className), children: [
2367
+ accountMenu,
2368
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2369
+ "button",
2370
+ {
2371
+ type: "button",
2372
+ "data-test": `${dataTest}-visible-sign-out`,
2373
+ title: "Sign out",
2374
+ "aria-label": "Sign out",
2375
+ className: "inline-flex h-11 w-11 shrink-0 items-center justify-center rounded-lg text-ph-mutedtext transition-colors hover:bg-ph-muted hover:text-ph-ink focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ph-focus-ring",
2376
+ onClick: onSignOut,
2377
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_iconoir_react6.LogOut, { className: "h-4 w-4", "aria-hidden": true })
2378
+ }
2379
+ )
2380
+ ] });
2267
2381
  }
2268
2382
 
2269
2383
  // src/suite/components/suite-bottom-nav.tsx
@@ -2314,6 +2428,7 @@ function SuiteBottomNav({
2314
2428
  import_link.default,
2315
2429
  {
2316
2430
  href: item.href,
2431
+ id: item.id,
2317
2432
  "data-test": (_a = item.dataTest) != null ? _a : `suite-nav-${item.label.toLowerCase().replace(/\s+/g, "-")}`,
2318
2433
  "aria-current": active ? "page" : void 0,
2319
2434
  className: cn(
@@ -2935,8 +3050,9 @@ function snapWidth(width) {
2935
3050
  if (width < SIDEBAR_MIN_EXPANDED_WIDTH) return SIDEBAR_MIN_EXPANDED_WIDTH;
2936
3051
  return Math.min(SIDEBAR_MAX_WIDTH, width);
2937
3052
  }
2938
- function useSidebarWidth(storageKey) {
2939
- const [width, setWidth] = (0, import_react11.useState)(SIDEBAR_DEFAULT_WIDTH);
3053
+ function useSidebarWidth(storageKey, defaultWidth = SIDEBAR_DEFAULT_WIDTH) {
3054
+ const fallbackWidth = snapWidth(clampWidth(defaultWidth));
3055
+ const [width, setWidth] = (0, import_react11.useState)(fallbackWidth);
2940
3056
  const [narrowViewport, setNarrowViewport] = (0, import_react11.useState)(false);
2941
3057
  const collapsed = narrowViewport || width <= SIDEBAR_COLLAPSE_THRESHOLD;
2942
3058
  (0, import_react11.useEffect)(() => {
@@ -2970,17 +3086,17 @@ function useSidebarWidth(storageKey) {
2970
3086
  const setCollapsed = (0, import_react11.useCallback)(
2971
3087
  (value) => {
2972
3088
  setWidth((current) => {
2973
- const next = value ? SIDEBAR_RAIL_WIDTH : current <= SIDEBAR_COLLAPSE_THRESHOLD ? SIDEBAR_DEFAULT_WIDTH : snapWidth(current);
3089
+ const next = value ? SIDEBAR_RAIL_WIDTH : current <= SIDEBAR_COLLAPSE_THRESHOLD ? fallbackWidth : snapWidth(current);
2974
3090
  persist(next);
2975
3091
  return next;
2976
3092
  });
2977
3093
  },
2978
- [persist]
3094
+ [fallbackWidth, persist]
2979
3095
  );
2980
3096
  const resetWidth = (0, import_react11.useCallback)(() => {
2981
- setWidth(SIDEBAR_DEFAULT_WIDTH);
2982
- persist(SIDEBAR_DEFAULT_WIDTH);
2983
- }, [persist]);
3097
+ setWidth(fallbackWidth);
3098
+ persist(fallbackWidth);
3099
+ }, [fallbackWidth, persist]);
2984
3100
  const startResize = (0, import_react11.useCallback)(
2985
3101
  (event) => {
2986
3102
  event.preventDefault();
@@ -3003,7 +3119,17 @@ function useSidebarWidth(storageKey) {
3003
3119
  },
3004
3120
  [persist, width]
3005
3121
  );
3006
- return { width, collapsed, setCollapsed, resetWidth, startResize };
3122
+ const resizeBy = (0, import_react11.useCallback)(
3123
+ (delta) => {
3124
+ setWidth((current) => {
3125
+ const next = clampWidth(current + delta);
3126
+ persist(next);
3127
+ return next;
3128
+ });
3129
+ },
3130
+ [persist]
3131
+ );
3132
+ return { width, collapsed, setCollapsed, resetWidth, startResize, resizeBy };
3007
3133
  }
3008
3134
 
3009
3135
  // src/suite/lib/motion.tsx
@@ -3200,6 +3326,7 @@ function SuiteSettingsMobileNav({
3200
3326
  "button",
3201
3327
  {
3202
3328
  type: "button",
3329
+ id: item.id,
3203
3330
  "data-test": item.testId,
3204
3331
  onClick: () => onSelect(item.href),
3205
3332
  "aria-current": active ? "page" : void 0,
@@ -3409,67 +3536,62 @@ function SuiteSidebar({
3409
3536
  collapsed ? "px-1.5 py-2" : "p-2"
3410
3537
  ),
3411
3538
  children: [
3412
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
3413
- "nav",
3414
- {
3415
- "aria-label": "Pages",
3416
- className: "shrink-0 space-y-0.5",
3417
- children: [
3418
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: cn("mb-3", collapsed && "flex justify-center"), children: renderNode(contextSwitcher, collapsed) }),
3419
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "space-y-0.5", children: navItems.map((item) => {
3420
- const Icon = item.icon;
3421
- const active = Boolean(item.active);
3422
- const link = /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
3423
- import_link2.default,
3424
- {
3425
- href: item.href,
3426
- "data-test": "nav-link",
3427
- "aria-current": active ? "page" : void 0,
3428
- onClick: item.onClick,
3429
- className: cn(
3430
- "group relative flex items-center gap-2.5 rounded-[var(--ph-radius-app)] text-sm font-medium transition-colors",
3431
- active ? "bg-ph-muted" : "text-ph-subtle hover:bg-ph-muted hover:text-ph-ink",
3432
- collapsed ? "mx-auto size-10 shrink-0 justify-center gap-0 px-0 py-0" : "w-full px-2.5 py-2"
3433
- ),
3434
- children: [
3435
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3436
- "span",
3437
- {
3438
- className: cn(
3439
- "relative flex h-4 w-4 shrink-0 items-center justify-center",
3440
- item.iconClassName
3441
- ),
3442
- "aria-hidden": true,
3443
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3444
- Icon,
3445
- {
3446
- className: "h-full w-full",
3447
- strokeWidth: active ? 2 : 1.75
3448
- }
3449
- )
3450
- }
3539
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("nav", { "aria-label": "Pages", className: "shrink-0 space-y-0.5", children: [
3540
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: cn("mb-3", collapsed && "flex justify-center"), children: renderNode(contextSwitcher, collapsed) }),
3541
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "space-y-0.5", children: navItems.map((item) => {
3542
+ var _a;
3543
+ const Icon = item.icon;
3544
+ const active = Boolean(item.active);
3545
+ const link = /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
3546
+ import_link2.default,
3547
+ {
3548
+ href: item.href,
3549
+ id: item.id,
3550
+ "data-test": (_a = item.dataTest) != null ? _a : "nav-link",
3551
+ "aria-current": active ? "page" : void 0,
3552
+ onClick: item.onClick,
3553
+ className: cn(
3554
+ "group relative flex min-h-11 touch-manipulation items-center gap-2.5 rounded-[var(--ph-radius-app)] text-sm font-medium transition-colors",
3555
+ active ? "bg-ph-muted" : "text-ph-subtle hover:bg-ph-muted hover:text-ph-ink",
3556
+ collapsed ? "mx-auto size-11 shrink-0 justify-center gap-0 px-0 py-0" : "w-full px-2.5 py-2"
3557
+ ),
3558
+ children: [
3559
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3560
+ "span",
3561
+ {
3562
+ className: cn(
3563
+ "relative flex h-4 w-4 shrink-0 items-center justify-center",
3564
+ item.iconClassName
3451
3565
  ),
3452
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3453
- "span",
3566
+ "aria-hidden": true,
3567
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3568
+ Icon,
3454
3569
  {
3455
- className: cn(
3456
- "relative truncate",
3457
- active ? "text-ph-ink" : "text-ph-subtle group-hover:text-ph-ink",
3458
- collapsed && "sr-only"
3459
- ),
3460
- children: item.label
3570
+ className: "h-full w-full",
3571
+ strokeWidth: active ? 2 : 1.75
3461
3572
  }
3573
+ )
3574
+ }
3575
+ ),
3576
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3577
+ "span",
3578
+ {
3579
+ className: cn(
3580
+ "relative truncate",
3581
+ active ? "text-ph-ink" : "text-ph-subtle group-hover:text-ph-ink",
3582
+ collapsed && "sr-only"
3462
3583
  ),
3463
- !collapsed && item.badge ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "relative ml-auto shrink-0", children: item.badge }) : null
3464
- ]
3465
- },
3466
- item.label
3467
- );
3468
- return collapsed ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Tooltip, { content: item.label, side: "right", children: link }, item.label) : link;
3469
- }) })
3470
- ]
3471
- }
3472
- ),
3584
+ children: item.label
3585
+ }
3586
+ ),
3587
+ !collapsed && item.badge ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "relative ml-auto shrink-0", children: item.badge }) : null
3588
+ ]
3589
+ },
3590
+ item.label
3591
+ );
3592
+ return collapsed ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Tooltip, { content: item.label, side: "right", children: link }, item.label) : link;
3593
+ }) })
3594
+ ] }),
3473
3595
  secondaryNav ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
3474
3596
  "div",
3475
3597
  {
@@ -3494,11 +3616,11 @@ function SuiteSidebar({
3494
3616
  {
3495
3617
  className: cn(
3496
3618
  "flex items-center gap-2",
3497
- collapsed && "justify-center"
3619
+ collapsed ? "flex-col justify-center" : "min-w-0"
3498
3620
  ),
3499
3621
  children: [
3500
3622
  renderNode(userMenu, collapsed),
3501
- !collapsed && footerExtras ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "ml-auto shrink-0", children: renderNode(footerExtras, collapsed) }) : null
3623
+ footerExtras ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: cn("shrink-0", collapsed ? "mt-2" : "ml-auto"), children: renderNode(footerExtras, collapsed) }) : null
3502
3624
  ]
3503
3625
  }
3504
3626
  )
@@ -3520,6 +3642,7 @@ function SuiteAppLayout({
3520
3642
  collapsed = false,
3521
3643
  lockMainScroll = false,
3522
3644
  onStartResize,
3645
+ onResizeBy,
3523
3646
  onResetWidth,
3524
3647
  className
3525
3648
  }) {
@@ -3527,12 +3650,15 @@ function SuiteAppLayout({
3527
3650
  "div",
3528
3651
  {
3529
3652
  "data-test": "app-shell",
3530
- className: cn("flex min-h-dvh lg:h-screen lg:overflow-hidden", className),
3653
+ className: cn(
3654
+ "suite-app-layout flex h-dvh overflow-hidden",
3655
+ className
3656
+ ),
3531
3657
  children: [
3532
3658
  /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
3533
3659
  "aside",
3534
3660
  {
3535
- className: "relative hidden shrink-0 flex-col overflow-hidden border-r border-ph-border transition-[width] duration-200 ease-out lg:flex",
3661
+ className: "relative hidden shrink-0 flex-col overflow-visible border-r border-ph-border ease-out lg:flex",
3536
3662
  style: { width: `${sidebarWidth}px` },
3537
3663
  "data-collapsed": collapsed ? "true" : "false",
3538
3664
  children: [
@@ -3543,9 +3669,23 @@ function SuiteAppLayout({
3543
3669
  role: "separator",
3544
3670
  "aria-orientation": "vertical",
3545
3671
  "aria-label": "Resize sidebar",
3672
+ "data-test": "sidebar-resize-handle",
3673
+ tabIndex: onResizeBy ? 0 : void 0,
3546
3674
  onPointerDown: onStartResize,
3547
3675
  onDoubleClick: onResetWidth,
3548
- 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)]"
3676
+ onKeyDown: (event) => {
3677
+ if (event.key === "Home") {
3678
+ event.preventDefault();
3679
+ onResetWidth == null ? void 0 : onResetWidth();
3680
+ } else if (event.key === "ArrowLeft") {
3681
+ event.preventDefault();
3682
+ onResizeBy == null ? void 0 : onResizeBy(-16);
3683
+ } else if (event.key === "ArrowRight") {
3684
+ event.preventDefault();
3685
+ onResizeBy == null ? void 0 : onResizeBy(16);
3686
+ }
3687
+ },
3688
+ className: "absolute inset-y-0 -right-1 z-10 w-2 cursor-col-resize touch-none transition-colors hover:bg-[color-mix(in_oklab,var(--ph-accent)_30%,transparent)]"
3549
3689
  }
3550
3690
  ) : null
3551
3691
  ]
@@ -3561,6 +3701,7 @@ function SuiteAppLayout({
3561
3701
  "data-lock-scroll": lockMainScroll ? "true" : void 0,
3562
3702
  className: cn(
3563
3703
  "flex min-h-0 min-w-0 flex-1 flex-col overflow-x-hidden overscroll-contain bg-ph-canvas focus:outline-none",
3704
+ "suite-app-layout__main",
3564
3705
  lockMainScroll ? "overflow-hidden" : "overflow-y-auto"
3565
3706
  ),
3566
3707
  children