@xenide-io/the-old-ui-theme 0.9.10 → 0.9.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/suite.js CHANGED
@@ -168,6 +168,7 @@ __export(suite_exports, {
168
168
  SuiteBreadcrumbs: () => SuiteBreadcrumbs,
169
169
  SuiteClientsProjectsDirectory: () => SuiteClientsProjectsDirectory,
170
170
  SuiteEmptyState: () => SuiteEmptyState,
171
+ SuiteEntityIcon: () => SuiteEntityIcon,
171
172
  SuiteIcon: () => SuiteIcon,
172
173
  SuiteIntegrationPicker: () => SuiteIntegrationPicker,
173
174
  SuiteIntegrationRules: () => SuiteIntegrationRules,
@@ -177,6 +178,7 @@ __export(suite_exports, {
177
178
  SuiteNotificationBell: () => SuiteNotificationBell,
178
179
  SuitePage: () => SuitePage,
179
180
  SuitePageHeader: () => SuitePageHeader,
181
+ SuitePaletteLibrary: () => SuitePaletteLibrary,
180
182
  SuiteSectionHeader: () => SuiteSectionHeader,
181
183
  SuiteSettingsLayout: () => SuiteSettingsLayout,
182
184
  SuiteSettingsMobileNav: () => SuiteSettingsMobileNav,
@@ -209,6 +211,9 @@ __export(suite_exports, {
209
211
  cn: () => cn,
210
212
  consumePendingAskAiPrompt: () => consumePendingAskAiPrompt,
211
213
  consumeSuiteAskAiOpenFromLocation: () => consumeSuiteAskAiOpenFromLocation,
214
+ fetchPaletteCollection: () => fetchPaletteCollection,
215
+ fetchPaletteLibrary: () => fetchPaletteLibrary,
216
+ findPaletteIcons: () => findPaletteIcons,
212
217
  getTodayGreeting: () => getTodayGreeting,
213
218
  m: () => import_react15.m,
214
219
  openSuiteAskAi: () => openSuiteAskAi,
@@ -672,13 +677,13 @@ function SuiteAppStrip({
672
677
  ),
673
678
  "aria-label": "ShellStack suite apps",
674
679
  children: SUITE_APPS.map((app) => {
675
- var _a;
680
+ var _a2;
676
681
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
677
682
  "div",
678
683
  {
679
684
  className: "flex items-center gap-2 rounded-full border border-ph-border bg-ph-surface px-2.5 py-1.5 shadow-sm",
680
685
  children: [
681
- (_a = icons == null ? void 0 : icons[app]) != null ? _a : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(SuiteAppIcon, { app, size: "sm" }),
686
+ (_a2 = icons == null ? void 0 : icons[app]) != null ? _a2 : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(SuiteAppIcon, { app, size: "sm" }),
682
687
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-xs font-medium text-ph-subtle", children: APP_META[app].name })
683
688
  ]
684
689
  },
@@ -797,13 +802,13 @@ function TodayTopBar({
797
802
  ] });
798
803
  }
799
804
  function getTodayGreeting(user, stats) {
800
- var _a, _b, _c, _d, _e;
805
+ var _a2, _b, _c, _d, _e;
801
806
  const hour = (/* @__PURE__ */ new Date()).getHours();
802
807
  let period = "morning";
803
808
  if (hour >= 12 && hour < 17) period = "afternoon";
804
809
  else if (hour >= 17 && hour < 21) period = "evening";
805
810
  else if (hour >= 21 || hour < 5) period = "night";
806
- const name = (user == null ? void 0 : user.first_name) || ((_a = user == null ? void 0 : user.name) == null ? void 0 : _a.split(" ")[0]) || ((_b = user == null ? void 0 : user.email) == null ? void 0 : _b.split("@")[0]) || null;
811
+ const name = (user == null ? void 0 : user.first_name) || ((_a2 = user == null ? void 0 : user.name) == null ? void 0 : _a2.split(" ")[0]) || ((_b = user == null ? void 0 : user.email) == null ? void 0 : _b.split("@")[0]) || null;
807
812
  let greeting = `Good ${period}`;
808
813
  if (name) greeting += `, ${name}`;
809
814
  const taskCount = (_c = stats == null ? void 0 : stats.taskCount) != null ? _c : 0;
@@ -1302,8 +1307,8 @@ var SOURCE_APP_SLUG = {
1302
1307
  shellstack: "shellstack"
1303
1308
  };
1304
1309
  function suiteAppSlugForNotificationSource(sourceApp) {
1305
- var _a;
1306
- return (_a = SOURCE_APP_SLUG[(sourceApp || "").toLowerCase()]) != null ? _a : null;
1310
+ var _a2;
1311
+ return (_a2 = SOURCE_APP_SLUG[(sourceApp || "").toLowerCase()]) != null ? _a2 : null;
1307
1312
  }
1308
1313
  function resolveSuiteNotificationHref(href, sourceApp) {
1309
1314
  const value = (href || "").trim();
@@ -1391,14 +1396,14 @@ function SuiteNotificationBell({
1391
1396
  (0, import_react2.useEffect)(() => {
1392
1397
  if (cacheKey) {
1393
1398
  queueMicrotask(() => {
1394
- var _a;
1399
+ var _a2;
1395
1400
  try {
1396
1401
  const raw = sessionStorage.getItem(cacheKey);
1397
1402
  if (raw) {
1398
1403
  const cached = JSON.parse(raw);
1399
1404
  if (Array.isArray(cached.notifications)) {
1400
1405
  setItems(cached.notifications);
1401
- setUnread((_a = cached.unread_count) != null ? _a : 0);
1406
+ setUnread((_a2 = cached.unread_count) != null ? _a2 : 0);
1402
1407
  }
1403
1408
  }
1404
1409
  } catch (e) {
@@ -1469,9 +1474,9 @@ function SuiteNotificationBell({
1469
1474
  const markAll = (0, import_react2.useCallback)(async () => {
1470
1475
  setItems(
1471
1476
  (prev) => prev.map((i) => {
1472
- var _a;
1477
+ var _a2;
1473
1478
  return __spreadProps(__spreadValues({}, i), {
1474
- read_at: (_a = i.read_at) != null ? _a : (/* @__PURE__ */ new Date()).toISOString()
1479
+ read_at: (_a2 = i.read_at) != null ? _a2 : (/* @__PURE__ */ new Date()).toISOString()
1475
1480
  });
1476
1481
  })
1477
1482
  );
@@ -2087,8 +2092,8 @@ function cn2(...parts) {
2087
2092
 
2088
2093
  // src/components/icons/IconBase.tsx
2089
2094
  var import_jsx_runtime13 = require("react/jsx-runtime");
2090
- var IconBase = (0, import_react7.forwardRef)(function IconBase2(_a, ref) {
2091
- var _b = _a, {
2095
+ var IconBase = (0, import_react7.forwardRef)(function IconBase2(_a2, ref) {
2096
+ var _b = _a2, {
2092
2097
  className,
2093
2098
  size,
2094
2099
  children,
@@ -2503,8 +2508,8 @@ var IconActivity = createIconBasePath(
2503
2508
  var IconFlask = createIconBasePath(
2504
2509
  "M19.8 18.4L14 10.67V6.5l1.35-1.35c.39-.39.39-1.02 0-1.41L14.65 2.7a.9959.9959 0 0 0-1.41 0L9.35 6.54c-.39.39-.39 1.02 0 1.41L10.7 9.3v4.17L4.2 18.4C3.53 19.07 4.04 20.25 5 20.25h14c.96 0 1.47-1.18.8-1.85zM6.91 18.25l5.09-5.09 5.09 5.09H6.91z"
2505
2510
  );
2506
- var IconSpinner = (0, import_react9.forwardRef)(function IconSpinner2(_a, ref) {
2507
- var _b = _a, { className } = _b, props = __objRest(_b, ["className"]);
2511
+ var IconSpinner = (0, import_react9.forwardRef)(function IconSpinner2(_a2, ref) {
2512
+ var _b = _a2, { className } = _b, props = __objRest(_b, ["className"]);
2508
2513
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(IconSync, __spreadValues({ ref, className: cn2("ph-icon-spin", className) }, props));
2509
2514
  });
2510
2515
  IconSpinner.displayName = "IconSpinner";
@@ -2603,8 +2608,8 @@ for (const [name, Icon] of Object.entries(CANONICAL_ICONS)) {
2603
2608
  namedIcon.displayName = `Icon${name[0].toUpperCase()}${name.slice(1)}`;
2604
2609
  }
2605
2610
  }
2606
- var IconByName = (0, import_react9.forwardRef)(function IconByName2(_a, ref) {
2607
- var _b = _a, { name } = _b, props = __objRest(_b, ["name"]);
2611
+ var IconByName = (0, import_react9.forwardRef)(function IconByName2(_a2, ref) {
2612
+ var _b = _a2, { name } = _b, props = __objRest(_b, ["name"]);
2608
2613
  const Icon = PH_ICONS[name];
2609
2614
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Icon, __spreadValues({ ref }, props));
2610
2615
  });
@@ -2658,8 +2663,8 @@ function DropdownContent({
2658
2663
  }
2659
2664
  ) });
2660
2665
  }
2661
- function DropdownMenu(_a) {
2662
- var _b = _a, {
2666
+ function DropdownMenu(_a2) {
2667
+ var _b = _a2, {
2663
2668
  trigger,
2664
2669
  triggerId,
2665
2670
  triggerDataTest,
@@ -2734,8 +2739,8 @@ function DropdownMenu(_a) {
2734
2739
  }
2735
2740
  ) }));
2736
2741
  }
2737
- function DropdownItem(_a) {
2738
- var _b = _a, {
2742
+ function DropdownItem(_a2) {
2743
+ var _b = _a2, {
2739
2744
  className,
2740
2745
  children,
2741
2746
  disabled
@@ -2934,7 +2939,7 @@ function SuiteBottomNav({
2934
2939
  children: [
2935
2940
  activeIndex >= 0 ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { "aria-hidden": true, className: "suite-bottom-nav__indicator" }) : null,
2936
2941
  items.map((item) => {
2937
- var _a;
2942
+ var _a2;
2938
2943
  const Icon = item.icon;
2939
2944
  const active = Boolean(item.active);
2940
2945
  return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
@@ -2942,7 +2947,7 @@ function SuiteBottomNav({
2942
2947
  {
2943
2948
  href: item.href,
2944
2949
  id: item.id,
2945
- "data-test": (_a = item.dataTest) != null ? _a : `suite-nav-${item.label.toLowerCase().replace(/\s+/g, "-")}`,
2950
+ "data-test": (_a2 = item.dataTest) != null ? _a2 : `suite-nav-${item.label.toLowerCase().replace(/\s+/g, "-")}`,
2946
2951
  "aria-current": active ? "page" : void 0,
2947
2952
  className: cn(
2948
2953
  "suite-bottom-nav__item relative flex min-h-[60px] min-w-0 flex-col items-center justify-center gap-1 px-1 pb-1.5 pt-2 text-[10px] font-medium leading-none text-ph-mutedtext transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ph-brand motion-reduce:transition-none",
@@ -3033,7 +3038,7 @@ var import_react10 = require("react");
3033
3038
 
3034
3039
  // src/suite/lib/cookies.ts
3035
3040
  function suiteCookieDomainAttr() {
3036
- var _a;
3041
+ var _a2;
3037
3042
  const host = window.location.hostname;
3038
3043
  if (host === "localhost" || /^\d{1,3}(?:\.\d{1,3}){3}$/.test(host)) {
3039
3044
  return "";
@@ -3052,7 +3057,7 @@ function suiteCookieDomainAttr() {
3052
3057
  "portal"
3053
3058
  ]);
3054
3059
  const parts = host.split(".");
3055
- if (parts.length >= 3 && known.has((_a = parts[0]) != null ? _a : "")) {
3060
+ if (parts.length >= 3 && known.has((_a2 = parts[0]) != null ? _a2 : "")) {
3056
3061
  return `; Domain=.${parts.slice(1).join(".")}`;
3057
3062
  }
3058
3063
  if (parts.length >= 2) return `; Domain=.${parts.slice(1).join(".")}`;
@@ -3261,10 +3266,10 @@ function useSuiteTheme() {
3261
3266
 
3262
3267
  // src/suite/lib/theme-boot.ts
3263
3268
  function suiteThemeBootScript(options) {
3264
- var _a, _b, _c, _d;
3269
+ var _a2, _b, _c, _d;
3265
3270
  const light = JSON.stringify(options.lightThemeId);
3266
3271
  const dark = JSON.stringify(options.darkThemeId);
3267
- const storageKey = JSON.stringify((_a = options.storageKey) != null ? _a : null);
3272
+ const storageKey = JSON.stringify((_a2 = options.storageKey) != null ? _a2 : null);
3268
3273
  const metaLight = JSON.stringify((_b = options.themeColorLight) != null ? _b : null);
3269
3274
  const metaDark = JSON.stringify((_c = options.themeColorDark) != null ? _c : null);
3270
3275
  const fallback = JSON.stringify((_d = options.fallback) != null ? _d : "light");
@@ -3461,8 +3466,8 @@ function consumeSuiteAskAiOpenFromLocation() {
3461
3466
  }
3462
3467
  var pendingAskAiPrompt = null;
3463
3468
  function openSuiteAskAi(detail) {
3464
- var _a;
3465
- pendingAskAiPrompt = ((_a = detail == null ? void 0 : detail.prompt) == null ? void 0 : _a.trim()) || null;
3469
+ var _a2;
3470
+ pendingAskAiPrompt = ((_a2 = detail == null ? void 0 : detail.prompt) == null ? void 0 : _a2.trim()) || null;
3466
3471
  if (typeof window === "undefined") return;
3467
3472
  window.dispatchEvent(
3468
3473
  new CustomEvent(SUITE_OPEN_ASK_AI_EVENT, {
@@ -3534,9 +3539,9 @@ function SuiteAiPanel({
3534
3539
  const waiting = loading || isWaitingForReply;
3535
3540
  (0, import_react12.useEffect)(() => {
3536
3541
  function onOpen(event) {
3537
- var _a;
3542
+ var _a2;
3538
3543
  const detail = event.detail;
3539
- const queued = ((_a = detail == null ? void 0 : detail.prompt) == null ? void 0 : _a.trim()) || consumePendingAskAiPrompt();
3544
+ const queued = ((_a2 = detail == null ? void 0 : detail.prompt) == null ? void 0 : _a2.trim()) || consumePendingAskAiPrompt();
3540
3545
  setOpen(true);
3541
3546
  if (queued) {
3542
3547
  pendingPromptRef.current = queued;
@@ -3559,12 +3564,12 @@ function SuiteAiPanel({
3559
3564
  setAtBottom(distance < 64);
3560
3565
  }, []);
3561
3566
  const hydrate = (0, import_react12.useCallback)(async () => {
3562
- var _a, _b, _c;
3567
+ var _a2, _b, _c;
3563
3568
  setHydrating(true);
3564
3569
  setError("");
3565
3570
  try {
3566
3571
  const data = await fetchChat();
3567
- setMessages((_a = data.messages) != null ? _a : []);
3572
+ setMessages((_a2 = data.messages) != null ? _a2 : []);
3568
3573
  if (!data.configured) {
3569
3574
  setError("ShellStack AI is not configured for this workspace yet.");
3570
3575
  } else {
@@ -3582,9 +3587,9 @@ function SuiteAiPanel({
3582
3587
  }
3583
3588
  }, [fetchChat]);
3584
3589
  (0, import_react12.useEffect)(() => {
3585
- var _a;
3590
+ var _a2;
3586
3591
  if (!open) return;
3587
- const queued = (_a = pendingPromptRef.current) != null ? _a : consumePendingAskAiPrompt();
3592
+ const queued = (_a2 = pendingPromptRef.current) != null ? _a2 : consumePendingAskAiPrompt();
3588
3593
  pendingPromptRef.current = queued;
3589
3594
  void hydrate().then(() => {
3590
3595
  const pending = pendingPromptRef.current;
@@ -3596,8 +3601,8 @@ function SuiteAiPanel({
3596
3601
  if (open && atBottom) scrollToBottom();
3597
3602
  }, [messages, waiting, open, atBottom, scrollToBottom]);
3598
3603
  (0, import_react12.useEffect)(() => {
3599
- var _a;
3600
- if (open && !hydrating) (_a = textareaRef.current) == null ? void 0 : _a.focus();
3604
+ var _a2;
3605
+ if (open && !hydrating) (_a2 = textareaRef.current) == null ? void 0 : _a2.focus();
3601
3606
  }, [open, hydrating]);
3602
3607
  (0, import_react12.useEffect)(() => {
3603
3608
  if (!open) return;
@@ -3611,7 +3616,7 @@ function SuiteAiPanel({
3611
3616
  el.style.height = `${Math.min(el.scrollHeight, 176)}px`;
3612
3617
  }, [prompt, open]);
3613
3618
  async function ask(text) {
3614
- var _a;
3619
+ var _a2;
3615
3620
  const trimmed = text.trim();
3616
3621
  if (!trimmed || waiting) return;
3617
3622
  const controller = new AbortController();
@@ -3627,20 +3632,20 @@ function SuiteAiPanel({
3627
3632
  signal: controller.signal
3628
3633
  });
3629
3634
  if (controller.signal.aborted) return;
3630
- const nextMessages = (_a = result.messages) != null ? _a : [];
3635
+ const nextMessages = (_a2 = result.messages) != null ? _a2 : [];
3631
3636
  setMessages(nextMessages);
3632
3637
  notifySuiteMutated(
3633
3638
  nextMessages.flatMap((message) => {
3634
- var _a2;
3635
- return (_a2 = message.actions) != null ? _a2 : [];
3639
+ var _a3;
3640
+ return (_a3 = message.actions) != null ? _a3 : [];
3636
3641
  })
3637
3642
  );
3638
3643
  } catch (err) {
3639
3644
  if (controller.signal.aborted) return;
3640
3645
  setMessages(
3641
3646
  (prev) => {
3642
- var _a2, _b;
3643
- 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;
3647
+ var _a3, _b;
3648
+ return ((_a3 = prev[prev.length - 1]) == null ? void 0 : _a3.role) === "user" && ((_b = prev[prev.length - 1]) == null ? void 0 : _b.content) === trimmed ? prev.slice(0, -1) : prev;
3644
3649
  }
3645
3650
  );
3646
3651
  setPrompt(trimmed);
@@ -3653,8 +3658,8 @@ function SuiteAiPanel({
3653
3658
  }
3654
3659
  }
3655
3660
  function stop() {
3656
- var _a;
3657
- (_a = abortRef.current) == null ? void 0 : _a.abort();
3661
+ var _a2;
3662
+ (_a2 = abortRef.current) == null ? void 0 : _a2.abort();
3658
3663
  abortRef.current = null;
3659
3664
  setLoading(false);
3660
3665
  if (!cancelMessage) return;
@@ -3664,14 +3669,14 @@ function SuiteAiPanel({
3664
3669
  });
3665
3670
  }
3666
3671
  function retry() {
3667
- var _a;
3668
- const lastUser = (_a = [...messages].reverse().find((message) => message.role === "user")) == null ? void 0 : _a.content;
3672
+ var _a2;
3673
+ const lastUser = (_a2 = [...messages].reverse().find((message) => message.role === "user")) == null ? void 0 : _a2.content;
3669
3674
  setError("");
3670
3675
  if (lastUser) void ask(lastUser);
3671
3676
  else void hydrate();
3672
3677
  }
3673
3678
  async function saveEdit(index) {
3674
- var _a;
3679
+ var _a2;
3675
3680
  const trimmed = editDraft.trim();
3676
3681
  if (!trimmed || waiting) return;
3677
3682
  setEditingIndex(null);
@@ -3689,12 +3694,12 @@ function SuiteAiPanel({
3689
3694
  signal: controller.signal
3690
3695
  }) : await sendMessage({ prompt: trimmed, signal: controller.signal });
3691
3696
  if (controller.signal.aborted) return;
3692
- const nextMessages = (_a = result.messages) != null ? _a : [];
3697
+ const nextMessages = (_a2 = result.messages) != null ? _a2 : [];
3693
3698
  setMessages(nextMessages);
3694
3699
  notifySuiteMutated(
3695
3700
  nextMessages.flatMap((message) => {
3696
- var _a2;
3697
- return (_a2 = message.actions) != null ? _a2 : [];
3701
+ var _a3;
3702
+ return (_a3 = message.actions) != null ? _a3 : [];
3698
3703
  })
3699
3704
  );
3700
3705
  } catch (err) {
@@ -3732,18 +3737,18 @@ function SuiteAiPanel({
3732
3737
  }
3733
3738
  }
3734
3739
  async function handleResolve(actionId, decision) {
3735
- var _a;
3740
+ var _a2;
3736
3741
  if (!resolveAction || resolvingId) return;
3737
3742
  setResolvingId(actionId);
3738
3743
  setError("");
3739
3744
  try {
3740
3745
  const result = await resolveAction(actionId, decision);
3741
- const nextMessages = (_a = result.messages) != null ? _a : [];
3746
+ const nextMessages = (_a2 = result.messages) != null ? _a2 : [];
3742
3747
  setMessages(nextMessages);
3743
3748
  notifySuiteMutated(
3744
3749
  nextMessages.flatMap((message) => {
3745
- var _a2;
3746
- return (_a2 = message.actions) != null ? _a2 : [];
3750
+ var _a3;
3751
+ return (_a3 = message.actions) != null ? _a3 : [];
3747
3752
  })
3748
3753
  );
3749
3754
  } catch (err) {
@@ -3755,12 +3760,12 @@ function SuiteAiPanel({
3755
3760
  }
3756
3761
  }
3757
3762
  function onConversationClick(event) {
3758
- var _a;
3763
+ var _a2;
3759
3764
  if (event.defaultPrevented) return;
3760
3765
  if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
3761
3766
  return;
3762
3767
  }
3763
- const anchor = (_a = event.target) == null ? void 0 : _a.closest("a");
3768
+ const anchor = (_a2 = event.target) == null ? void 0 : _a2.closest("a");
3764
3769
  if (!anchor || !suiteAppBases) return;
3765
3770
  const href = anchor.href;
3766
3771
  if (!href) return;
@@ -3848,7 +3853,7 @@ function SuiteAiPanel({
3848
3853
  )) }) : null
3849
3854
  ] }) : null,
3850
3855
  messages.map((message, index) => {
3851
- var _a;
3856
+ var _a2;
3852
3857
  const isUser = message.role === "user";
3853
3858
  if (isUser) {
3854
3859
  if (editingIndex === index) {
@@ -3981,7 +3986,7 @@ function SuiteAiPanel({
3981
3986
  )
3982
3987
  }
3983
3988
  ) }),
3984
- ((_a = message.actions) != null ? _a : []).map((action) => /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
3989
+ ((_a2 = message.actions) != null ? _a2 : []).map((action) => /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
3985
3990
  "div",
3986
3991
  {
3987
3992
  "data-test": "ask-ai-action",
@@ -4153,9 +4158,9 @@ function SuiteWorkspaceSwitcher({
4153
4158
  triggerDataTest,
4154
4159
  footer
4155
4160
  }) {
4156
- var _a;
4161
+ var _a2;
4157
4162
  const [open, setOpen] = (0, import_react13.useState)(false);
4158
- const sections = (_a = groups == null ? void 0 : groups.filter((group) => group.workspaces.length > 0)) != null ? _a : workspaces.length > 0 ? [{ id: "workspaces", label: "Switch workspace", workspaces }] : [];
4163
+ const sections = (_a2 = groups == null ? void 0 : groups.filter((group) => group.workspaces.length > 0)) != null ? _a2 : workspaces.length > 0 ? [{ id: "workspaces", label: "Switch workspace", workspaces }] : [];
4159
4164
  return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
4160
4165
  DropdownMenu2,
4161
4166
  {
@@ -4857,7 +4862,7 @@ function SuiteSidebar({
4857
4862
  /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "min-h-0 flex-1", children: askAi })
4858
4863
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_jsx_runtime30.Fragment, { children: [
4859
4864
  /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("nav", { "aria-label": "Pages", className: "shrink-0 space-y-1", children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "space-y-1", children: navItems.map((item) => {
4860
- var _a;
4865
+ var _a2;
4861
4866
  const Icon = item.icon;
4862
4867
  const active = Boolean(item.active);
4863
4868
  const link = /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
@@ -4865,7 +4870,7 @@ function SuiteSidebar({
4865
4870
  {
4866
4871
  href: item.href,
4867
4872
  id: item.id,
4868
- "data-test": (_a = item.dataTest) != null ? _a : "nav-link",
4873
+ "data-test": (_a2 = item.dataTest) != null ? _a2 : "nav-link",
4869
4874
  "aria-current": active ? "page" : void 0,
4870
4875
  onClick: item.onClick,
4871
4876
  className: cn(
@@ -5071,8 +5076,8 @@ var shapeClass = {
5071
5076
  square: "ph-btn-square",
5072
5077
  wide: "ph-btn-wide"
5073
5078
  };
5074
- var Button = (0, import_react18.forwardRef)(function Button2(_a, ref) {
5075
- var _b = _a, {
5079
+ var Button = (0, import_react18.forwardRef)(function Button2(_a2, ref) {
5080
+ var _b = _a2, {
5076
5081
  variant = "secondary",
5077
5082
  size = "md",
5078
5083
  shape = "default",
@@ -5149,8 +5154,8 @@ var statusClassMap = {
5149
5154
  warning: "ph-alert-warning",
5150
5155
  danger: "ph-alert-danger"
5151
5156
  };
5152
- var Alert = (0, import_react19.forwardRef)(function Alert2(_a, ref) {
5153
- var _b = _a, {
5157
+ var Alert = (0, import_react19.forwardRef)(function Alert2(_a2, ref) {
5158
+ var _b = _a2, {
5154
5159
  status = "info",
5155
5160
  title,
5156
5161
  description,
@@ -5222,8 +5227,8 @@ var sizeMap = {
5222
5227
  sm: "text-[10px] px-1.5 py-0.5",
5223
5228
  md: ""
5224
5229
  };
5225
- var Badge = (0, import_react20.forwardRef)(function Badge2(_a, ref) {
5226
- var _b = _a, {
5230
+ var Badge = (0, import_react20.forwardRef)(function Badge2(_a2, ref) {
5231
+ var _b = _a2, {
5227
5232
  variant = "neutral",
5228
5233
  size = "md",
5229
5234
  children,
@@ -5260,8 +5265,8 @@ var variantMap2 = {
5260
5265
  elevated: "ph-card-elevated",
5261
5266
  highlighted: "ph-card-highlighted"
5262
5267
  };
5263
- var Card = (0, import_react21.forwardRef)(function Card2(_a, ref) {
5264
- var _b = _a, {
5268
+ var Card = (0, import_react21.forwardRef)(function Card2(_a2, ref) {
5269
+ var _b = _a2, {
5265
5270
  children,
5266
5271
  title,
5267
5272
  description,
@@ -5353,8 +5358,8 @@ var import_iconoir_react11 = require("iconoir-react");
5353
5358
  // src/components/ui/FormField.tsx
5354
5359
  var import_react22 = require("react");
5355
5360
  var import_jsx_runtime36 = require("react/jsx-runtime");
5356
- function FormField(_a) {
5357
- var _b = _a, {
5361
+ function FormField(_a2) {
5362
+ var _b = _a2, {
5358
5363
  controlId,
5359
5364
  label,
5360
5365
  hideLabel = false,
@@ -5414,8 +5419,8 @@ function joinIds(...ids) {
5414
5419
  const value = ids.filter(Boolean).join(" ");
5415
5420
  return value || void 0;
5416
5421
  }
5417
- var Input = (0, import_react23.forwardRef)(function Input2(_a, ref) {
5418
- var _b = _a, {
5422
+ var Input = (0, import_react23.forwardRef)(function Input2(_a2, ref) {
5423
+ var _b = _a2, {
5419
5424
  id: idProp,
5420
5425
  label,
5421
5426
  hideLabel = false,
@@ -5497,8 +5502,8 @@ var Input = (0, import_react23.forwardRef)(function Input2(_a, ref) {
5497
5502
  );
5498
5503
  });
5499
5504
  Input.displayName = "Input";
5500
- var Select = (0, import_react23.forwardRef)(function Select2(_a, ref) {
5501
- var _b = _a, {
5505
+ var Select = (0, import_react23.forwardRef)(function Select2(_a2, ref) {
5506
+ var _b = _a2, {
5502
5507
  id: idProp,
5503
5508
  label,
5504
5509
  hideLabel = false,
@@ -5548,8 +5553,8 @@ var Select = (0, import_react23.forwardRef)(function Select2(_a, ref) {
5548
5553
  ) });
5549
5554
  });
5550
5555
  Select.displayName = "Select";
5551
- var Textarea = (0, import_react23.forwardRef)(function Textarea2(_a, ref) {
5552
- var _b = _a, {
5556
+ var Textarea = (0, import_react23.forwardRef)(function Textarea2(_a2, ref) {
5557
+ var _b = _a2, {
5553
5558
  id: idProp,
5554
5559
  label,
5555
5560
  hideLabel = false,
@@ -5595,8 +5600,8 @@ var Textarea = (0, import_react23.forwardRef)(function Textarea2(_a, ref) {
5595
5600
  ) });
5596
5601
  });
5597
5602
  Textarea.displayName = "Textarea";
5598
- var Checkbox = (0, import_react23.forwardRef)(function Checkbox2(_a, ref) {
5599
- var _b = _a, {
5603
+ var Checkbox = (0, import_react23.forwardRef)(function Checkbox2(_a2, ref) {
5604
+ var _b = _a2, {
5600
5605
  id: idProp,
5601
5606
  label,
5602
5607
  error,
@@ -5650,8 +5655,8 @@ var Checkbox = (0, import_react23.forwardRef)(function Checkbox2(_a, ref) {
5650
5655
  ] });
5651
5656
  });
5652
5657
  Checkbox.displayName = "Checkbox";
5653
- var Radio = (0, import_react23.forwardRef)(function Radio2(_a, ref) {
5654
- var _b = _a, {
5658
+ var Radio = (0, import_react23.forwardRef)(function Radio2(_a2, ref) {
5659
+ var _b = _a2, {
5655
5660
  id: idProp,
5656
5661
  label,
5657
5662
  className,
@@ -5681,8 +5686,8 @@ var Radio = (0, import_react23.forwardRef)(function Radio2(_a, ref) {
5681
5686
  ] });
5682
5687
  });
5683
5688
  Radio.displayName = "Radio";
5684
- var Toggle = (0, import_react23.forwardRef)(function Toggle2(_a, ref) {
5685
- var _b = _a, {
5689
+ var Toggle = (0, import_react23.forwardRef)(function Toggle2(_a2, ref) {
5690
+ var _b = _a2, {
5686
5691
  id: idProp,
5687
5692
  label,
5688
5693
  className,
@@ -5713,8 +5718,8 @@ var Toggle = (0, import_react23.forwardRef)(function Toggle2(_a, ref) {
5713
5718
  ] });
5714
5719
  });
5715
5720
  Toggle.displayName = "Toggle";
5716
- var Range = (0, import_react23.forwardRef)(function Range2(_a, ref) {
5717
- var _b = _a, {
5721
+ var Range = (0, import_react23.forwardRef)(function Range2(_a2, ref) {
5722
+ var _b = _a2, {
5718
5723
  id: idProp,
5719
5724
  label,
5720
5725
  minLabel,
@@ -5744,8 +5749,8 @@ var Range = (0, import_react23.forwardRef)(function Range2(_a, ref) {
5744
5749
  ] });
5745
5750
  });
5746
5751
  Range.displayName = "Range";
5747
- var FileUpload = (0, import_react23.forwardRef)(function FileUpload2(_a, ref) {
5748
- var _b = _a, {
5752
+ var FileUpload = (0, import_react23.forwardRef)(function FileUpload2(_a2, ref) {
5753
+ var _b = _a2, {
5749
5754
  id: idProp,
5750
5755
  label,
5751
5756
  prompt = "Drop file or browse",
@@ -5833,9 +5838,9 @@ function Modal({
5833
5838
  restoreFocusRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
5834
5839
  },
5835
5840
  onCloseAutoFocus: (event) => {
5836
- var _a;
5841
+ var _a2;
5837
5842
  event.preventDefault();
5838
- (_a = restoreFocusRef.current) == null ? void 0 : _a.focus();
5843
+ (_a2 = restoreFocusRef.current) == null ? void 0 : _a2.focus();
5839
5844
  },
5840
5845
  onEscapeKeyDown: (event) => {
5841
5846
  if (!canDismiss || !closeOnEscape) event.preventDefault();
@@ -5904,15 +5909,15 @@ var AUTH_SCHEME_LABELS = {
5904
5909
  OAUTH2: "OAuth 2.0"
5905
5910
  };
5906
5911
  function authSchemeLabel(scheme) {
5907
- var _a;
5912
+ var _a2;
5908
5913
  const normalised = scheme.trim().toUpperCase();
5909
- return (_a = AUTH_SCHEME_LABELS[normalised]) != null ? _a : normalised.replace(/[-_]/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase());
5914
+ return (_a2 = AUTH_SCHEME_LABELS[normalised]) != null ? _a2 : normalised.replace(/[-_]/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase());
5910
5915
  }
5911
5916
  function authSchemesFor(item) {
5912
- var _a;
5917
+ var _a2;
5913
5918
  return Array.from(
5914
5919
  new Set(
5915
- ((_a = item.authSchemes) != null ? _a : []).map((scheme) => scheme.trim().toUpperCase()).filter(Boolean)
5920
+ ((_a2 = item.authSchemes) != null ? _a2 : []).map((scheme) => scheme.trim().toUpperCase()).filter(Boolean)
5916
5921
  )
5917
5922
  );
5918
5923
  }
@@ -5935,10 +5940,10 @@ var CATEGORY_APP_AFFINITY = {
5935
5940
  };
5936
5941
  var DEFAULT_APP_AFFINITY = ["tides", "kraken"];
5937
5942
  function suiteAppsForIntegration(categories) {
5938
- var _a;
5943
+ var _a2;
5939
5944
  const apps = /* @__PURE__ */ new Set();
5940
5945
  for (const category of categories != null ? categories : []) {
5941
- for (const app of (_a = CATEGORY_APP_AFFINITY[category.trim().toLowerCase()]) != null ? _a : []) {
5946
+ for (const app of (_a2 = CATEGORY_APP_AFFINITY[category.trim().toLowerCase()]) != null ? _a2 : []) {
5942
5947
  apps.add(app);
5943
5948
  }
5944
5949
  }
@@ -5995,8 +6000,8 @@ function SuiteIntegrationPicker({
5995
6000
  const itemCategories = (0, import_react25.useMemo)(
5996
6001
  () => Array.from(
5997
6002
  new Set(items.flatMap((item) => {
5998
- var _a;
5999
- return (_a = item.categories) != null ? _a : [];
6003
+ var _a2;
6004
+ return (_a2 = item.categories) != null ? _a2 : [];
6000
6005
  }))
6001
6006
  ).sort(),
6002
6007
  [items]
@@ -6006,8 +6011,8 @@ function SuiteIntegrationPicker({
6006
6011
  const activeCategory = controlledCategory != null ? controlledCategory : category;
6007
6012
  const categoryLabel = (value) => value.replace(/[-_]/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase());
6008
6013
  const filtered = onSearchChange || onCategoryChange ? items : items.filter((item) => {
6009
- var _a;
6010
- return item.label.toLowerCase().includes(activeSearch.trim().toLowerCase()) && (activeCategory === "all" || ((_a = item.categories) != null ? _a : []).includes(activeCategory));
6014
+ var _a2;
6015
+ return item.label.toLowerCase().includes(activeSearch.trim().toLowerCase()) && (activeCategory === "all" || ((_a2 = item.categories) != null ? _a2 : []).includes(activeCategory));
6011
6016
  });
6012
6017
  const visibleCategories = categories.filter(
6013
6018
  (value) => categoryLabel(value).toLowerCase().includes(categoryQuery.trim().toLowerCase())
@@ -6032,7 +6037,7 @@ function SuiteIntegrationPicker({
6032
6037
  closeCategoryMenu(true);
6033
6038
  }
6034
6039
  function moveCategoryFocus(event, value) {
6035
- var _a;
6040
+ var _a2;
6036
6041
  const index = categoryValues.indexOf(value);
6037
6042
  let nextIndex = null;
6038
6043
  if (event.key === "ArrowDown") nextIndex = (index + 1) % categoryValues.length;
@@ -6042,16 +6047,16 @@ function SuiteIntegrationPicker({
6042
6047
  else if (event.key === "End") nextIndex = categoryValues.length - 1;
6043
6048
  if (nextIndex === null) return;
6044
6049
  event.preventDefault();
6045
- (_a = categoryOptionRefs.current[categoryValues[nextIndex]]) == null ? void 0 : _a.focus();
6050
+ (_a2 = categoryOptionRefs.current[categoryValues[nextIndex]]) == null ? void 0 : _a2.focus();
6046
6051
  }
6047
6052
  function handleCategoryTriggerKeyDown(event) {
6048
- var _a;
6053
+ var _a2;
6049
6054
  if (event.key === "ArrowDown") {
6050
6055
  event.preventDefault();
6051
6056
  openCategoryMenu(activeCategory === "all" ? "all" : activeCategory);
6052
6057
  } else if (event.key === "ArrowUp") {
6053
6058
  event.preventDefault();
6054
- openCategoryMenu((_a = categoryValues.at(-1)) != null ? _a : "all");
6059
+ openCategoryMenu((_a2 = categoryValues.at(-1)) != null ? _a2 : "all");
6055
6060
  } else if (event.key === "Enter" || event.key === " ") {
6056
6061
  event.preventDefault();
6057
6062
  openCategoryMenu("search");
@@ -6069,7 +6074,7 @@ function SuiteIntegrationPicker({
6069
6074
  resetAuthForm();
6070
6075
  }
6071
6076
  async function prepareConnection(item, scheme) {
6072
- var _a;
6077
+ var _a2;
6073
6078
  setMethodItem(null);
6074
6079
  setAuthError(null);
6075
6080
  setConnectionError(null);
@@ -6091,7 +6096,7 @@ function SuiteIntegrationPicker({
6091
6096
  try {
6092
6097
  const details = await onFetchAuthFields(item, scheme);
6093
6098
  if (requestId !== authRequestRef.current) return;
6094
- const resolvedScheme = (_a = details.auth_scheme) != null ? _a : scheme;
6099
+ const resolvedScheme = (_a2 = details.auth_scheme) != null ? _a2 : scheme;
6095
6100
  if (details.managed) {
6096
6101
  setAuthItem(null);
6097
6102
  await onConnect(item, { auth_scheme: resolvedScheme });
@@ -6176,8 +6181,8 @@ function SuiteIntegrationPicker({
6176
6181
  (0, import_react25.useEffect)(() => {
6177
6182
  if (!categoryMenuOpen) return;
6178
6183
  const handlePointerDown = (event) => {
6179
- var _a;
6180
- if (!((_a = categoryMenuRef.current) == null ? void 0 : _a.contains(event.target))) {
6184
+ var _a2;
6185
+ if (!((_a2 = categoryMenuRef.current) == null ? void 0 : _a2.contains(event.target))) {
6181
6186
  closeCategoryMenu();
6182
6187
  }
6183
6188
  };
@@ -6192,11 +6197,11 @@ function SuiteIntegrationPicker({
6192
6197
  };
6193
6198
  }, [categoryMenuOpen]);
6194
6199
  (0, import_react25.useEffect)(() => {
6195
- var _a, _b, _c;
6200
+ var _a2, _b, _c;
6196
6201
  const target = pendingCategoryFocus.current;
6197
6202
  if (!target) return;
6198
6203
  pendingCategoryFocus.current = null;
6199
- if (target === "trigger") (_a = categoryTriggerRef.current) == null ? void 0 : _a.focus();
6204
+ if (target === "trigger") (_a2 = categoryTriggerRef.current) == null ? void 0 : _a2.focus();
6200
6205
  else if (target === "search") (_b = categorySearchRef.current) == null ? void 0 : _b.focus();
6201
6206
  else (_c = categoryOptionRefs.current[target]) == null ? void 0 : _c.focus();
6202
6207
  }, [activeCategory, categoryMenuOpen, categoryQuery, visibleCategories]);
@@ -6309,10 +6314,10 @@ function SuiteIntegrationPicker({
6309
6314
  placeholder: "Search categories...",
6310
6315
  "aria-label": "Search categories",
6311
6316
  onKeyDown: (event) => {
6312
- var _a;
6317
+ var _a2;
6313
6318
  if (event.key === "ArrowDown") {
6314
6319
  event.preventDefault();
6315
- (_a = categoryOptionRefs.current[categoryValues[0]]) == null ? void 0 : _a.focus();
6320
+ (_a2 = categoryOptionRefs.current[categoryValues[0]]) == null ? void 0 : _a2.focus();
6316
6321
  } else if (event.key === "Escape") {
6317
6322
  event.preventDefault();
6318
6323
  closeCategoryMenu(true);
@@ -6375,7 +6380,7 @@ function SuiteIntegrationPicker({
6375
6380
  }
6376
6381
  ) : /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "grid gap-3 sm:grid-cols-2 lg:grid-cols-3", children: [
6377
6382
  filtered.map((item) => {
6378
- var _a, _b;
6383
+ var _a2, _b;
6379
6384
  const isExpanded = expanded === item.id;
6380
6385
  const longDescription = item.description.length > DESCRIPTION_LIMIT;
6381
6386
  const text = isExpanded || !longDescription ? item.description : `${item.description.slice(0, DESCRIPTION_LIMIT).trimEnd()}...`;
@@ -6392,7 +6397,7 @@ function SuiteIntegrationPicker({
6392
6397
  onClick: () => longDescription && setExpanded(isExpanded ? null : item.id),
6393
6398
  "aria-expanded": isExpanded,
6394
6399
  children: /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { className: "flex items-start gap-3", children: [
6395
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-ph-muted text-ph-ink", children: (_a = item.icon) != null ? _a : /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_iconoir_react12.EvPlug, { className: "h-5 w-5", "aria-hidden": true }) }),
6400
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-ph-muted text-ph-ink", children: (_a2 = item.icon) != null ? _a2 : /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_iconoir_react12.EvPlug, { className: "h-5 w-5", "aria-hidden": true }) }),
6396
6401
  /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("span", { className: "min-w-0", children: [
6397
6402
  /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "block truncate font-medium text-ph-ink", children: item.label }),
6398
6403
  /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "mt-1 block text-xs text-ph-subtle", children: text }),
@@ -6600,12 +6605,12 @@ function SuiteIntegrationPicker({
6600
6605
  }
6601
6606
  ) : null,
6602
6607
  authItem.fields.map((field) => {
6603
- var _a, _b;
6608
+ var _a2, _b;
6604
6609
  return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
6605
6610
  Input,
6606
6611
  {
6607
6612
  label: field.label,
6608
- type: (_a = field.type) != null ? _a : "password",
6613
+ type: (_a2 = field.type) != null ? _a2 : "password",
6609
6614
  required: true,
6610
6615
  value: (_b = authValues[field.name]) != null ? _b : "",
6611
6616
  onChange: (event) => setAuthValues((current) => __spreadProps(__spreadValues({}, current), {
@@ -6648,8 +6653,8 @@ var ACTION_LABELS = {
6648
6653
  create_suite_notification: "Send a suite notification"
6649
6654
  };
6650
6655
  function actionLabel(actionType) {
6651
- var _a;
6652
- return (_a = ACTION_LABELS[actionType]) != null ? _a : actionType;
6656
+ var _a2;
6657
+ return (_a2 = ACTION_LABELS[actionType]) != null ? _a2 : actionType;
6653
6658
  }
6654
6659
  function formatDateTime(value) {
6655
6660
  if (!value) return "\u2014";
@@ -7037,214 +7042,566 @@ function SuiteIntegrationRules({
7037
7042
  }
7038
7043
 
7039
7044
  // src/suite/components/suite-clients-projects-directory.tsx
7045
+ var import_react28 = require("react");
7046
+ var import_iconoir_react15 = require("iconoir-react");
7047
+
7048
+ // src/suite/lib/palette-api.ts
7049
+ var _a;
7050
+ var PALETTE_URL = ((_a = process.env.NEXT_PUBLIC_PALETTE_URL) != null ? _a : "http://localhost:8010").replace(/\/$/, "");
7051
+ function toQuery(params) {
7052
+ const query = new URLSearchParams();
7053
+ for (const [key, value] of Object.entries(params != null ? params : {})) {
7054
+ if (value !== void 0 && value !== null && value !== "") {
7055
+ query.set(key, String(value));
7056
+ }
7057
+ }
7058
+ return query.toString();
7059
+ }
7060
+ async function paletteGet(path, params) {
7061
+ const suffix = toQuery(params);
7062
+ const response = await fetch(
7063
+ `${PALETTE_URL}${path}${suffix ? `?${suffix}` : ""}`,
7064
+ { headers: { Accept: "application/json" } }
7065
+ );
7066
+ if (!response.ok) {
7067
+ throw new Error(`Palette request failed (${response.status}).`);
7068
+ }
7069
+ return await response.json();
7070
+ }
7071
+ var cache = /* @__PURE__ */ new Map();
7072
+ async function paletteGetCached(path, params, ttlMs) {
7073
+ const key = `${path}?${toQuery(params)}`;
7074
+ const now = Date.now();
7075
+ const hit = cache.get(key);
7076
+ if (hit && hit.expires > now) return hit.value;
7077
+ const value = await paletteGet(path, params);
7078
+ cache.set(key, { expires: now + ttlMs, value });
7079
+ return value;
7080
+ }
7081
+ function fetchPaletteLibrary(options) {
7082
+ return paletteGetCached("/library", options, 5 * 6e4);
7083
+ }
7084
+ function fetchPaletteCollection(slug, options) {
7085
+ return paletteGetCached(
7086
+ `/collections/${slug}`,
7087
+ options,
7088
+ 2 * 6e4
7089
+ );
7090
+ }
7091
+ function findPaletteIcons(options) {
7092
+ return paletteGet("/find", options);
7093
+ }
7094
+ function paletteIconSrc(imageUrl, color) {
7095
+ if (!imageUrl || !color) return imageUrl;
7096
+ if (!imageUrl.includes("/svgrepo/")) return imageUrl;
7097
+ return `${PALETTE_URL}/render?src=${encodeURIComponent(imageUrl)}&color=${encodeURIComponent(color)}`;
7098
+ }
7099
+
7100
+ // src/suite/components/suite-entity-icon.tsx
7101
+ var import_jsx_runtime41 = require("react/jsx-runtime");
7102
+ function SuiteEntityIcon({
7103
+ imageUrl,
7104
+ label,
7105
+ color,
7106
+ className,
7107
+ roundedClass = "rounded-md",
7108
+ style,
7109
+ tinted = false
7110
+ }) {
7111
+ const hasColor = typeof color === "string" && /^#[0-9a-fA-F]{3,8}$/.test(color);
7112
+ const tint = hasColor ? color : null;
7113
+ const neutralBackground = "var(--ph-muted, rgba(127,127,127,0.08))";
7114
+ if (imageUrl) {
7115
+ const src = tinted && tint ? paletteIconSrc(imageUrl, tint) : imageUrl;
7116
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7117
+ "span",
7118
+ {
7119
+ className: cn2(
7120
+ "inline-flex shrink-0 items-center justify-center overflow-hidden leading-none",
7121
+ roundedClass,
7122
+ className
7123
+ ),
7124
+ style: __spreadValues({
7125
+ backgroundColor: tint ? `${tint}18` : neutralBackground
7126
+ }, style),
7127
+ children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("img", { src: src != null ? src : void 0, alt: "", className: "h-full w-full object-cover" })
7128
+ }
7129
+ );
7130
+ }
7131
+ const initial = label == null ? void 0 : label.trim().charAt(0).toUpperCase();
7132
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7133
+ "span",
7134
+ {
7135
+ className: cn2(
7136
+ "inline-flex shrink-0 items-center justify-center font-semibold leading-none",
7137
+ roundedClass,
7138
+ className
7139
+ ),
7140
+ style: __spreadValues({
7141
+ color: tint != null ? tint : "var(--ph-mutedtext)",
7142
+ backgroundColor: tint ? `${tint}18` : neutralBackground
7143
+ }, style),
7144
+ "aria-hidden": "true",
7145
+ children: initial ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "text-[0.7em]", children: initial }) : /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "block h-1.5 w-1.5 rounded-full bg-current opacity-40" })
7146
+ }
7147
+ );
7148
+ }
7149
+
7150
+ // src/suite/components/suite-palette-library.tsx
7040
7151
  var import_react27 = require("react");
7041
7152
  var import_iconoir_react14 = require("iconoir-react");
7042
- var import_jsx_runtime41 = require("react/jsx-runtime");
7043
- var DEFAULT_ICON = "castle-emblem";
7044
- var DEFAULT_COLOR = "#6366f1";
7045
- var DIRECTORY_ICON_OPTIONS = [
7046
- ["arena", "Arena"],
7047
- ["bridge", "Bridge"],
7048
- ["capitol", "Capitol"],
7049
- ["castle-emblem", "Castle"],
7050
- ["castle-flag", "Castle flag"],
7051
- ["lighthouse", "Lighthouse"],
7052
- ["tower", "Tower"],
7053
- ["wooden-sign", "Sign"],
7054
- ["anvil", "Anvil"],
7055
- ["book", "Book"],
7056
- ["chessboard", "Chessboard"],
7057
- ["cog", "Settings"],
7058
- ["hammer", "Build"],
7059
- ["light-bulb", "Idea"],
7060
- ["microphone", "Communication"],
7061
- ["quill-ink", "Writing"],
7062
- ["scroll-unfurled", "Notes"],
7063
- ["hourglass", "Planning"],
7064
- ["wrench", "Tools"],
7065
- ["archer", "Archer"],
7066
- ["archery-target", "Target"],
7067
- ["axe", "Axe"],
7068
- ["campfire", "Campfire"],
7069
- ["compass", "Compass"],
7070
- ["crossed-swords", "Battle"],
7071
- ["knight-helmet", "Knight"],
7072
- ["mountains", "Mountains"],
7073
- ["shield", "Shield"],
7074
- ["ship-emblem", "Voyage"],
7075
- ["sword", "Sword"],
7076
- ["trophy", "Trophy"],
7077
- ["apple", "Apple"],
7078
- ["butterfly", "Butterfly"],
7079
- ["clover", "Clover"],
7080
- ["dragon", "Dragon"],
7081
- ["fire", "Fire"],
7082
- ["flower", "Flower"],
7083
- ["flowers", "Flowers"],
7084
- ["grass", "Grass"],
7085
- ["leaf", "Leaf"],
7086
- ["pine-tree", "Pine tree"],
7087
- ["sun", "Sun"],
7088
- ["water-drop", "Water"],
7089
- ["aura", "Aura"],
7090
- ["crystal-ball", "Crystal ball"],
7091
- ["diamond", "Diamond"],
7092
- ["explosion", "Explosion"],
7093
- ["fire-symbol", "Fire symbol"],
7094
- ["gem", "Gem"],
7095
- ["lightning-trio", "Lightning"],
7096
- ["potion", "Potion"],
7097
- ["rune-stone", "Rune stone"],
7098
- ["skull", "Skull"],
7099
- ["tentacle", "Tentacle"],
7100
- ["wolf-head", "Wolf"],
7101
- ["anchor", "Anchor"],
7102
- ["beer", "Beer"],
7103
- ["carrot", "Carrot"],
7104
- ["cat", "Cat"],
7105
- ["crown", "Crown"],
7106
- ["gold-bar", "Gold bar"],
7107
- ["helmet", "Helmet"],
7108
- ["key", "Key"],
7109
- ["three-keys", "Keys"]
7153
+ var import_jsx_runtime42 = require("react/jsx-runtime");
7154
+ var PAGE_SIZE = 60;
7155
+ var DISCOVER_LIMIT = 120;
7156
+ var ICON_TYPES = [
7157
+ { value: "all", label: "All types" },
7158
+ { value: "line", label: "Line" },
7159
+ { value: "solid", label: "Solid" },
7160
+ { value: "duotone", label: "Duotone" },
7161
+ { value: "color", label: "Colour" },
7162
+ { value: "mixed", label: "Mixed" }
7110
7163
  ];
7111
- function isDirectoryIcon(value) {
7112
- return DIRECTORY_ICON_OPTIONS.some(([name]) => name === value);
7113
- }
7114
- function DirectoryIconPicker({
7164
+ function FilterSelect({
7165
+ icon: Icon,
7166
+ label,
7115
7167
  value,
7116
- preview,
7117
- onFileChange,
7118
- onClear,
7119
- onChange
7168
+ onChange,
7169
+ children
7120
7170
  }) {
7121
- const iconRefs = (0, import_react27.useRef)({});
7122
- function moveSelection(event, index) {
7123
- var _a;
7124
- let nextIndex = null;
7125
- if (event.key === "ArrowRight" || event.key === "ArrowDown") {
7126
- nextIndex = (index + 1) % DIRECTORY_ICON_OPTIONS.length;
7127
- } else if (event.key === "ArrowLeft" || event.key === "ArrowUp") {
7128
- nextIndex = (index - 1 + DIRECTORY_ICON_OPTIONS.length) % DIRECTORY_ICON_OPTIONS.length;
7129
- } else if (event.key === "Home") {
7130
- nextIndex = 0;
7131
- } else if (event.key === "End") {
7132
- nextIndex = DIRECTORY_ICON_OPTIONS.length - 1;
7133
- }
7134
- if (nextIndex === null) return;
7135
- event.preventDefault();
7136
- const [nextIcon] = DIRECTORY_ICON_OPTIONS[nextIndex];
7137
- onChange(nextIcon);
7138
- (_a = iconRefs.current[nextIcon]) == null ? void 0 : _a.focus();
7139
- }
7140
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "space-y-2", children: [
7141
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "mb-1.5 block text-sm font-medium text-ph-ink", children: "Icon" }),
7142
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7143
- "div",
7171
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "relative", children: [
7172
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7173
+ Icon,
7144
7174
  {
7145
- role: "radiogroup",
7146
- "aria-label": "Icon",
7147
- className: "grid grid-cols-6 gap-1.5 rounded-lg border border-ph-border p-1.5 sm:grid-cols-8",
7148
- children: DIRECTORY_ICON_OPTIONS.map(([name, label], index) => {
7149
- const selected = value === name;
7150
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7151
- "button",
7175
+ className: "pointer-events-none absolute left-2.5 top-1/2 h-4 w-4 -translate-y-1/2 text-ph-mutedtext",
7176
+ "aria-hidden": true
7177
+ }
7178
+ ),
7179
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7180
+ "select",
7181
+ {
7182
+ "aria-label": label,
7183
+ value,
7184
+ onChange: (event) => onChange(event.target.value),
7185
+ className: "h-full w-full appearance-none rounded-lg border border-ph-border bg-ph-surface py-2 pl-8 pr-7 text-sm text-ph-ink focus:border-ph-brand focus:outline-none",
7186
+ children
7187
+ }
7188
+ ),
7189
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7190
+ import_iconoir_react14.NavArrowDown,
7191
+ {
7192
+ className: "pointer-events-none absolute right-2 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-ph-mutedtext",
7193
+ "aria-hidden": true
7194
+ }
7195
+ )
7196
+ ] });
7197
+ }
7198
+ function SuitePaletteLibrary({
7199
+ onPick
7200
+ }) {
7201
+ var _a2, _b;
7202
+ const [collections, setCollections] = (0, import_react27.useState)([]);
7203
+ const [typeFilter, setTypeFilter] = (0, import_react27.useState)("all");
7204
+ const [collectionFilter, setCollectionFilter] = (0, import_react27.useState)("");
7205
+ const [libraryOpen, setLibraryOpen] = (0, import_react27.useState)(false);
7206
+ const [libraryQuery, setLibraryQuery] = (0, import_react27.useState)("");
7207
+ const libraryRef = (0, import_react27.useRef)(null);
7208
+ const [icons, setIcons] = (0, import_react27.useState)([]);
7209
+ const [total, setTotal] = (0, import_react27.useState)(0);
7210
+ const [page, setPage] = (0, import_react27.useState)(1);
7211
+ const [query, setQuery] = (0, import_react27.useState)("");
7212
+ const [loading, setLoading] = (0, import_react27.useState)(true);
7213
+ const [loadingMore, setLoadingMore] = (0, import_react27.useState)(false);
7214
+ const [error, setError] = (0, import_react27.useState)(null);
7215
+ const requestId = (0, import_react27.useRef)(0);
7216
+ const libraryOptions = (0, import_react27.useMemo)(() => {
7217
+ const list = collections.filter(
7218
+ (item) => typeFilter === "all" || item.style === typeFilter
7219
+ );
7220
+ return [...list].sort(
7221
+ (a, b) => Number(b.featured) - Number(a.featured) || a.name.localeCompare(b.name)
7222
+ );
7223
+ }, [collections, typeFilter]);
7224
+ const discoverIcons = (0, import_react27.useMemo)(() => {
7225
+ const seen = /* @__PURE__ */ new Set();
7226
+ const out = [];
7227
+ for (const collection of libraryOptions) {
7228
+ for (const url of collection.preview) {
7229
+ if (seen.has(url)) continue;
7230
+ seen.add(url);
7231
+ out.push({ id: url, name: collection.name, tags: [], url });
7232
+ if (out.length >= DISCOVER_LIMIT) return out;
7233
+ }
7234
+ }
7235
+ return out;
7236
+ }, [libraryOptions]);
7237
+ const loadCollection = (0, import_react27.useCallback)(async (slug, nextPage = 1) => {
7238
+ const id = ++requestId.current;
7239
+ if (nextPage === 1) {
7240
+ setLoading(true);
7241
+ setIcons([]);
7242
+ } else {
7243
+ setLoadingMore(true);
7244
+ }
7245
+ setError(null);
7246
+ try {
7247
+ const detail = await fetchPaletteCollection(slug, {
7248
+ page: nextPage,
7249
+ size: PAGE_SIZE
7250
+ });
7251
+ if (id !== requestId.current) return;
7252
+ setTotal(detail.count);
7253
+ setPage(nextPage);
7254
+ setIcons(
7255
+ (current) => nextPage === 1 ? detail.icons : [...current, ...detail.icons]
7256
+ );
7257
+ } catch (err) {
7258
+ if (id === requestId.current) {
7259
+ setError(err instanceof Error ? err.message : "Could not load icons.");
7260
+ }
7261
+ } finally {
7262
+ if (id === requestId.current) {
7263
+ setLoading(false);
7264
+ setLoadingMore(false);
7265
+ }
7266
+ }
7267
+ }, []);
7268
+ (0, import_react27.useEffect)(() => {
7269
+ let cancelled = false;
7270
+ fetchPaletteLibrary().then((library) => {
7271
+ if (cancelled) return;
7272
+ setCollections(library.collections);
7273
+ }).catch((err) => {
7274
+ if (cancelled) return;
7275
+ setError(err instanceof Error ? err.message : "Could not load the library.");
7276
+ setLoading(false);
7277
+ });
7278
+ return () => {
7279
+ cancelled = true;
7280
+ };
7281
+ }, []);
7282
+ (0, import_react27.useEffect)(() => {
7283
+ if (!collections.length) return;
7284
+ if (collectionFilter && !libraryOptions.some((c) => c.slug === collectionFilter)) {
7285
+ setCollectionFilter("");
7286
+ }
7287
+ }, [libraryOptions, collectionFilter, collections.length]);
7288
+ (0, import_react27.useEffect)(() => {
7289
+ if (query.trim()) return;
7290
+ if (collectionFilter) {
7291
+ void loadCollection(collectionFilter, 1);
7292
+ return;
7293
+ }
7294
+ requestId.current += 1;
7295
+ setLoading(false);
7296
+ setPage(1);
7297
+ setIcons(discoverIcons);
7298
+ setTotal(discoverIcons.length);
7299
+ }, [collectionFilter, query, loadCollection, discoverIcons]);
7300
+ (0, import_react27.useEffect)(() => {
7301
+ const term = query.trim();
7302
+ if (!term) return;
7303
+ const id = ++requestId.current;
7304
+ setLoading(true);
7305
+ setError(null);
7306
+ const handle = setTimeout(async () => {
7307
+ try {
7308
+ const results = await findPaletteIcons({
7309
+ q: term,
7310
+ collection: collectionFilter || void 0,
7311
+ style: typeFilter === "all" ? void 0 : typeFilter,
7312
+ limit: 120
7313
+ });
7314
+ if (id !== requestId.current) return;
7315
+ setTotal(results.total);
7316
+ setPage(1);
7317
+ setIcons(
7318
+ results.results.map((hit) => ({
7319
+ id: `${hit.collection}/${hit.id}`,
7320
+ name: hit.name,
7321
+ tags: hit.tags,
7322
+ url: hit.url
7323
+ }))
7324
+ );
7325
+ } catch (err) {
7326
+ if (id === requestId.current) {
7327
+ setError(err instanceof Error ? err.message : "Search failed.");
7328
+ }
7329
+ } finally {
7330
+ if (id === requestId.current) setLoading(false);
7331
+ }
7332
+ }, 250);
7333
+ return () => clearTimeout(handle);
7334
+ }, [query, collectionFilter, typeFilter]);
7335
+ const searching = Boolean(query.trim());
7336
+ const activeLibrary = (_a2 = collections.find((c) => c.slug === collectionFilter)) != null ? _a2 : null;
7337
+ const filteredLibraries = (0, import_react27.useMemo)(() => {
7338
+ const term = libraryQuery.trim().toLowerCase();
7339
+ if (!term) return libraryOptions;
7340
+ return libraryOptions.filter((c) => c.name.toLowerCase().includes(term));
7341
+ }, [libraryOptions, libraryQuery]);
7342
+ (0, import_react27.useEffect)(() => {
7343
+ if (!libraryOpen) return;
7344
+ const onPointerDown = (event) => {
7345
+ var _a3;
7346
+ if (!((_a3 = libraryRef.current) == null ? void 0 : _a3.contains(event.target))) setLibraryOpen(false);
7347
+ };
7348
+ document.addEventListener("pointerdown", onPointerDown);
7349
+ return () => document.removeEventListener("pointerdown", onPointerDown);
7350
+ }, [libraryOpen]);
7351
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "space-y-3", "data-test": "palette-icon-library", children: [
7352
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { ref: libraryRef, className: "space-y-2", children: [
7353
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex flex-col gap-2 sm:flex-row", children: [
7354
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "relative flex-1", children: [
7355
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7356
+ import_iconoir_react14.Search,
7152
7357
  {
7153
- type: "button",
7154
- role: "radio",
7155
- "aria-label": label,
7156
- "aria-checked": selected,
7157
- tabIndex: selected ? 0 : -1,
7158
- title: label,
7159
- onClick: () => onChange(name),
7160
- onKeyDown: (event) => moveSelection(event, index),
7161
- ref: (element) => {
7162
- iconRefs.current[name] = element;
7163
- },
7164
- className: cn2(
7165
- "flex h-9 items-center justify-center rounded-md text-ph-mutedtext hover:bg-ph-muted hover:text-ph-ink",
7166
- selected && "bg-ph-muted text-ph-ink ring-2 ring-ph-brand ring-inset"
7167
- ),
7168
- children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7169
- "i",
7358
+ className: "pointer-events-none absolute left-2.5 top-1/2 h-4 w-4 -translate-y-1/2 text-ph-mutedtext",
7359
+ "aria-hidden": true
7360
+ }
7361
+ ),
7362
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7363
+ "input",
7364
+ {
7365
+ type: "search",
7366
+ value: query,
7367
+ onChange: (event) => setQuery(event.target.value),
7368
+ placeholder: "Search icons \u2014 handshake, rocket, briefcase\u2026",
7369
+ "aria-label": "Search icons",
7370
+ className: "w-full rounded-lg border border-ph-border bg-ph-surface py-2 pl-8 pr-3 text-sm text-ph-ink placeholder:text-ph-mutedtext focus:border-ph-brand focus:outline-none"
7371
+ }
7372
+ )
7373
+ ] }),
7374
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
7375
+ "button",
7376
+ {
7377
+ type: "button",
7378
+ "aria-haspopup": "listbox",
7379
+ "aria-expanded": libraryOpen,
7380
+ onClick: () => setLibraryOpen((open) => !open),
7381
+ className: "flex items-center gap-2 rounded-lg border border-ph-border bg-ph-surface px-2.5 py-2 text-sm text-ph-ink hover:border-ph-brand focus:outline-none focus-visible:ring-2 focus-visible:ring-ph-brand",
7382
+ children: [
7383
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(import_iconoir_react14.FilterList, { className: "h-4 w-4 shrink-0 text-ph-mutedtext", "aria-hidden": true }),
7384
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "max-w-[10rem] truncate", children: (_b = activeLibrary == null ? void 0 : activeLibrary.name) != null ? _b : "All libraries" }),
7385
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7386
+ import_iconoir_react14.NavArrowDown,
7170
7387
  {
7171
- className: cn2("ra", `ra-${name}`, "text-base leading-none"),
7388
+ className: cn2(
7389
+ "h-3.5 w-3.5 shrink-0 text-ph-mutedtext transition-transform",
7390
+ libraryOpen && "rotate-180"
7391
+ ),
7172
7392
  "aria-hidden": true
7173
7393
  }
7174
7394
  )
7175
- },
7176
- name
7177
- );
7178
- })
7179
- }
7180
- ),
7181
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "rounded-lg border border-ph-border bg-ph-muted p-2", children: [
7182
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "flex items-center gap-2 text-sm font-medium text-ph-ink", children: [
7183
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_iconoir_react14.MediaImagePlus, { className: "h-4 w-4", "aria-hidden": true }),
7184
- " Custom image"
7185
- ] }),
7186
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { className: "mt-1 text-xs text-ph-mutedtext", children: "PNG, JPG, GIF, WebP, or SVG \u2014 max 512 KB." }),
7187
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7188
- FileUpload,
7189
- {
7190
- accept: "image/png,image/jpeg,image/gif,image/webp,image/svg+xml,.svg",
7191
- onChange: (event) => {
7192
- var _a, _b;
7193
- return onFileChange((_b = (_a = event.target.files) == null ? void 0 : _a[0]) != null ? _b : null);
7395
+ ]
7194
7396
  }
7195
- }
7196
- ),
7197
- preview ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "mt-2 flex items-center gap-2", children: [
7198
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7199
- "img",
7397
+ ),
7398
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7399
+ FilterSelect,
7200
7400
  {
7201
- src: preview,
7202
- alt: "",
7203
- className: "h-8 w-8 rounded object-cover"
7401
+ icon: import_iconoir_react14.Filter,
7402
+ label: "Filter by icon type",
7403
+ value: typeFilter,
7404
+ onChange: setTypeFilter,
7405
+ children: ICON_TYPES.map((type) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("option", { value: type.value, children: type.label }, type.value))
7204
7406
  }
7205
- ),
7206
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
7207
- "button",
7407
+ )
7408
+ ] }),
7409
+ libraryOpen ? /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "rounded-lg border border-ph-border bg-ph-surface p-2", children: [
7410
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "relative mb-2", children: [
7411
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7412
+ import_iconoir_react14.Search,
7413
+ {
7414
+ className: "pointer-events-none absolute left-2.5 top-1/2 h-4 w-4 -translate-y-1/2 text-ph-mutedtext",
7415
+ "aria-hidden": true
7416
+ }
7417
+ ),
7418
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7419
+ "input",
7420
+ {
7421
+ type: "search",
7422
+ autoFocus: true,
7423
+ value: libraryQuery,
7424
+ onChange: (event) => setLibraryQuery(event.target.value),
7425
+ placeholder: "Search libraries\u2026",
7426
+ "aria-label": "Search libraries",
7427
+ className: "w-full rounded-md border border-ph-border bg-ph-muted py-1.5 pl-8 pr-3 text-sm text-ph-ink placeholder:text-ph-mutedtext focus:border-ph-brand focus:outline-none"
7428
+ }
7429
+ )
7430
+ ] }),
7431
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
7432
+ "ul",
7208
7433
  {
7209
- type: "button",
7210
- className: "text-xs text-ph-mutedtext hover:text-ph-ink",
7211
- onClick: onClear,
7434
+ role: "listbox",
7435
+ "aria-label": "Libraries",
7436
+ className: "max-h-56 overflow-y-auto",
7212
7437
  children: [
7213
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_iconoir_react14.Trash, { className: "mr-1 inline h-3.5 w-3.5", "aria-hidden": true }),
7214
- " Remove custom image"
7438
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7439
+ "button",
7440
+ {
7441
+ type: "button",
7442
+ role: "option",
7443
+ "aria-selected": !collectionFilter,
7444
+ onClick: () => {
7445
+ setCollectionFilter("");
7446
+ setLibraryOpen(false);
7447
+ },
7448
+ className: cn2(
7449
+ "flex w-full items-center rounded-md px-2 py-1.5 text-left text-sm",
7450
+ !collectionFilter ? "bg-ph-muted text-ph-ink" : "text-ph-ink hover:bg-ph-muted"
7451
+ ),
7452
+ children: "All libraries"
7453
+ }
7454
+ ) }),
7455
+ filteredLibraries.map((collection) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
7456
+ "button",
7457
+ {
7458
+ type: "button",
7459
+ role: "option",
7460
+ "aria-selected": collectionFilter === collection.slug,
7461
+ onClick: () => {
7462
+ setCollectionFilter(collection.slug);
7463
+ setLibraryOpen(false);
7464
+ },
7465
+ className: cn2(
7466
+ "flex w-full items-center justify-between gap-2 rounded-md px-2 py-1.5 text-left text-sm",
7467
+ collectionFilter === collection.slug ? "bg-ph-muted text-ph-ink" : "text-ph-ink hover:bg-ph-muted"
7468
+ ),
7469
+ children: [
7470
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "truncate", children: collection.name }),
7471
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "shrink-0 text-xs text-ph-mutedtext", children: collection.count })
7472
+ ]
7473
+ }
7474
+ ) }, collection.slug)),
7475
+ filteredLibraries.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("li", { className: "px-2 py-4 text-center text-sm text-ph-mutedtext", children: "No libraries match." }) : null
7215
7476
  ]
7216
7477
  }
7217
7478
  )
7218
7479
  ] }) : null
7480
+ ] }),
7481
+ error ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { className: "text-sm text-ph-danger", children: error }) : loading ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { className: "py-8 text-center text-sm text-ph-mutedtext", children: "Loading icons\u2026" }) : icons.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("p", { className: "py-8 text-center text-sm text-ph-mutedtext", children: "No icons matched. Try another word or filter." }) : /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_jsx_runtime42.Fragment, { children: [
7482
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "max-h-[320px] overflow-y-auto rounded-lg border border-ph-border p-2", children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { className: "grid grid-cols-6 gap-1.5 sm:grid-cols-8", children: icons.map((icon) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7483
+ "button",
7484
+ {
7485
+ type: "button",
7486
+ onClick: () => onPick({ url: icon.url, name: icon.name }),
7487
+ title: icon.name,
7488
+ "aria-label": `Use ${icon.name}`,
7489
+ className: "flex h-10 items-center justify-center rounded-md border border-transparent p-1.5 hover:border-ph-brand hover:bg-ph-muted",
7490
+ children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7491
+ "img",
7492
+ {
7493
+ src: icon.url,
7494
+ alt: "",
7495
+ loading: "lazy",
7496
+ decoding: "async",
7497
+ className: "h-6 w-6"
7498
+ }
7499
+ )
7500
+ },
7501
+ icon.id
7502
+ )) }) }),
7503
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "flex items-center justify-between text-xs text-ph-mutedtext", children: [
7504
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { children: [
7505
+ icons.length,
7506
+ " of ",
7507
+ total,
7508
+ searching ? " matching" : activeLibrary ? ` in ${activeLibrary.name}` : " across all libraries"
7509
+ ] }),
7510
+ !searching && activeLibrary && icons.length < total ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7511
+ "button",
7512
+ {
7513
+ type: "button",
7514
+ disabled: loadingMore,
7515
+ onClick: () => void loadCollection(activeLibrary.slug, page + 1),
7516
+ className: cn2(
7517
+ "font-medium text-ph-brand hover:underline",
7518
+ loadingMore && "opacity-50"
7519
+ ),
7520
+ children: loadingMore ? "Loading\u2026" : "Load more"
7521
+ }
7522
+ ) : null
7523
+ ] })
7219
7524
  ] })
7220
7525
  ] });
7221
7526
  }
7222
- function DirectoryIcon({
7223
- item
7527
+
7528
+ // src/suite/components/suite-clients-projects-directory.tsx
7529
+ var import_jsx_runtime43 = require("react/jsx-runtime");
7530
+ var DEFAULT_ICON = "";
7531
+ var DEFAULT_COLOR = "";
7532
+ function DirectoryIconPicker({
7533
+ preview,
7534
+ label,
7535
+ color,
7536
+ onFileChange,
7537
+ onClear,
7538
+ onBrowse
7224
7539
  }) {
7225
- const icon = item.icon && isDirectoryIcon(item.icon) ? item.icon : DEFAULT_ICON;
7226
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7227
- "span",
7228
- {
7229
- className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg text-white",
7230
- style: { backgroundColor: item.color || "var(--ph-brand)" },
7231
- children: item.icon_image ? (
7232
- // eslint-disable-next-line @next/next/no-img-element
7233
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7234
- "img",
7540
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "space-y-2", children: [
7541
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "mb-1.5 block text-sm font-medium text-ph-ink", children: "Icon" }),
7542
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "rounded-lg border border-ph-border bg-ph-muted p-3", children: [
7543
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex items-center gap-3", children: [
7544
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
7545
+ SuiteEntityIcon,
7235
7546
  {
7236
- src: item.icon_image,
7237
- alt: "",
7238
- className: "h-full w-full rounded-lg object-cover"
7547
+ imageUrl: preview,
7548
+ label,
7549
+ color,
7550
+ tinted: true,
7551
+ className: "h-9 w-9 text-base"
7239
7552
  }
7240
- )
7241
- ) : /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7242
- "i",
7553
+ ),
7554
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "min-w-0 flex-1", children: [
7555
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: "text-sm font-medium text-ph-ink", children: preview ? "Custom image" : "No icon yet" }),
7556
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: "text-xs text-ph-mutedtext", children: preview ? "Shown on cards and lists." : "Browse the library or upload your own." })
7557
+ ] }),
7558
+ onBrowse ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
7559
+ "button",
7560
+ {
7561
+ type: "button",
7562
+ onClick: onBrowse,
7563
+ className: "rounded-md border border-ph-border px-3 py-1.5 text-xs font-medium text-ph-ink hover:border-ph-brand hover:bg-ph-surface",
7564
+ children: "Browse library"
7565
+ }
7566
+ ) : null
7567
+ ] }),
7568
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "mt-3", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
7569
+ FileUpload,
7243
7570
  {
7244
- className: cn2("ra", `ra-${icon}`, "text-base leading-none"),
7245
- "aria-hidden": true
7571
+ accept: "image/png,image/jpeg,image/gif,image/webp,image/svg+xml,.svg",
7572
+ onChange: (event) => {
7573
+ var _a2, _b;
7574
+ return onFileChange((_b = (_a2 = event.target.files) == null ? void 0 : _a2[0]) != null ? _b : null);
7575
+ }
7246
7576
  }
7247
- )
7577
+ ) }),
7578
+ preview ? /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
7579
+ "button",
7580
+ {
7581
+ type: "button",
7582
+ className: "mt-2 inline-flex items-center gap-1.5 rounded-md px-2 py-1 text-xs text-ph-mutedtext hover:bg-ph-surface hover:text-ph-ink",
7583
+ onClick: onClear,
7584
+ children: [
7585
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_iconoir_react15.Trash, { className: "h-3.5 w-3.5", "aria-hidden": true }),
7586
+ " Remove image"
7587
+ ]
7588
+ }
7589
+ ) : null
7590
+ ] })
7591
+ ] });
7592
+ }
7593
+ function DirectoryIcon({
7594
+ item
7595
+ }) {
7596
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
7597
+ SuiteEntityIcon,
7598
+ {
7599
+ imageUrl: item.icon_image,
7600
+ label: item.name,
7601
+ color: item.color,
7602
+ tinted: true,
7603
+ className: "h-8 w-8 text-sm",
7604
+ roundedClass: "rounded-lg"
7248
7605
  }
7249
7606
  );
7250
7607
  }
@@ -7260,51 +7617,53 @@ function SuiteClientsProjectsDirectory({
7260
7617
  onCreateProject,
7261
7618
  onUpdateProject,
7262
7619
  onDeleteProject,
7620
+ renderIconLibrary,
7263
7621
  dataTest = "suite-clients-projects-directory"
7264
7622
  }) {
7265
- var _a;
7266
- const [query, setQuery] = (0, import_react27.useState)("");
7267
- const [selectedClientId, setSelectedClientId] = (0, import_react27.useState)(null);
7268
- const [mobileDetail, setMobileDetail] = (0, import_react27.useState)(false);
7269
- const [editing, setEditing] = (0, import_react27.useState)(null);
7270
- const [draft, setDraft] = (0, import_react27.useState)({
7623
+ var _a2;
7624
+ const [query, setQuery] = (0, import_react28.useState)("");
7625
+ const [selectedClientId, setSelectedClientId] = (0, import_react28.useState)(null);
7626
+ const [mobileDetail, setMobileDetail] = (0, import_react28.useState)(false);
7627
+ const [editing, setEditing] = (0, import_react28.useState)(null);
7628
+ const [draft, setDraft] = (0, import_react28.useState)({
7271
7629
  name: "",
7272
7630
  icon: DEFAULT_ICON,
7273
7631
  color: DEFAULT_COLOR
7274
7632
  });
7275
- const [draftClientId, setDraftClientId] = (0, import_react27.useState)(null);
7276
- const [preview, setPreview] = (0, import_react27.useState)(null);
7277
- const [draftArchived, setDraftArchived] = (0, import_react27.useState)(false);
7278
- const [confirming, setConfirming] = (0, import_react27.useState)(null);
7279
- const [saving, setSaving] = (0, import_react27.useState)(false);
7280
- const [mutationError, setMutationError] = (0, import_react27.useState)(null);
7281
- const clientButtonRefs = (0, import_react27.useRef)({});
7282
- const backToClientsRef = (0, import_react27.useRef)(null);
7283
- const mobileFocusTarget = (0, import_react27.useRef)(null);
7284
- (0, import_react27.useEffect)(() => {
7285
- var _a2, _b;
7633
+ const [draftClientId, setDraftClientId] = (0, import_react28.useState)(null);
7634
+ const [preview, setPreview] = (0, import_react28.useState)(null);
7635
+ const [libraryOpen, setLibraryOpen] = (0, import_react28.useState)(false);
7636
+ const [draftArchived, setDraftArchived] = (0, import_react28.useState)(false);
7637
+ const [confirming, setConfirming] = (0, import_react28.useState)(null);
7638
+ const [saving, setSaving] = (0, import_react28.useState)(false);
7639
+ const [mutationError, setMutationError] = (0, import_react28.useState)(null);
7640
+ const clientButtonRefs = (0, import_react28.useRef)({});
7641
+ const backToClientsRef = (0, import_react28.useRef)(null);
7642
+ const mobileFocusTarget = (0, import_react28.useRef)(null);
7643
+ (0, import_react28.useEffect)(() => {
7644
+ var _a3, _b;
7286
7645
  if (selectedClientId && clients.some((client) => client.id === selectedClientId))
7287
7646
  return;
7288
- setSelectedClientId((_b = (_a2 = clients[0]) == null ? void 0 : _a2.id) != null ? _b : null);
7647
+ setSelectedClientId((_b = (_a3 = clients[0]) == null ? void 0 : _a3.id) != null ? _b : null);
7289
7648
  }, [clients, selectedClientId]);
7290
- (0, import_react27.useEffect)(() => {
7291
- var _a2, _b;
7649
+ (0, import_react28.useEffect)(() => {
7650
+ var _a3, _b;
7292
7651
  const target = mobileFocusTarget.current;
7293
7652
  if (!target) return;
7294
7653
  mobileFocusTarget.current = null;
7295
- if (target === "detail") (_a2 = backToClientsRef.current) == null ? void 0 : _a2.focus();
7654
+ if (target === "detail") (_a3 = backToClientsRef.current) == null ? void 0 : _a3.focus();
7296
7655
  else if (selectedClientId)
7297
7656
  (_b = clientButtonRefs.current[selectedClientId]) == null ? void 0 : _b.focus();
7298
7657
  }, [mobileDetail, selectedClientId]);
7299
- const filteredClients = (0, import_react27.useMemo)(() => {
7658
+ const filteredClients = (0, import_react28.useMemo)(() => {
7300
7659
  const value = query.trim().toLowerCase();
7301
7660
  return [...clients].sort((a, b) => a.name.localeCompare(b.name)).filter((client) => !value || client.name.toLowerCase().includes(value));
7302
7661
  }, [clients, query]);
7303
- const selectedClient = (_a = clients.find((client) => client.id === selectedClientId)) != null ? _a : null;
7662
+ const selectedClient = (_a2 = clients.find((client) => client.id === selectedClientId)) != null ? _a2 : null;
7304
7663
  const selectedProjects = projects.filter((project) => project.clientId === selectedClientId).sort((a, b) => a.name.localeCompare(b.name));
7305
7664
  function isMobileDirectoryView() {
7306
- var _a2, _b;
7307
- return (_b = (_a2 = window.matchMedia) == null ? void 0 : _a2.call(window, "(max-width: 1023px)").matches) != null ? _b : false;
7665
+ var _a3, _b;
7666
+ return (_b = (_a3 = window.matchMedia) == null ? void 0 : _a3.call(window, "(max-width: 1023px)").matches) != null ? _b : false;
7308
7667
  }
7309
7668
  function selectClient(client) {
7310
7669
  setSelectedClientId(client.id);
@@ -7312,7 +7671,7 @@ function SuiteClientsProjectsDirectory({
7312
7671
  if (isMobileDirectoryView()) mobileFocusTarget.current = "detail";
7313
7672
  }
7314
7673
  function moveClientSelection(event, index) {
7315
- var _a2;
7674
+ var _a3;
7316
7675
  let nextIndex = null;
7317
7676
  if (event.key === "ArrowDown") {
7318
7677
  nextIndex = (index + 1) % filteredClients.length;
@@ -7327,7 +7686,7 @@ function SuiteClientsProjectsDirectory({
7327
7686
  event.preventDefault();
7328
7687
  const client = filteredClients[nextIndex];
7329
7688
  selectClient(client);
7330
- if (!isMobileDirectoryView()) (_a2 = clientButtonRefs.current[client.id]) == null ? void 0 : _a2.focus();
7689
+ if (!isMobileDirectoryView()) (_a3 = clientButtonRefs.current[client.id]) == null ? void 0 : _a3.focus();
7331
7690
  }
7332
7691
  function openNew(kind) {
7333
7692
  setMutationError(null);
@@ -7336,6 +7695,7 @@ function SuiteClientsProjectsDirectory({
7336
7695
  icon: DEFAULT_ICON,
7337
7696
  color: DEFAULT_COLOR,
7338
7697
  iconImageFile: null,
7698
+ iconImageUrl: null,
7339
7699
  clearIconImage: false
7340
7700
  });
7341
7701
  setPreview(null);
@@ -7344,13 +7704,14 @@ function SuiteClientsProjectsDirectory({
7344
7704
  setEditing({ kind: kind === "client" ? "new-client" : "new-project" });
7345
7705
  }
7346
7706
  function openEdit(item, kind) {
7347
- var _a2;
7707
+ var _a3, _b;
7348
7708
  setMutationError(null);
7349
7709
  setDraft({
7350
7710
  name: item.name,
7351
- icon: item.icon && isDirectoryIcon(item.icon) ? item.icon : DEFAULT_ICON,
7711
+ icon: (_a3 = item.icon) != null ? _a3 : DEFAULT_ICON,
7352
7712
  color: item.color || DEFAULT_COLOR,
7353
7713
  iconImageFile: null,
7714
+ iconImageUrl: null,
7354
7715
  clearIconImage: false
7355
7716
  });
7356
7717
  setPreview(item.icon_image || null);
@@ -7358,7 +7719,7 @@ function SuiteClientsProjectsDirectory({
7358
7719
  kind === "project" && Boolean(item.isArchived)
7359
7720
  );
7360
7721
  setDraftClientId(
7361
- kind === "project" ? (_a2 = item.clientId) != null ? _a2 : null : null
7722
+ kind === "project" ? (_b = item.clientId) != null ? _b : null : null
7362
7723
  );
7363
7724
  setEditing({ kind, item });
7364
7725
  }
@@ -7372,6 +7733,7 @@ function SuiteClientsProjectsDirectory({
7372
7733
  if (preview == null ? void 0 : preview.startsWith("blob:")) URL.revokeObjectURL(preview);
7373
7734
  setDraft((current) => __spreadProps(__spreadValues({}, current), {
7374
7735
  iconImageFile: file,
7736
+ iconImageUrl: null,
7375
7737
  clearIconImage: false
7376
7738
  }));
7377
7739
  setPreview(URL.createObjectURL(file));
@@ -7381,9 +7743,21 @@ function SuiteClientsProjectsDirectory({
7381
7743
  setPreview(null);
7382
7744
  setDraft((current) => __spreadProps(__spreadValues({}, current), {
7383
7745
  iconImageFile: null,
7746
+ iconImageUrl: null,
7384
7747
  clearIconImage: true
7385
7748
  }));
7386
7749
  }
7750
+ function pickFromLibrary(icon) {
7751
+ if (preview == null ? void 0 : preview.startsWith("blob:")) URL.revokeObjectURL(preview);
7752
+ setMutationError(null);
7753
+ setPreview(icon.url);
7754
+ setDraft((current) => __spreadProps(__spreadValues({}, current), {
7755
+ iconImageFile: null,
7756
+ iconImageUrl: icon.url,
7757
+ clearIconImage: false
7758
+ }));
7759
+ setLibraryOpen(false);
7760
+ }
7387
7761
  function closeEditor() {
7388
7762
  if (!saving) setEditing(null);
7389
7763
  }
@@ -7419,14 +7793,14 @@ function SuiteClientsProjectsDirectory({
7419
7793
  setConfirming({ item, kind });
7420
7794
  }
7421
7795
  async function toggleArchive(project) {
7422
- var _a2;
7796
+ var _a3, _b;
7423
7797
  if (!onUpdateProject) return;
7424
7798
  try {
7425
7799
  await onUpdateProject(project, {
7426
7800
  name: project.name,
7427
- icon: project.icon && isDirectoryIcon(project.icon) ? project.icon : DEFAULT_ICON,
7801
+ icon: (_a3 = project.icon) != null ? _a3 : DEFAULT_ICON,
7428
7802
  color: project.color || DEFAULT_COLOR,
7429
- clientId: (_a2 = project.clientId) != null ? _a2 : null,
7803
+ clientId: (_b = project.clientId) != null ? _b : null,
7430
7804
  isArchived: !project.isArchived
7431
7805
  });
7432
7806
  } catch (err) {
@@ -7449,10 +7823,10 @@ function SuiteClientsProjectsDirectory({
7449
7823
  );
7450
7824
  }
7451
7825
  }
7452
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { "data-test": dataTest, className: "space-y-3", children: [
7453
- error || mutationError ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Alert, { status: "danger", live: "assertive", children: error || mutationError }) : null,
7454
- loading ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { className: "text-sm text-ph-mutedtext", children: "Loading directory..." }) : /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "overflow-hidden rounded-xl border border-ph-border bg-ph-surface lg:grid lg:min-h-[22rem] lg:grid-cols-[minmax(14rem,18rem)_1fr]", children: [
7455
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
7826
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { "data-test": dataTest, className: "space-y-3", children: [
7827
+ error || mutationError ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Alert, { status: "danger", live: "assertive", children: error || mutationError }) : null,
7828
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: "text-sm text-ph-mutedtext", children: "Loading directory..." }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "overflow-hidden rounded-xl border border-ph-border bg-ph-surface lg:grid lg:min-h-[22rem] lg:grid-cols-[minmax(14rem,18rem)_1fr]", children: [
7829
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
7456
7830
  "section",
7457
7831
  {
7458
7832
  className: cn2(
@@ -7460,16 +7834,16 @@ function SuiteClientsProjectsDirectory({
7460
7834
  mobileDetail ? "hidden lg:block" : "block"
7461
7835
  ),
7462
7836
  children: [
7463
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "flex h-14 items-center gap-2 border-b border-ph-border px-3", children: [
7464
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "relative min-w-0 flex-1", children: [
7465
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7466
- import_iconoir_react14.Search,
7837
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex h-14 items-center gap-2 border-b border-ph-border px-3", children: [
7838
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "relative min-w-0 flex-1", children: [
7839
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
7840
+ import_iconoir_react15.Search,
7467
7841
  {
7468
7842
  className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-ph-mutedtext",
7469
7843
  "aria-hidden": true
7470
7844
  }
7471
7845
  ),
7472
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7846
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
7473
7847
  Input,
7474
7848
  {
7475
7849
  hideLabel: true,
@@ -7481,18 +7855,18 @@ function SuiteClientsProjectsDirectory({
7481
7855
  }
7482
7856
  )
7483
7857
  ] }),
7484
- canEdit && onCreateClient ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7858
+ canEdit && onCreateClient ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
7485
7859
  Button,
7486
7860
  {
7487
7861
  size: "sm",
7488
7862
  variant: "primary",
7489
- icon: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_iconoir_react14.Plus, { className: "h-4 w-4" }),
7863
+ icon: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_iconoir_react15.Plus, { className: "h-4 w-4" }),
7490
7864
  onClick: () => openNew("client"),
7491
7865
  children: "New client"
7492
7866
  }
7493
7867
  ) : null
7494
7868
  ] }),
7495
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7869
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
7496
7870
  "ul",
7497
7871
  {
7498
7872
  role: "listbox",
@@ -7503,7 +7877,7 @@ function SuiteClientsProjectsDirectory({
7503
7877
  const count = projects.filter(
7504
7878
  (project) => project.clientId === client.id
7505
7879
  ).length;
7506
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("li", { role: "none", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
7880
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("li", { role: "none", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
7507
7881
  "button",
7508
7882
  {
7509
7883
  type: "button",
@@ -7520,10 +7894,10 @@ function SuiteClientsProjectsDirectory({
7520
7894
  selected ? "bg-ph-muted" : "hover:bg-ph-canvas"
7521
7895
  ),
7522
7896
  children: [
7523
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(DirectoryIcon, { item: client }),
7524
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { className: "min-w-0 flex-1", children: [
7525
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "block truncate text-sm font-medium text-ph-ink", children: client.name }),
7526
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { className: "text-xs text-ph-mutedtext", children: [
7897
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(DirectoryIcon, { item: client }),
7898
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: "min-w-0 flex-1", children: [
7899
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "block truncate text-sm font-medium text-ph-ink", children: client.name }),
7900
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: "text-xs text-ph-mutedtext", children: [
7527
7901
  count,
7528
7902
  " project",
7529
7903
  count === 1 ? "" : "s"
@@ -7532,13 +7906,13 @@ function SuiteClientsProjectsDirectory({
7532
7906
  ]
7533
7907
  }
7534
7908
  ) }, client.id);
7535
- }) : /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("li", { className: "px-3 py-8 text-center text-sm text-ph-mutedtext", children: clients.length ? "No matches." : "Add a client to get started." })
7909
+ }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("li", { className: "px-3 py-8 text-center text-sm text-ph-mutedtext", children: clients.length ? "No matches." : "Add a client to get started." })
7536
7910
  }
7537
7911
  )
7538
7912
  ]
7539
7913
  }
7540
7914
  ),
7541
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
7915
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
7542
7916
  "section",
7543
7917
  {
7544
7918
  className: cn2(
@@ -7546,8 +7920,8 @@ function SuiteClientsProjectsDirectory({
7546
7920
  mobileDetail ? "flex" : "hidden lg:flex"
7547
7921
  ),
7548
7922
  children: [
7549
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "flex min-h-14 items-center gap-2 border-b border-ph-border px-3 py-2", children: selectedClient ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_jsx_runtime41.Fragment, { children: [
7550
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7923
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "flex min-h-14 items-center gap-2 border-b border-ph-border px-3 py-2", children: selectedClient ? /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_jsx_runtime43.Fragment, { children: [
7924
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
7551
7925
  "button",
7552
7926
  {
7553
7927
  type: "button",
@@ -7558,36 +7932,36 @@ function SuiteClientsProjectsDirectory({
7558
7932
  setMobileDetail(false);
7559
7933
  },
7560
7934
  "aria-label": "Back to clients",
7561
- children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_iconoir_react14.ArrowLeft, { className: "h-4 w-4" })
7935
+ children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_iconoir_react15.ArrowLeft, { className: "h-4 w-4" })
7562
7936
  }
7563
7937
  ),
7564
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(DirectoryIcon, { item: selectedClient }),
7565
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "min-w-0 flex-1", children: [
7566
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("h3", { className: "truncate text-sm font-semibold text-ph-ink", children: selectedClient.name }),
7567
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("p", { className: "text-xs text-ph-mutedtext", children: [
7938
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(DirectoryIcon, { item: selectedClient }),
7939
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "min-w-0 flex-1", children: [
7940
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("h3", { className: "truncate text-sm font-semibold text-ph-ink", children: selectedClient.name }),
7941
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("p", { className: "text-xs text-ph-mutedtext", children: [
7568
7942
  selectedProjects.length,
7569
7943
  " project",
7570
7944
  selectedProjects.length === 1 ? "" : "s"
7571
7945
  ] })
7572
7946
  ] }),
7573
- canEdit && (onUpdateClient || onDeleteClient) ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { onClick: (event) => event.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7947
+ canEdit && (onUpdateClient || onDeleteClient) ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { onClick: (event) => event.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
7574
7948
  DropdownMenu,
7575
7949
  {
7576
7950
  "aria-label": `Actions for ${selectedClient.name}`,
7577
7951
  align: "end",
7578
- trigger: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { className: "inline-flex h-8 w-8 items-center justify-center rounded-md text-ph-mutedtext hover:bg-ph-muted hover:text-ph-ink", children: [
7579
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_iconoir_react14.MoreHoriz, { className: "h-4 w-4", "aria-hidden": true }),
7580
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "sr-only", children: "Client actions" })
7952
+ trigger: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: "inline-flex h-8 w-8 items-center justify-center rounded-md text-ph-mutedtext hover:bg-ph-muted hover:text-ph-ink", children: [
7953
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_iconoir_react15.MoreHoriz, { className: "h-4 w-4", "aria-hidden": true }),
7954
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "sr-only", children: "Client actions" })
7581
7955
  ] }),
7582
- children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "p-1", children: [
7583
- onUpdateClient ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7956
+ children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "p-1", children: [
7957
+ onUpdateClient ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
7584
7958
  DropdownItem,
7585
7959
  {
7586
7960
  onClick: () => openEdit(selectedClient, "client"),
7587
7961
  children: "Edit client"
7588
7962
  }
7589
7963
  ) : null,
7590
- onDeleteClient ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7964
+ onDeleteClient ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
7591
7965
  DropdownItem,
7592
7966
  {
7593
7967
  className: "text-red-600",
@@ -7598,32 +7972,32 @@ function SuiteClientsProjectsDirectory({
7598
7972
  ] })
7599
7973
  }
7600
7974
  ) }) : null
7601
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { className: "text-sm text-ph-mutedtext", children: "Select a client" }) }),
7602
- canEdit && onCreateProject ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "border-b border-ph-border p-3", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7975
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: "text-sm text-ph-mutedtext", children: "Select a client" }) }),
7976
+ canEdit && onCreateProject ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "border-b border-ph-border p-3", children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
7603
7977
  Button,
7604
7978
  {
7605
7979
  variant: "primary",
7606
- icon: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_iconoir_react14.Plus, { className: "h-4 w-4" }),
7980
+ icon: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_iconoir_react15.Plus, { className: "h-4 w-4" }),
7607
7981
  onClick: () => openNew("project"),
7608
7982
  children: "Add project"
7609
7983
  }
7610
7984
  ) }) : null,
7611
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("ul", { className: "flex-1 p-2", children: selectedClient && selectedProjects.length ? selectedProjects.map((project) => /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
7985
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("ul", { className: "flex-1 p-2", children: selectedClient && selectedProjects.length ? selectedProjects.map((project) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
7612
7986
  "div",
7613
7987
  {
7614
7988
  className: "flex items-center gap-3 rounded-lg px-2 py-1 hover:bg-ph-canvas",
7615
7989
  onClick: () => openEdit(project, "project"),
7616
7990
  children: [
7617
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
7991
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
7618
7992
  "button",
7619
7993
  {
7620
7994
  type: "button",
7621
7995
  className: "flex min-w-0 flex-1 items-center gap-3 rounded-lg py-1 text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-brand",
7622
7996
  onClick: () => openEdit(project, "project"),
7623
7997
  children: [
7624
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(DirectoryIcon, { item: project }),
7625
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { className: "min-w-0 flex-1", children: [
7626
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7998
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(DirectoryIcon, { item: project }),
7999
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: "min-w-0 flex-1", children: [
8000
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
7627
8001
  "span",
7628
8002
  {
7629
8003
  className: cn2(
@@ -7633,36 +8007,36 @@ function SuiteClientsProjectsDirectory({
7633
8007
  children: project.name
7634
8008
  }
7635
8009
  ),
7636
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "text-xs text-ph-mutedtext", children: project.isArchived ? "Archived" : "Active" })
8010
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "text-xs text-ph-mutedtext", children: project.isArchived ? "Archived" : "Active" })
7637
8011
  ] })
7638
8012
  ]
7639
8013
  }
7640
8014
  ),
7641
- canEdit && (onUpdateProject || onDeleteProject) ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { onClick: (event) => event.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8015
+ canEdit && (onUpdateProject || onDeleteProject) ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { onClick: (event) => event.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
7642
8016
  DropdownMenu,
7643
8017
  {
7644
8018
  "aria-label": `Actions for ${project.name}`,
7645
8019
  align: "end",
7646
- trigger: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("span", { className: "inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-md text-ph-mutedtext hover:bg-ph-muted hover:text-ph-ink", children: [
7647
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7648
- import_iconoir_react14.MoreHoriz,
8020
+ trigger: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("span", { className: "inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-md text-ph-mutedtext hover:bg-ph-muted hover:text-ph-ink", children: [
8021
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
8022
+ import_iconoir_react15.MoreHoriz,
7649
8023
  {
7650
8024
  className: "h-4 w-4",
7651
8025
  "aria-hidden": true
7652
8026
  }
7653
8027
  ),
7654
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "sr-only", children: "Project actions" })
8028
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "sr-only", children: "Project actions" })
7655
8029
  ] }),
7656
- children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "p-1", children: [
7657
- onUpdateProject ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_jsx_runtime41.Fragment, { children: [
7658
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8030
+ children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "p-1", children: [
8031
+ onUpdateProject ? /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_jsx_runtime43.Fragment, { children: [
8032
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
7659
8033
  DropdownItem,
7660
8034
  {
7661
8035
  onClick: () => openEdit(project, "project"),
7662
8036
  children: "Edit project"
7663
8037
  }
7664
8038
  ),
7665
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8039
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
7666
8040
  DropdownItem,
7667
8041
  {
7668
8042
  onClick: () => void toggleArchive(project),
@@ -7670,7 +8044,7 @@ function SuiteClientsProjectsDirectory({
7670
8044
  }
7671
8045
  )
7672
8046
  ] }) : null,
7673
- onDeleteProject ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8047
+ onDeleteProject ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
7674
8048
  DropdownItem,
7675
8049
  {
7676
8050
  className: "text-red-600",
@@ -7683,20 +8057,20 @@ function SuiteClientsProjectsDirectory({
7683
8057
  ) }) : null
7684
8058
  ]
7685
8059
  }
7686
- ) }, project.id)) : /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("li", { className: "px-3 py-8 text-center text-sm text-ph-mutedtext", children: selectedClient ? "No projects yet." : "Select a client to see its projects." }) })
8060
+ ) }, project.id)) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("li", { className: "px-3 py-8 text-center text-sm text-ph-mutedtext", children: selectedClient ? "No projects yet." : "Select a client to see its projects." }) })
7687
8061
  ]
7688
8062
  }
7689
8063
  )
7690
8064
  ] }),
7691
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8065
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
7692
8066
  Modal,
7693
8067
  {
7694
8068
  open: editing !== null,
7695
8069
  onClose: closeEditor,
7696
8070
  title: (editing == null ? void 0 : editing.kind.includes("project")) ? editing.kind === "new-project" ? "New project" : "Edit project" : (editing == null ? void 0 : editing.kind) === "new-client" ? "New client" : "Edit client",
7697
- footer: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "flex justify-end gap-2", children: [
7698
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Button, { variant: "tertiary", onClick: closeEditor, disabled: saving, children: "Cancel" }),
7699
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8071
+ footer: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex justify-end gap-2", children: [
8072
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Button, { variant: "tertiary", onClick: closeEditor, disabled: saving, children: "Cancel" }),
8073
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
7700
8074
  Button,
7701
8075
  {
7702
8076
  variant: "primary",
@@ -7706,8 +8080,8 @@ function SuiteClientsProjectsDirectory({
7706
8080
  }
7707
8081
  )
7708
8082
  ] }),
7709
- children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "space-y-3", children: [
7710
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8083
+ children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "space-y-3", children: [
8084
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
7711
8085
  Input,
7712
8086
  {
7713
8087
  label: "Name",
@@ -7716,22 +8090,35 @@ function SuiteClientsProjectsDirectory({
7716
8090
  onChange: (event) => setDraft(__spreadProps(__spreadValues({}, draft), { name: event.target.value }))
7717
8091
  }
7718
8092
  ),
7719
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8093
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
7720
8094
  DirectoryIconPicker,
7721
8095
  {
7722
- value: isDirectoryIcon(draft.icon) ? draft.icon : DEFAULT_ICON,
7723
8096
  preview,
8097
+ label: draft.name,
8098
+ color: draft.color,
7724
8099
  onFileChange: chooseImage,
7725
8100
  onClear: clearImage,
7726
- onChange: (icon) => {
7727
- if (preview) clearImage();
7728
- setDraft((current) => __spreadProps(__spreadValues({}, current), { icon }));
7729
- }
8101
+ onBrowse: () => setLibraryOpen(true)
7730
8102
  }
7731
8103
  ),
7732
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { children: [
7733
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "mb-1.5 block text-sm font-medium text-ph-ink", children: "Colour" }),
7734
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "flex flex-wrap gap-2", children: [
8104
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { children: [
8105
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "mb-1.5 block text-sm font-medium text-ph-ink", children: "Colour" }),
8106
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex flex-wrap items-center gap-2", children: [
8107
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
8108
+ "button",
8109
+ {
8110
+ type: "button",
8111
+ "aria-label": "No colour",
8112
+ "aria-pressed": !draft.color,
8113
+ title: "No colour",
8114
+ onClick: () => setDraft(__spreadProps(__spreadValues({}, draft), { color: "" })),
8115
+ className: cn2(
8116
+ "flex h-8 w-8 items-center justify-center rounded-full border border-ph-border bg-ph-surface text-ph-mutedtext ring-offset-2",
8117
+ !draft.color && "ring-2 ring-ph-brand"
8118
+ ),
8119
+ children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_iconoir_react15.Prohibition, { className: "h-4 w-4", "aria-hidden": true })
8120
+ }
8121
+ ),
7735
8122
  [
7736
8123
  "#6366f1",
7737
8124
  "#0ea5e9",
@@ -7740,7 +8127,7 @@ function SuiteClientsProjectsDirectory({
7740
8127
  "#ef4444",
7741
8128
  "#a855f7",
7742
8129
  "#64748b"
7743
- ].map((color) => /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8130
+ ].map((color) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
7744
8131
  "button",
7745
8132
  {
7746
8133
  type: "button",
@@ -7755,33 +8142,70 @@ function SuiteClientsProjectsDirectory({
7755
8142
  },
7756
8143
  color
7757
8144
  )),
7758
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7759
- Input,
8145
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
8146
+ "label",
7760
8147
  {
7761
- hideLabel: true,
7762
- label: "Custom colour",
7763
- type: "color",
7764
- value: draft.color,
7765
- onChange: (event) => setDraft(__spreadProps(__spreadValues({}, draft), { color: event.target.value })),
7766
- className: "h-8 w-8 p-0"
8148
+ className: cn2(
8149
+ "relative inline-flex h-8 w-8 cursor-pointer items-center justify-center rounded-full ring-1 ring-ph-border ring-offset-2",
8150
+ ![
8151
+ "#6366f1",
8152
+ "#0ea5e9",
8153
+ "#10b981",
8154
+ "#f59e0b",
8155
+ "#ef4444",
8156
+ "#a855f7",
8157
+ "#64748b"
8158
+ ].includes(draft.color) && "ring-2 ring-ph-brand"
8159
+ ),
8160
+ style: {
8161
+ background: "conic-gradient(from 0deg, #ef4444, #f59e0b, #eab308, #22c55e, #06b6d4, #3b82f6, #8b5cf6, #ec4899, #ef4444)"
8162
+ },
8163
+ title: "Custom colour",
8164
+ children: [
8165
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "flex h-4 w-4 items-center justify-center rounded-full bg-ph-surface", children: [
8166
+ "#6366f1",
8167
+ "#0ea5e9",
8168
+ "#10b981",
8169
+ "#f59e0b",
8170
+ "#ef4444",
8171
+ "#a855f7",
8172
+ "#64748b"
8173
+ ].includes(draft.color) ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_iconoir_react15.Plus, { className: "h-3 w-3 text-ph-ink", "aria-hidden": true }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
8174
+ "span",
8175
+ {
8176
+ className: "h-2.5 w-2.5 rounded-full",
8177
+ style: { backgroundColor: draft.color }
8178
+ }
8179
+ ) }),
8180
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
8181
+ "input",
8182
+ {
8183
+ type: "color",
8184
+ "aria-label": "Custom colour",
8185
+ value: draft.color,
8186
+ onChange: (event) => setDraft(__spreadProps(__spreadValues({}, draft), { color: event.target.value })),
8187
+ className: "sr-only"
8188
+ }
8189
+ )
8190
+ ]
7767
8191
  }
7768
8192
  )
7769
8193
  ] })
7770
8194
  ] }),
7771
- (editing == null ? void 0 : editing.kind.includes("project")) ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
8195
+ (editing == null ? void 0 : editing.kind.includes("project")) ? /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
7772
8196
  Select,
7773
8197
  {
7774
8198
  label: "Client",
7775
8199
  value: draftClientId != null ? draftClientId : "",
7776
8200
  onChange: (event) => setDraftClientId(event.target.value || null),
7777
8201
  children: [
7778
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("option", { value: "", children: "No client" }),
7779
- clients.map((client) => /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("option", { value: client.id, children: client.name }, client.id))
8202
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("option", { value: "", children: "No client" }),
8203
+ clients.map((client) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("option", { value: client.id, children: client.name }, client.id))
7780
8204
  ]
7781
8205
  }
7782
8206
  ) : null,
7783
- (editing == null ? void 0 : editing.kind.includes("project")) ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("label", { className: "flex items-center gap-2 text-sm text-ph-ink", children: [
7784
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8207
+ (editing == null ? void 0 : editing.kind.includes("project")) ? /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("label", { className: "flex items-center gap-2 text-sm text-ph-ink", children: [
8208
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
7785
8209
  "input",
7786
8210
  {
7787
8211
  type: "checkbox",
@@ -7794,17 +8218,26 @@ function SuiteClientsProjectsDirectory({
7794
8218
  ] })
7795
8219
  }
7796
8220
  ),
7797
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
8221
+ libraryOpen ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
8222
+ Modal,
8223
+ {
8224
+ open: true,
8225
+ onClose: () => setLibraryOpen(false),
8226
+ title: "Icon library",
8227
+ children: renderIconLibrary ? renderIconLibrary({ onPick: pickFromLibrary }) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(SuitePaletteLibrary, { onPick: pickFromLibrary })
8228
+ }
8229
+ ) : null,
8230
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
7798
8231
  Modal,
7799
8232
  {
7800
8233
  open: confirming !== null,
7801
8234
  onClose: () => setConfirming(null),
7802
8235
  title: "Confirm deletion",
7803
- footer: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "flex justify-end gap-2", children: [
7804
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Button, { variant: "tertiary", onClick: () => setConfirming(null), children: "Cancel" }),
7805
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Button, { variant: "primary", onClick: () => void confirmRemove(), children: "Delete" })
8236
+ footer: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "flex justify-end gap-2", children: [
8237
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Button, { variant: "tertiary", onClick: () => setConfirming(null), children: "Cancel" }),
8238
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Button, { variant: "primary", onClick: () => void confirmRemove(), children: "Delete" })
7806
8239
  ] }),
7807
- children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("p", { className: "text-sm text-ph-ink", children: [
8240
+ children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("p", { className: "text-sm text-ph-ink", children: [
7808
8241
  "Delete ",
7809
8242
  confirming == null ? void 0 : confirming.item.name,
7810
8243
  "? This cannot be undone."
@@ -7850,6 +8283,7 @@ function SuiteClientsProjectsDirectory({
7850
8283
  SuiteBreadcrumbs,
7851
8284
  SuiteClientsProjectsDirectory,
7852
8285
  SuiteEmptyState,
8286
+ SuiteEntityIcon,
7853
8287
  SuiteIcon,
7854
8288
  SuiteIntegrationPicker,
7855
8289
  SuiteIntegrationRules,
@@ -7859,6 +8293,7 @@ function SuiteClientsProjectsDirectory({
7859
8293
  SuiteNotificationBell,
7860
8294
  SuitePage,
7861
8295
  SuitePageHeader,
8296
+ SuitePaletteLibrary,
7862
8297
  SuiteSectionHeader,
7863
8298
  SuiteSettingsLayout,
7864
8299
  SuiteSettingsMobileNav,
@@ -7891,6 +8326,9 @@ function SuiteClientsProjectsDirectory({
7891
8326
  cn,
7892
8327
  consumePendingAskAiPrompt,
7893
8328
  consumeSuiteAskAiOpenFromLocation,
8329
+ fetchPaletteCollection,
8330
+ fetchPaletteLibrary,
8331
+ findPaletteIcons,
7894
8332
  getTodayGreeting,
7895
8333
  m,
7896
8334
  openSuiteAskAi,