@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.mjs CHANGED
@@ -465,13 +465,13 @@ function SuiteAppStrip({
465
465
  ),
466
466
  "aria-label": "ShellStack suite apps",
467
467
  children: SUITE_APPS.map((app) => {
468
- var _a;
468
+ var _a2;
469
469
  return /* @__PURE__ */ jsxs4(
470
470
  "div",
471
471
  {
472
472
  className: "flex items-center gap-2 rounded-full border border-ph-border bg-ph-surface px-2.5 py-1.5 shadow-sm",
473
473
  children: [
474
- (_a = icons == null ? void 0 : icons[app]) != null ? _a : /* @__PURE__ */ jsx4(SuiteAppIcon, { app, size: "sm" }),
474
+ (_a2 = icons == null ? void 0 : icons[app]) != null ? _a2 : /* @__PURE__ */ jsx4(SuiteAppIcon, { app, size: "sm" }),
475
475
  /* @__PURE__ */ jsx4("span", { className: "text-xs font-medium text-ph-subtle", children: APP_META[app].name })
476
476
  ]
477
477
  },
@@ -590,13 +590,13 @@ function TodayTopBar({
590
590
  ] });
591
591
  }
592
592
  function getTodayGreeting(user, stats) {
593
- var _a, _b, _c, _d, _e;
593
+ var _a2, _b, _c, _d, _e;
594
594
  const hour = (/* @__PURE__ */ new Date()).getHours();
595
595
  let period = "morning";
596
596
  if (hour >= 12 && hour < 17) period = "afternoon";
597
597
  else if (hour >= 17 && hour < 21) period = "evening";
598
598
  else if (hour >= 21 || hour < 5) period = "night";
599
- 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;
599
+ 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;
600
600
  let greeting = `Good ${period}`;
601
601
  if (name) greeting += `, ${name}`;
602
602
  const taskCount = (_c = stats == null ? void 0 : stats.taskCount) != null ? _c : 0;
@@ -1095,8 +1095,8 @@ var SOURCE_APP_SLUG = {
1095
1095
  shellstack: "shellstack"
1096
1096
  };
1097
1097
  function suiteAppSlugForNotificationSource(sourceApp) {
1098
- var _a;
1099
- return (_a = SOURCE_APP_SLUG[(sourceApp || "").toLowerCase()]) != null ? _a : null;
1098
+ var _a2;
1099
+ return (_a2 = SOURCE_APP_SLUG[(sourceApp || "").toLowerCase()]) != null ? _a2 : null;
1100
1100
  }
1101
1101
  function resolveSuiteNotificationHref(href, sourceApp) {
1102
1102
  const value = (href || "").trim();
@@ -1184,14 +1184,14 @@ function SuiteNotificationBell({
1184
1184
  useEffect(() => {
1185
1185
  if (cacheKey) {
1186
1186
  queueMicrotask(() => {
1187
- var _a;
1187
+ var _a2;
1188
1188
  try {
1189
1189
  const raw = sessionStorage.getItem(cacheKey);
1190
1190
  if (raw) {
1191
1191
  const cached = JSON.parse(raw);
1192
1192
  if (Array.isArray(cached.notifications)) {
1193
1193
  setItems(cached.notifications);
1194
- setUnread((_a = cached.unread_count) != null ? _a : 0);
1194
+ setUnread((_a2 = cached.unread_count) != null ? _a2 : 0);
1195
1195
  }
1196
1196
  }
1197
1197
  } catch (e) {
@@ -1262,9 +1262,9 @@ function SuiteNotificationBell({
1262
1262
  const markAll = useCallback(async () => {
1263
1263
  setItems(
1264
1264
  (prev) => prev.map((i) => {
1265
- var _a;
1265
+ var _a2;
1266
1266
  return __spreadProps(__spreadValues({}, i), {
1267
- read_at: (_a = i.read_at) != null ? _a : (/* @__PURE__ */ new Date()).toISOString()
1267
+ read_at: (_a2 = i.read_at) != null ? _a2 : (/* @__PURE__ */ new Date()).toISOString()
1268
1268
  });
1269
1269
  })
1270
1270
  );
@@ -2047,7 +2047,7 @@ function SuiteBottomNav({
2047
2047
  children: [
2048
2048
  activeIndex >= 0 ? /* @__PURE__ */ jsx14("span", { "aria-hidden": true, className: "suite-bottom-nav__indicator" }) : null,
2049
2049
  items.map((item) => {
2050
- var _a;
2050
+ var _a2;
2051
2051
  const Icon = item.icon;
2052
2052
  const active = Boolean(item.active);
2053
2053
  return /* @__PURE__ */ jsxs12(
@@ -2055,7 +2055,7 @@ function SuiteBottomNav({
2055
2055
  {
2056
2056
  href: item.href,
2057
2057
  id: item.id,
2058
- "data-test": (_a = item.dataTest) != null ? _a : `suite-nav-${item.label.toLowerCase().replace(/\s+/g, "-")}`,
2058
+ "data-test": (_a2 = item.dataTest) != null ? _a2 : `suite-nav-${item.label.toLowerCase().replace(/\s+/g, "-")}`,
2059
2059
  "aria-current": active ? "page" : void 0,
2060
2060
  className: cn2(
2061
2061
  "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",
@@ -2154,7 +2154,7 @@ import {
2154
2154
 
2155
2155
  // src/suite/lib/cookies.ts
2156
2156
  function suiteCookieDomainAttr() {
2157
- var _a;
2157
+ var _a2;
2158
2158
  const host = window.location.hostname;
2159
2159
  if (host === "localhost" || /^\d{1,3}(?:\.\d{1,3}){3}$/.test(host)) {
2160
2160
  return "";
@@ -2173,7 +2173,7 @@ function suiteCookieDomainAttr() {
2173
2173
  "portal"
2174
2174
  ]);
2175
2175
  const parts = host.split(".");
2176
- if (parts.length >= 3 && known.has((_a = parts[0]) != null ? _a : "")) {
2176
+ if (parts.length >= 3 && known.has((_a2 = parts[0]) != null ? _a2 : "")) {
2177
2177
  return `; Domain=.${parts.slice(1).join(".")}`;
2178
2178
  }
2179
2179
  if (parts.length >= 2) return `; Domain=.${parts.slice(1).join(".")}`;
@@ -2441,8 +2441,8 @@ function consumeSuiteAskAiOpenFromLocation() {
2441
2441
  }
2442
2442
  var pendingAskAiPrompt = null;
2443
2443
  function openSuiteAskAi(detail) {
2444
- var _a;
2445
- pendingAskAiPrompt = ((_a = detail == null ? void 0 : detail.prompt) == null ? void 0 : _a.trim()) || null;
2444
+ var _a2;
2445
+ pendingAskAiPrompt = ((_a2 = detail == null ? void 0 : detail.prompt) == null ? void 0 : _a2.trim()) || null;
2446
2446
  if (typeof window === "undefined") return;
2447
2447
  window.dispatchEvent(
2448
2448
  new CustomEvent(SUITE_OPEN_ASK_AI_EVENT, {
@@ -2514,9 +2514,9 @@ function SuiteAiPanel({
2514
2514
  const waiting = loading || isWaitingForReply;
2515
2515
  useEffect7(() => {
2516
2516
  function onOpen(event) {
2517
- var _a;
2517
+ var _a2;
2518
2518
  const detail = event.detail;
2519
- const queued = ((_a = detail == null ? void 0 : detail.prompt) == null ? void 0 : _a.trim()) || consumePendingAskAiPrompt();
2519
+ const queued = ((_a2 = detail == null ? void 0 : detail.prompt) == null ? void 0 : _a2.trim()) || consumePendingAskAiPrompt();
2520
2520
  setOpen(true);
2521
2521
  if (queued) {
2522
2522
  pendingPromptRef.current = queued;
@@ -2539,12 +2539,12 @@ function SuiteAiPanel({
2539
2539
  setAtBottom(distance < 64);
2540
2540
  }, []);
2541
2541
  const hydrate = useCallback3(async () => {
2542
- var _a, _b, _c;
2542
+ var _a2, _b, _c;
2543
2543
  setHydrating(true);
2544
2544
  setError("");
2545
2545
  try {
2546
2546
  const data = await fetchChat();
2547
- setMessages((_a = data.messages) != null ? _a : []);
2547
+ setMessages((_a2 = data.messages) != null ? _a2 : []);
2548
2548
  if (!data.configured) {
2549
2549
  setError("ShellStack AI is not configured for this workspace yet.");
2550
2550
  } else {
@@ -2562,9 +2562,9 @@ function SuiteAiPanel({
2562
2562
  }
2563
2563
  }, [fetchChat]);
2564
2564
  useEffect7(() => {
2565
- var _a;
2565
+ var _a2;
2566
2566
  if (!open) return;
2567
- const queued = (_a = pendingPromptRef.current) != null ? _a : consumePendingAskAiPrompt();
2567
+ const queued = (_a2 = pendingPromptRef.current) != null ? _a2 : consumePendingAskAiPrompt();
2568
2568
  pendingPromptRef.current = queued;
2569
2569
  void hydrate().then(() => {
2570
2570
  const pending = pendingPromptRef.current;
@@ -2576,8 +2576,8 @@ function SuiteAiPanel({
2576
2576
  if (open && atBottom) scrollToBottom();
2577
2577
  }, [messages, waiting, open, atBottom, scrollToBottom]);
2578
2578
  useEffect7(() => {
2579
- var _a;
2580
- if (open && !hydrating) (_a = textareaRef.current) == null ? void 0 : _a.focus();
2579
+ var _a2;
2580
+ if (open && !hydrating) (_a2 = textareaRef.current) == null ? void 0 : _a2.focus();
2581
2581
  }, [open, hydrating]);
2582
2582
  useEffect7(() => {
2583
2583
  if (!open) return;
@@ -2591,7 +2591,7 @@ function SuiteAiPanel({
2591
2591
  el.style.height = `${Math.min(el.scrollHeight, 176)}px`;
2592
2592
  }, [prompt, open]);
2593
2593
  async function ask(text) {
2594
- var _a;
2594
+ var _a2;
2595
2595
  const trimmed = text.trim();
2596
2596
  if (!trimmed || waiting) return;
2597
2597
  const controller = new AbortController();
@@ -2607,20 +2607,20 @@ function SuiteAiPanel({
2607
2607
  signal: controller.signal
2608
2608
  });
2609
2609
  if (controller.signal.aborted) return;
2610
- const nextMessages = (_a = result.messages) != null ? _a : [];
2610
+ const nextMessages = (_a2 = result.messages) != null ? _a2 : [];
2611
2611
  setMessages(nextMessages);
2612
2612
  notifySuiteMutated(
2613
2613
  nextMessages.flatMap((message) => {
2614
- var _a2;
2615
- return (_a2 = message.actions) != null ? _a2 : [];
2614
+ var _a3;
2615
+ return (_a3 = message.actions) != null ? _a3 : [];
2616
2616
  })
2617
2617
  );
2618
2618
  } catch (err) {
2619
2619
  if (controller.signal.aborted) return;
2620
2620
  setMessages(
2621
2621
  (prev) => {
2622
- var _a2, _b;
2623
- 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;
2622
+ var _a3, _b;
2623
+ 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;
2624
2624
  }
2625
2625
  );
2626
2626
  setPrompt(trimmed);
@@ -2633,8 +2633,8 @@ function SuiteAiPanel({
2633
2633
  }
2634
2634
  }
2635
2635
  function stop() {
2636
- var _a;
2637
- (_a = abortRef.current) == null ? void 0 : _a.abort();
2636
+ var _a2;
2637
+ (_a2 = abortRef.current) == null ? void 0 : _a2.abort();
2638
2638
  abortRef.current = null;
2639
2639
  setLoading(false);
2640
2640
  if (!cancelMessage) return;
@@ -2644,14 +2644,14 @@ function SuiteAiPanel({
2644
2644
  });
2645
2645
  }
2646
2646
  function retry() {
2647
- var _a;
2648
- const lastUser = (_a = [...messages].reverse().find((message) => message.role === "user")) == null ? void 0 : _a.content;
2647
+ var _a2;
2648
+ const lastUser = (_a2 = [...messages].reverse().find((message) => message.role === "user")) == null ? void 0 : _a2.content;
2649
2649
  setError("");
2650
2650
  if (lastUser) void ask(lastUser);
2651
2651
  else void hydrate();
2652
2652
  }
2653
2653
  async function saveEdit(index) {
2654
- var _a;
2654
+ var _a2;
2655
2655
  const trimmed = editDraft.trim();
2656
2656
  if (!trimmed || waiting) return;
2657
2657
  setEditingIndex(null);
@@ -2669,12 +2669,12 @@ function SuiteAiPanel({
2669
2669
  signal: controller.signal
2670
2670
  }) : await sendMessage({ prompt: trimmed, signal: controller.signal });
2671
2671
  if (controller.signal.aborted) return;
2672
- const nextMessages = (_a = result.messages) != null ? _a : [];
2672
+ const nextMessages = (_a2 = result.messages) != null ? _a2 : [];
2673
2673
  setMessages(nextMessages);
2674
2674
  notifySuiteMutated(
2675
2675
  nextMessages.flatMap((message) => {
2676
- var _a2;
2677
- return (_a2 = message.actions) != null ? _a2 : [];
2676
+ var _a3;
2677
+ return (_a3 = message.actions) != null ? _a3 : [];
2678
2678
  })
2679
2679
  );
2680
2680
  } catch (err) {
@@ -2712,18 +2712,18 @@ function SuiteAiPanel({
2712
2712
  }
2713
2713
  }
2714
2714
  async function handleResolve(actionId, decision) {
2715
- var _a;
2715
+ var _a2;
2716
2716
  if (!resolveAction || resolvingId) return;
2717
2717
  setResolvingId(actionId);
2718
2718
  setError("");
2719
2719
  try {
2720
2720
  const result = await resolveAction(actionId, decision);
2721
- const nextMessages = (_a = result.messages) != null ? _a : [];
2721
+ const nextMessages = (_a2 = result.messages) != null ? _a2 : [];
2722
2722
  setMessages(nextMessages);
2723
2723
  notifySuiteMutated(
2724
2724
  nextMessages.flatMap((message) => {
2725
- var _a2;
2726
- return (_a2 = message.actions) != null ? _a2 : [];
2725
+ var _a3;
2726
+ return (_a3 = message.actions) != null ? _a3 : [];
2727
2727
  })
2728
2728
  );
2729
2729
  } catch (err) {
@@ -2735,12 +2735,12 @@ function SuiteAiPanel({
2735
2735
  }
2736
2736
  }
2737
2737
  function onConversationClick(event) {
2738
- var _a;
2738
+ var _a2;
2739
2739
  if (event.defaultPrevented) return;
2740
2740
  if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
2741
2741
  return;
2742
2742
  }
2743
- const anchor = (_a = event.target) == null ? void 0 : _a.closest("a");
2743
+ const anchor = (_a2 = event.target) == null ? void 0 : _a2.closest("a");
2744
2744
  if (!anchor || !suiteAppBases) return;
2745
2745
  const href = anchor.href;
2746
2746
  if (!href) return;
@@ -2828,7 +2828,7 @@ function SuiteAiPanel({
2828
2828
  )) }) : null
2829
2829
  ] }) : null,
2830
2830
  messages.map((message, index) => {
2831
- var _a;
2831
+ var _a2;
2832
2832
  const isUser = message.role === "user";
2833
2833
  if (isUser) {
2834
2834
  if (editingIndex === index) {
@@ -2961,7 +2961,7 @@ function SuiteAiPanel({
2961
2961
  )
2962
2962
  }
2963
2963
  ) }),
2964
- ((_a = message.actions) != null ? _a : []).map((action) => /* @__PURE__ */ jsxs14(
2964
+ ((_a2 = message.actions) != null ? _a2 : []).map((action) => /* @__PURE__ */ jsxs14(
2965
2965
  "div",
2966
2966
  {
2967
2967
  "data-test": "ask-ai-action",
@@ -3133,9 +3133,9 @@ function SuiteWorkspaceSwitcher({
3133
3133
  triggerDataTest,
3134
3134
  footer
3135
3135
  }) {
3136
- var _a;
3136
+ var _a2;
3137
3137
  const [open, setOpen] = useState9(false);
3138
- 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 }] : [];
3138
+ 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 }] : [];
3139
3139
  return /* @__PURE__ */ jsx18(
3140
3140
  DropdownMenu2,
3141
3141
  {
@@ -3841,7 +3841,7 @@ function SuiteSidebar({
3841
3841
  /* @__PURE__ */ jsx23("div", { className: "min-h-0 flex-1", children: askAi })
3842
3842
  ] }) : /* @__PURE__ */ jsxs19(Fragment7, { children: [
3843
3843
  /* @__PURE__ */ jsx23("nav", { "aria-label": "Pages", className: "shrink-0 space-y-1", children: /* @__PURE__ */ jsx23("div", { className: "space-y-1", children: navItems.map((item) => {
3844
- var _a;
3844
+ var _a2;
3845
3845
  const Icon = item.icon;
3846
3846
  const active = Boolean(item.active);
3847
3847
  const link = /* @__PURE__ */ jsxs19(
@@ -3849,7 +3849,7 @@ function SuiteSidebar({
3849
3849
  {
3850
3850
  href: item.href,
3851
3851
  id: item.id,
3852
- "data-test": (_a = item.dataTest) != null ? _a : "nav-link",
3852
+ "data-test": (_a2 = item.dataTest) != null ? _a2 : "nav-link",
3853
3853
  "aria-current": active ? "page" : void 0,
3854
3854
  onClick: item.onClick,
3855
3855
  className: cn2(
@@ -4067,15 +4067,15 @@ var AUTH_SCHEME_LABELS = {
4067
4067
  OAUTH2: "OAuth 2.0"
4068
4068
  };
4069
4069
  function authSchemeLabel(scheme) {
4070
- var _a;
4070
+ var _a2;
4071
4071
  const normalised = scheme.trim().toUpperCase();
4072
- return (_a = AUTH_SCHEME_LABELS[normalised]) != null ? _a : normalised.replace(/[-_]/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase());
4072
+ return (_a2 = AUTH_SCHEME_LABELS[normalised]) != null ? _a2 : normalised.replace(/[-_]/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase());
4073
4073
  }
4074
4074
  function authSchemesFor(item) {
4075
- var _a;
4075
+ var _a2;
4076
4076
  return Array.from(
4077
4077
  new Set(
4078
- ((_a = item.authSchemes) != null ? _a : []).map((scheme) => scheme.trim().toUpperCase()).filter(Boolean)
4078
+ ((_a2 = item.authSchemes) != null ? _a2 : []).map((scheme) => scheme.trim().toUpperCase()).filter(Boolean)
4079
4079
  )
4080
4080
  );
4081
4081
  }
@@ -4098,10 +4098,10 @@ var CATEGORY_APP_AFFINITY = {
4098
4098
  };
4099
4099
  var DEFAULT_APP_AFFINITY = ["tides", "kraken"];
4100
4100
  function suiteAppsForIntegration(categories) {
4101
- var _a;
4101
+ var _a2;
4102
4102
  const apps = /* @__PURE__ */ new Set();
4103
4103
  for (const category of categories != null ? categories : []) {
4104
- for (const app of (_a = CATEGORY_APP_AFFINITY[category.trim().toLowerCase()]) != null ? _a : []) {
4104
+ for (const app of (_a2 = CATEGORY_APP_AFFINITY[category.trim().toLowerCase()]) != null ? _a2 : []) {
4105
4105
  apps.add(app);
4106
4106
  }
4107
4107
  }
@@ -4158,8 +4158,8 @@ function SuiteIntegrationPicker({
4158
4158
  const itemCategories = useMemo2(
4159
4159
  () => Array.from(
4160
4160
  new Set(items.flatMap((item) => {
4161
- var _a;
4162
- return (_a = item.categories) != null ? _a : [];
4161
+ var _a2;
4162
+ return (_a2 = item.categories) != null ? _a2 : [];
4163
4163
  }))
4164
4164
  ).sort(),
4165
4165
  [items]
@@ -4169,8 +4169,8 @@ function SuiteIntegrationPicker({
4169
4169
  const activeCategory = controlledCategory != null ? controlledCategory : category;
4170
4170
  const categoryLabel = (value) => value.replace(/[-_]/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase());
4171
4171
  const filtered = onSearchChange || onCategoryChange ? items : items.filter((item) => {
4172
- var _a;
4173
- return item.label.toLowerCase().includes(activeSearch.trim().toLowerCase()) && (activeCategory === "all" || ((_a = item.categories) != null ? _a : []).includes(activeCategory));
4172
+ var _a2;
4173
+ return item.label.toLowerCase().includes(activeSearch.trim().toLowerCase()) && (activeCategory === "all" || ((_a2 = item.categories) != null ? _a2 : []).includes(activeCategory));
4174
4174
  });
4175
4175
  const visibleCategories = categories.filter(
4176
4176
  (value) => categoryLabel(value).toLowerCase().includes(categoryQuery.trim().toLowerCase())
@@ -4195,7 +4195,7 @@ function SuiteIntegrationPicker({
4195
4195
  closeCategoryMenu(true);
4196
4196
  }
4197
4197
  function moveCategoryFocus(event, value) {
4198
- var _a;
4198
+ var _a2;
4199
4199
  const index = categoryValues.indexOf(value);
4200
4200
  let nextIndex = null;
4201
4201
  if (event.key === "ArrowDown") nextIndex = (index + 1) % categoryValues.length;
@@ -4205,16 +4205,16 @@ function SuiteIntegrationPicker({
4205
4205
  else if (event.key === "End") nextIndex = categoryValues.length - 1;
4206
4206
  if (nextIndex === null) return;
4207
4207
  event.preventDefault();
4208
- (_a = categoryOptionRefs.current[categoryValues[nextIndex]]) == null ? void 0 : _a.focus();
4208
+ (_a2 = categoryOptionRefs.current[categoryValues[nextIndex]]) == null ? void 0 : _a2.focus();
4209
4209
  }
4210
4210
  function handleCategoryTriggerKeyDown(event) {
4211
- var _a;
4211
+ var _a2;
4212
4212
  if (event.key === "ArrowDown") {
4213
4213
  event.preventDefault();
4214
4214
  openCategoryMenu(activeCategory === "all" ? "all" : activeCategory);
4215
4215
  } else if (event.key === "ArrowUp") {
4216
4216
  event.preventDefault();
4217
- openCategoryMenu((_a = categoryValues.at(-1)) != null ? _a : "all");
4217
+ openCategoryMenu((_a2 = categoryValues.at(-1)) != null ? _a2 : "all");
4218
4218
  } else if (event.key === "Enter" || event.key === " ") {
4219
4219
  event.preventDefault();
4220
4220
  openCategoryMenu("search");
@@ -4232,7 +4232,7 @@ function SuiteIntegrationPicker({
4232
4232
  resetAuthForm();
4233
4233
  }
4234
4234
  async function prepareConnection(item, scheme) {
4235
- var _a;
4235
+ var _a2;
4236
4236
  setMethodItem(null);
4237
4237
  setAuthError(null);
4238
4238
  setConnectionError(null);
@@ -4254,7 +4254,7 @@ function SuiteIntegrationPicker({
4254
4254
  try {
4255
4255
  const details = await onFetchAuthFields(item, scheme);
4256
4256
  if (requestId !== authRequestRef.current) return;
4257
- const resolvedScheme = (_a = details.auth_scheme) != null ? _a : scheme;
4257
+ const resolvedScheme = (_a2 = details.auth_scheme) != null ? _a2 : scheme;
4258
4258
  if (details.managed) {
4259
4259
  setAuthItem(null);
4260
4260
  await onConnect(item, { auth_scheme: resolvedScheme });
@@ -4339,8 +4339,8 @@ function SuiteIntegrationPicker({
4339
4339
  useEffect9(() => {
4340
4340
  if (!categoryMenuOpen) return;
4341
4341
  const handlePointerDown = (event) => {
4342
- var _a;
4343
- if (!((_a = categoryMenuRef.current) == null ? void 0 : _a.contains(event.target))) {
4342
+ var _a2;
4343
+ if (!((_a2 = categoryMenuRef.current) == null ? void 0 : _a2.contains(event.target))) {
4344
4344
  closeCategoryMenu();
4345
4345
  }
4346
4346
  };
@@ -4355,11 +4355,11 @@ function SuiteIntegrationPicker({
4355
4355
  };
4356
4356
  }, [categoryMenuOpen]);
4357
4357
  useEffect9(() => {
4358
- var _a, _b, _c;
4358
+ var _a2, _b, _c;
4359
4359
  const target = pendingCategoryFocus.current;
4360
4360
  if (!target) return;
4361
4361
  pendingCategoryFocus.current = null;
4362
- if (target === "trigger") (_a = categoryTriggerRef.current) == null ? void 0 : _a.focus();
4362
+ if (target === "trigger") (_a2 = categoryTriggerRef.current) == null ? void 0 : _a2.focus();
4363
4363
  else if (target === "search") (_b = categorySearchRef.current) == null ? void 0 : _b.focus();
4364
4364
  else (_c = categoryOptionRefs.current[target]) == null ? void 0 : _c.focus();
4365
4365
  }, [activeCategory, categoryMenuOpen, categoryQuery, visibleCategories]);
@@ -4472,10 +4472,10 @@ function SuiteIntegrationPicker({
4472
4472
  placeholder: "Search categories...",
4473
4473
  "aria-label": "Search categories",
4474
4474
  onKeyDown: (event) => {
4475
- var _a;
4475
+ var _a2;
4476
4476
  if (event.key === "ArrowDown") {
4477
4477
  event.preventDefault();
4478
- (_a = categoryOptionRefs.current[categoryValues[0]]) == null ? void 0 : _a.focus();
4478
+ (_a2 = categoryOptionRefs.current[categoryValues[0]]) == null ? void 0 : _a2.focus();
4479
4479
  } else if (event.key === "Escape") {
4480
4480
  event.preventDefault();
4481
4481
  closeCategoryMenu(true);
@@ -4538,7 +4538,7 @@ function SuiteIntegrationPicker({
4538
4538
  }
4539
4539
  ) : /* @__PURE__ */ jsxs21("div", { className: "grid gap-3 sm:grid-cols-2 lg:grid-cols-3", children: [
4540
4540
  filtered.map((item) => {
4541
- var _a, _b;
4541
+ var _a2, _b;
4542
4542
  const isExpanded = expanded === item.id;
4543
4543
  const longDescription = item.description.length > DESCRIPTION_LIMIT;
4544
4544
  const text = isExpanded || !longDescription ? item.description : `${item.description.slice(0, DESCRIPTION_LIMIT).trimEnd()}...`;
@@ -4555,7 +4555,7 @@ function SuiteIntegrationPicker({
4555
4555
  onClick: () => longDescription && setExpanded(isExpanded ? null : item.id),
4556
4556
  "aria-expanded": isExpanded,
4557
4557
  children: /* @__PURE__ */ jsxs21("span", { className: "flex items-start gap-3", children: [
4558
- /* @__PURE__ */ jsx25("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__ */ jsx25(Plug, { className: "h-5 w-5", "aria-hidden": true }) }),
4558
+ /* @__PURE__ */ jsx25("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__ */ jsx25(Plug, { className: "h-5 w-5", "aria-hidden": true }) }),
4559
4559
  /* @__PURE__ */ jsxs21("span", { className: "min-w-0", children: [
4560
4560
  /* @__PURE__ */ jsx25("span", { className: "block truncate font-medium text-ph-ink", children: item.label }),
4561
4561
  /* @__PURE__ */ jsx25("span", { className: "mt-1 block text-xs text-ph-subtle", children: text }),
@@ -4763,12 +4763,12 @@ function SuiteIntegrationPicker({
4763
4763
  }
4764
4764
  ) : null,
4765
4765
  authItem.fields.map((field) => {
4766
- var _a, _b;
4766
+ var _a2, _b;
4767
4767
  return /* @__PURE__ */ jsx25(
4768
4768
  Input,
4769
4769
  {
4770
4770
  label: field.label,
4771
- type: (_a = field.type) != null ? _a : "password",
4771
+ type: (_a2 = field.type) != null ? _a2 : "password",
4772
4772
  required: true,
4773
4773
  value: (_b = authValues[field.name]) != null ? _b : "",
4774
4774
  onChange: (event) => setAuthValues((current) => __spreadProps(__spreadValues({}, current), {
@@ -4811,8 +4811,8 @@ var ACTION_LABELS = {
4811
4811
  create_suite_notification: "Send a suite notification"
4812
4812
  };
4813
4813
  function actionLabel(actionType) {
4814
- var _a;
4815
- return (_a = ACTION_LABELS[actionType]) != null ? _a : actionType;
4814
+ var _a2;
4815
+ return (_a2 = ACTION_LABELS[actionType]) != null ? _a2 : actionType;
4816
4816
  }
4817
4817
  function formatDateTime(value) {
4818
4818
  if (!value) return "\u2014";
@@ -5201,225 +5201,583 @@ function SuiteIntegrationRules({
5201
5201
 
5202
5202
  // src/suite/components/suite-clients-projects-directory.tsx
5203
5203
  import {
5204
- useEffect as useEffect10,
5205
- useMemo as useMemo3,
5206
- useRef as useRef5,
5207
- useState as useState13
5204
+ useEffect as useEffect11,
5205
+ useMemo as useMemo4,
5206
+ useRef as useRef6,
5207
+ useState as useState14
5208
5208
  } from "react";
5209
5209
  import {
5210
5210
  ArrowLeft,
5211
- MediaImagePlus as ImagePlus,
5212
5211
  MoreHoriz as MoreHorizontal,
5213
5212
  Plus as Plus2,
5214
- Search as Search2,
5213
+ Prohibition,
5214
+ Search as Search3,
5215
5215
  Trash
5216
5216
  } from "iconoir-react";
5217
- import { Fragment as Fragment9, jsx as jsx27, jsxs as jsxs23 } from "react/jsx-runtime";
5218
- var DEFAULT_ICON = "castle-emblem";
5219
- var DEFAULT_COLOR = "#6366f1";
5220
- var DIRECTORY_ICON_OPTIONS = [
5221
- ["arena", "Arena"],
5222
- ["bridge", "Bridge"],
5223
- ["capitol", "Capitol"],
5224
- ["castle-emblem", "Castle"],
5225
- ["castle-flag", "Castle flag"],
5226
- ["lighthouse", "Lighthouse"],
5227
- ["tower", "Tower"],
5228
- ["wooden-sign", "Sign"],
5229
- ["anvil", "Anvil"],
5230
- ["book", "Book"],
5231
- ["chessboard", "Chessboard"],
5232
- ["cog", "Settings"],
5233
- ["hammer", "Build"],
5234
- ["light-bulb", "Idea"],
5235
- ["microphone", "Communication"],
5236
- ["quill-ink", "Writing"],
5237
- ["scroll-unfurled", "Notes"],
5238
- ["hourglass", "Planning"],
5239
- ["wrench", "Tools"],
5240
- ["archer", "Archer"],
5241
- ["archery-target", "Target"],
5242
- ["axe", "Axe"],
5243
- ["campfire", "Campfire"],
5244
- ["compass", "Compass"],
5245
- ["crossed-swords", "Battle"],
5246
- ["knight-helmet", "Knight"],
5247
- ["mountains", "Mountains"],
5248
- ["shield", "Shield"],
5249
- ["ship-emblem", "Voyage"],
5250
- ["sword", "Sword"],
5251
- ["trophy", "Trophy"],
5252
- ["apple", "Apple"],
5253
- ["butterfly", "Butterfly"],
5254
- ["clover", "Clover"],
5255
- ["dragon", "Dragon"],
5256
- ["fire", "Fire"],
5257
- ["flower", "Flower"],
5258
- ["flowers", "Flowers"],
5259
- ["grass", "Grass"],
5260
- ["leaf", "Leaf"],
5261
- ["pine-tree", "Pine tree"],
5262
- ["sun", "Sun"],
5263
- ["water-drop", "Water"],
5264
- ["aura", "Aura"],
5265
- ["crystal-ball", "Crystal ball"],
5266
- ["diamond", "Diamond"],
5267
- ["explosion", "Explosion"],
5268
- ["fire-symbol", "Fire symbol"],
5269
- ["gem", "Gem"],
5270
- ["lightning-trio", "Lightning"],
5271
- ["potion", "Potion"],
5272
- ["rune-stone", "Rune stone"],
5273
- ["skull", "Skull"],
5274
- ["tentacle", "Tentacle"],
5275
- ["wolf-head", "Wolf"],
5276
- ["anchor", "Anchor"],
5277
- ["beer", "Beer"],
5278
- ["carrot", "Carrot"],
5279
- ["cat", "Cat"],
5280
- ["crown", "Crown"],
5281
- ["gold-bar", "Gold bar"],
5282
- ["helmet", "Helmet"],
5283
- ["key", "Key"],
5284
- ["three-keys", "Keys"]
5285
- ];
5286
- function isDirectoryIcon(value) {
5287
- return DIRECTORY_ICON_OPTIONS.some(([name]) => name === value);
5217
+
5218
+ // src/suite/lib/palette-api.ts
5219
+ var _a;
5220
+ var PALETTE_URL = ((_a = process.env.NEXT_PUBLIC_PALETTE_URL) != null ? _a : "http://localhost:8010").replace(/\/$/, "");
5221
+ function toQuery(params) {
5222
+ const query = new URLSearchParams();
5223
+ for (const [key, value] of Object.entries(params != null ? params : {})) {
5224
+ if (value !== void 0 && value !== null && value !== "") {
5225
+ query.set(key, String(value));
5226
+ }
5227
+ }
5228
+ return query.toString();
5288
5229
  }
5289
- function DirectoryIconPicker({
5290
- value,
5291
- preview,
5292
- onFileChange,
5293
- onClear,
5294
- onChange
5230
+ async function paletteGet(path, params) {
5231
+ const suffix = toQuery(params);
5232
+ const response = await fetch(
5233
+ `${PALETTE_URL}${path}${suffix ? `?${suffix}` : ""}`,
5234
+ { headers: { Accept: "application/json" } }
5235
+ );
5236
+ if (!response.ok) {
5237
+ throw new Error(`Palette request failed (${response.status}).`);
5238
+ }
5239
+ return await response.json();
5240
+ }
5241
+ var cache = /* @__PURE__ */ new Map();
5242
+ async function paletteGetCached(path, params, ttlMs) {
5243
+ const key = `${path}?${toQuery(params)}`;
5244
+ const now = Date.now();
5245
+ const hit = cache.get(key);
5246
+ if (hit && hit.expires > now) return hit.value;
5247
+ const value = await paletteGet(path, params);
5248
+ cache.set(key, { expires: now + ttlMs, value });
5249
+ return value;
5250
+ }
5251
+ function fetchPaletteLibrary(options) {
5252
+ return paletteGetCached("/library", options, 5 * 6e4);
5253
+ }
5254
+ function fetchPaletteCollection(slug, options) {
5255
+ return paletteGetCached(
5256
+ `/collections/${slug}`,
5257
+ options,
5258
+ 2 * 6e4
5259
+ );
5260
+ }
5261
+ function findPaletteIcons(options) {
5262
+ return paletteGet("/find", options);
5263
+ }
5264
+ function paletteIconSrc(imageUrl, color) {
5265
+ if (!imageUrl || !color) return imageUrl;
5266
+ if (!imageUrl.includes("/svgrepo/")) return imageUrl;
5267
+ return `${PALETTE_URL}/render?src=${encodeURIComponent(imageUrl)}&color=${encodeURIComponent(color)}`;
5268
+ }
5269
+
5270
+ // src/suite/components/suite-entity-icon.tsx
5271
+ import { jsx as jsx27 } from "react/jsx-runtime";
5272
+ function SuiteEntityIcon({
5273
+ imageUrl,
5274
+ label,
5275
+ color,
5276
+ className,
5277
+ roundedClass = "rounded-md",
5278
+ style,
5279
+ tinted = false
5295
5280
  }) {
5296
- const iconRefs = useRef5({});
5297
- function moveSelection(event, index) {
5298
- var _a;
5299
- let nextIndex = null;
5300
- if (event.key === "ArrowRight" || event.key === "ArrowDown") {
5301
- nextIndex = (index + 1) % DIRECTORY_ICON_OPTIONS.length;
5302
- } else if (event.key === "ArrowLeft" || event.key === "ArrowUp") {
5303
- nextIndex = (index - 1 + DIRECTORY_ICON_OPTIONS.length) % DIRECTORY_ICON_OPTIONS.length;
5304
- } else if (event.key === "Home") {
5305
- nextIndex = 0;
5306
- } else if (event.key === "End") {
5307
- nextIndex = DIRECTORY_ICON_OPTIONS.length - 1;
5308
- }
5309
- if (nextIndex === null) return;
5310
- event.preventDefault();
5311
- const [nextIcon] = DIRECTORY_ICON_OPTIONS[nextIndex];
5312
- onChange(nextIcon);
5313
- (_a = iconRefs.current[nextIcon]) == null ? void 0 : _a.focus();
5281
+ const hasColor = typeof color === "string" && /^#[0-9a-fA-F]{3,8}$/.test(color);
5282
+ const tint = hasColor ? color : null;
5283
+ const neutralBackground = "var(--ph-muted, rgba(127,127,127,0.08))";
5284
+ if (imageUrl) {
5285
+ const src = tinted && tint ? paletteIconSrc(imageUrl, tint) : imageUrl;
5286
+ return /* @__PURE__ */ jsx27(
5287
+ "span",
5288
+ {
5289
+ className: cn(
5290
+ "inline-flex shrink-0 items-center justify-center overflow-hidden leading-none",
5291
+ roundedClass,
5292
+ className
5293
+ ),
5294
+ style: __spreadValues({
5295
+ backgroundColor: tint ? `${tint}18` : neutralBackground
5296
+ }, style),
5297
+ children: /* @__PURE__ */ jsx27("img", { src: src != null ? src : void 0, alt: "", className: "h-full w-full object-cover" })
5298
+ }
5299
+ );
5314
5300
  }
5315
- return /* @__PURE__ */ jsxs23("div", { className: "space-y-2", children: [
5316
- /* @__PURE__ */ jsx27("span", { className: "mb-1.5 block text-sm font-medium text-ph-ink", children: "Icon" }),
5317
- /* @__PURE__ */ jsx27(
5318
- "div",
5301
+ const initial = label == null ? void 0 : label.trim().charAt(0).toUpperCase();
5302
+ return /* @__PURE__ */ jsx27(
5303
+ "span",
5304
+ {
5305
+ className: cn(
5306
+ "inline-flex shrink-0 items-center justify-center font-semibold leading-none",
5307
+ roundedClass,
5308
+ className
5309
+ ),
5310
+ style: __spreadValues({
5311
+ color: tint != null ? tint : "var(--ph-mutedtext)",
5312
+ backgroundColor: tint ? `${tint}18` : neutralBackground
5313
+ }, style),
5314
+ "aria-hidden": "true",
5315
+ children: initial ? /* @__PURE__ */ jsx27("span", { className: "text-[0.7em]", children: initial }) : /* @__PURE__ */ jsx27("span", { className: "block h-1.5 w-1.5 rounded-full bg-current opacity-40" })
5316
+ }
5317
+ );
5318
+ }
5319
+
5320
+ // src/suite/components/suite-palette-library.tsx
5321
+ import {
5322
+ useCallback as useCallback6,
5323
+ useEffect as useEffect10,
5324
+ useMemo as useMemo3,
5325
+ useRef as useRef5,
5326
+ useState as useState13
5327
+ } from "react";
5328
+ import { Filter as Filter2, FilterList, NavArrowDown as NavArrowDown3, Search as Search2 } from "iconoir-react";
5329
+ import { Fragment as Fragment9, jsx as jsx28, jsxs as jsxs23 } from "react/jsx-runtime";
5330
+ var PAGE_SIZE = 60;
5331
+ var DISCOVER_LIMIT = 120;
5332
+ var ICON_TYPES = [
5333
+ { value: "all", label: "All types" },
5334
+ { value: "line", label: "Line" },
5335
+ { value: "solid", label: "Solid" },
5336
+ { value: "duotone", label: "Duotone" },
5337
+ { value: "color", label: "Colour" },
5338
+ { value: "mixed", label: "Mixed" }
5339
+ ];
5340
+ function FilterSelect({
5341
+ icon: Icon,
5342
+ label,
5343
+ value,
5344
+ onChange,
5345
+ children
5346
+ }) {
5347
+ return /* @__PURE__ */ jsxs23("div", { className: "relative", children: [
5348
+ /* @__PURE__ */ jsx28(
5349
+ Icon,
5319
5350
  {
5320
- role: "radiogroup",
5321
- "aria-label": "Icon",
5322
- className: "grid grid-cols-6 gap-1.5 rounded-lg border border-ph-border p-1.5 sm:grid-cols-8",
5323
- children: DIRECTORY_ICON_OPTIONS.map(([name, label], index) => {
5324
- const selected = value === name;
5325
- return /* @__PURE__ */ jsx27(
5326
- "button",
5351
+ className: "pointer-events-none absolute left-2.5 top-1/2 h-4 w-4 -translate-y-1/2 text-ph-mutedtext",
5352
+ "aria-hidden": true
5353
+ }
5354
+ ),
5355
+ /* @__PURE__ */ jsx28(
5356
+ "select",
5357
+ {
5358
+ "aria-label": label,
5359
+ value,
5360
+ onChange: (event) => onChange(event.target.value),
5361
+ 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",
5362
+ children
5363
+ }
5364
+ ),
5365
+ /* @__PURE__ */ jsx28(
5366
+ NavArrowDown3,
5367
+ {
5368
+ className: "pointer-events-none absolute right-2 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-ph-mutedtext",
5369
+ "aria-hidden": true
5370
+ }
5371
+ )
5372
+ ] });
5373
+ }
5374
+ function SuitePaletteLibrary({
5375
+ onPick
5376
+ }) {
5377
+ var _a2, _b;
5378
+ const [collections, setCollections] = useState13([]);
5379
+ const [typeFilter, setTypeFilter] = useState13("all");
5380
+ const [collectionFilter, setCollectionFilter] = useState13("");
5381
+ const [libraryOpen, setLibraryOpen] = useState13(false);
5382
+ const [libraryQuery, setLibraryQuery] = useState13("");
5383
+ const libraryRef = useRef5(null);
5384
+ const [icons, setIcons] = useState13([]);
5385
+ const [total, setTotal] = useState13(0);
5386
+ const [page, setPage] = useState13(1);
5387
+ const [query, setQuery] = useState13("");
5388
+ const [loading, setLoading] = useState13(true);
5389
+ const [loadingMore, setLoadingMore] = useState13(false);
5390
+ const [error, setError] = useState13(null);
5391
+ const requestId = useRef5(0);
5392
+ const libraryOptions = useMemo3(() => {
5393
+ const list = collections.filter(
5394
+ (item) => typeFilter === "all" || item.style === typeFilter
5395
+ );
5396
+ return [...list].sort(
5397
+ (a, b) => Number(b.featured) - Number(a.featured) || a.name.localeCompare(b.name)
5398
+ );
5399
+ }, [collections, typeFilter]);
5400
+ const discoverIcons = useMemo3(() => {
5401
+ const seen = /* @__PURE__ */ new Set();
5402
+ const out = [];
5403
+ for (const collection of libraryOptions) {
5404
+ for (const url of collection.preview) {
5405
+ if (seen.has(url)) continue;
5406
+ seen.add(url);
5407
+ out.push({ id: url, name: collection.name, tags: [], url });
5408
+ if (out.length >= DISCOVER_LIMIT) return out;
5409
+ }
5410
+ }
5411
+ return out;
5412
+ }, [libraryOptions]);
5413
+ const loadCollection = useCallback6(async (slug, nextPage = 1) => {
5414
+ const id = ++requestId.current;
5415
+ if (nextPage === 1) {
5416
+ setLoading(true);
5417
+ setIcons([]);
5418
+ } else {
5419
+ setLoadingMore(true);
5420
+ }
5421
+ setError(null);
5422
+ try {
5423
+ const detail = await fetchPaletteCollection(slug, {
5424
+ page: nextPage,
5425
+ size: PAGE_SIZE
5426
+ });
5427
+ if (id !== requestId.current) return;
5428
+ setTotal(detail.count);
5429
+ setPage(nextPage);
5430
+ setIcons(
5431
+ (current) => nextPage === 1 ? detail.icons : [...current, ...detail.icons]
5432
+ );
5433
+ } catch (err) {
5434
+ if (id === requestId.current) {
5435
+ setError(err instanceof Error ? err.message : "Could not load icons.");
5436
+ }
5437
+ } finally {
5438
+ if (id === requestId.current) {
5439
+ setLoading(false);
5440
+ setLoadingMore(false);
5441
+ }
5442
+ }
5443
+ }, []);
5444
+ useEffect10(() => {
5445
+ let cancelled = false;
5446
+ fetchPaletteLibrary().then((library) => {
5447
+ if (cancelled) return;
5448
+ setCollections(library.collections);
5449
+ }).catch((err) => {
5450
+ if (cancelled) return;
5451
+ setError(err instanceof Error ? err.message : "Could not load the library.");
5452
+ setLoading(false);
5453
+ });
5454
+ return () => {
5455
+ cancelled = true;
5456
+ };
5457
+ }, []);
5458
+ useEffect10(() => {
5459
+ if (!collections.length) return;
5460
+ if (collectionFilter && !libraryOptions.some((c) => c.slug === collectionFilter)) {
5461
+ setCollectionFilter("");
5462
+ }
5463
+ }, [libraryOptions, collectionFilter, collections.length]);
5464
+ useEffect10(() => {
5465
+ if (query.trim()) return;
5466
+ if (collectionFilter) {
5467
+ void loadCollection(collectionFilter, 1);
5468
+ return;
5469
+ }
5470
+ requestId.current += 1;
5471
+ setLoading(false);
5472
+ setPage(1);
5473
+ setIcons(discoverIcons);
5474
+ setTotal(discoverIcons.length);
5475
+ }, [collectionFilter, query, loadCollection, discoverIcons]);
5476
+ useEffect10(() => {
5477
+ const term = query.trim();
5478
+ if (!term) return;
5479
+ const id = ++requestId.current;
5480
+ setLoading(true);
5481
+ setError(null);
5482
+ const handle = setTimeout(async () => {
5483
+ try {
5484
+ const results = await findPaletteIcons({
5485
+ q: term,
5486
+ collection: collectionFilter || void 0,
5487
+ style: typeFilter === "all" ? void 0 : typeFilter,
5488
+ limit: 120
5489
+ });
5490
+ if (id !== requestId.current) return;
5491
+ setTotal(results.total);
5492
+ setPage(1);
5493
+ setIcons(
5494
+ results.results.map((hit) => ({
5495
+ id: `${hit.collection}/${hit.id}`,
5496
+ name: hit.name,
5497
+ tags: hit.tags,
5498
+ url: hit.url
5499
+ }))
5500
+ );
5501
+ } catch (err) {
5502
+ if (id === requestId.current) {
5503
+ setError(err instanceof Error ? err.message : "Search failed.");
5504
+ }
5505
+ } finally {
5506
+ if (id === requestId.current) setLoading(false);
5507
+ }
5508
+ }, 250);
5509
+ return () => clearTimeout(handle);
5510
+ }, [query, collectionFilter, typeFilter]);
5511
+ const searching = Boolean(query.trim());
5512
+ const activeLibrary = (_a2 = collections.find((c) => c.slug === collectionFilter)) != null ? _a2 : null;
5513
+ const filteredLibraries = useMemo3(() => {
5514
+ const term = libraryQuery.trim().toLowerCase();
5515
+ if (!term) return libraryOptions;
5516
+ return libraryOptions.filter((c) => c.name.toLowerCase().includes(term));
5517
+ }, [libraryOptions, libraryQuery]);
5518
+ useEffect10(() => {
5519
+ if (!libraryOpen) return;
5520
+ const onPointerDown = (event) => {
5521
+ var _a3;
5522
+ if (!((_a3 = libraryRef.current) == null ? void 0 : _a3.contains(event.target))) setLibraryOpen(false);
5523
+ };
5524
+ document.addEventListener("pointerdown", onPointerDown);
5525
+ return () => document.removeEventListener("pointerdown", onPointerDown);
5526
+ }, [libraryOpen]);
5527
+ return /* @__PURE__ */ jsxs23("div", { className: "space-y-3", "data-test": "palette-icon-library", children: [
5528
+ /* @__PURE__ */ jsxs23("div", { ref: libraryRef, className: "space-y-2", children: [
5529
+ /* @__PURE__ */ jsxs23("div", { className: "flex flex-col gap-2 sm:flex-row", children: [
5530
+ /* @__PURE__ */ jsxs23("div", { className: "relative flex-1", children: [
5531
+ /* @__PURE__ */ jsx28(
5532
+ Search2,
5327
5533
  {
5328
- type: "button",
5329
- role: "radio",
5330
- "aria-label": label,
5331
- "aria-checked": selected,
5332
- tabIndex: selected ? 0 : -1,
5333
- title: label,
5334
- onClick: () => onChange(name),
5335
- onKeyDown: (event) => moveSelection(event, index),
5336
- ref: (element) => {
5337
- iconRefs.current[name] = element;
5338
- },
5339
- className: cn(
5340
- "flex h-9 items-center justify-center rounded-md text-ph-mutedtext hover:bg-ph-muted hover:text-ph-ink",
5341
- selected && "bg-ph-muted text-ph-ink ring-2 ring-ph-brand ring-inset"
5342
- ),
5343
- children: /* @__PURE__ */ jsx27(
5344
- "i",
5534
+ className: "pointer-events-none absolute left-2.5 top-1/2 h-4 w-4 -translate-y-1/2 text-ph-mutedtext",
5535
+ "aria-hidden": true
5536
+ }
5537
+ ),
5538
+ /* @__PURE__ */ jsx28(
5539
+ "input",
5540
+ {
5541
+ type: "search",
5542
+ value: query,
5543
+ onChange: (event) => setQuery(event.target.value),
5544
+ placeholder: "Search icons \u2014 handshake, rocket, briefcase\u2026",
5545
+ "aria-label": "Search icons",
5546
+ 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"
5547
+ }
5548
+ )
5549
+ ] }),
5550
+ /* @__PURE__ */ jsxs23(
5551
+ "button",
5552
+ {
5553
+ type: "button",
5554
+ "aria-haspopup": "listbox",
5555
+ "aria-expanded": libraryOpen,
5556
+ onClick: () => setLibraryOpen((open) => !open),
5557
+ 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",
5558
+ children: [
5559
+ /* @__PURE__ */ jsx28(FilterList, { className: "h-4 w-4 shrink-0 text-ph-mutedtext", "aria-hidden": true }),
5560
+ /* @__PURE__ */ jsx28("span", { className: "max-w-[10rem] truncate", children: (_b = activeLibrary == null ? void 0 : activeLibrary.name) != null ? _b : "All libraries" }),
5561
+ /* @__PURE__ */ jsx28(
5562
+ NavArrowDown3,
5345
5563
  {
5346
- className: cn("ra", `ra-${name}`, "text-base leading-none"),
5564
+ className: cn(
5565
+ "h-3.5 w-3.5 shrink-0 text-ph-mutedtext transition-transform",
5566
+ libraryOpen && "rotate-180"
5567
+ ),
5347
5568
  "aria-hidden": true
5348
5569
  }
5349
5570
  )
5350
- },
5351
- name
5352
- );
5353
- })
5354
- }
5355
- ),
5356
- /* @__PURE__ */ jsxs23("div", { className: "rounded-lg border border-ph-border bg-ph-muted p-2", children: [
5357
- /* @__PURE__ */ jsxs23("div", { className: "flex items-center gap-2 text-sm font-medium text-ph-ink", children: [
5358
- /* @__PURE__ */ jsx27(ImagePlus, { className: "h-4 w-4", "aria-hidden": true }),
5359
- " Custom image"
5360
- ] }),
5361
- /* @__PURE__ */ jsx27("p", { className: "mt-1 text-xs text-ph-mutedtext", children: "PNG, JPG, GIF, WebP, or SVG \u2014 max 512 KB." }),
5362
- /* @__PURE__ */ jsx27(
5363
- FileUpload,
5364
- {
5365
- accept: "image/png,image/jpeg,image/gif,image/webp,image/svg+xml,.svg",
5366
- onChange: (event) => {
5367
- var _a, _b;
5368
- return onFileChange((_b = (_a = event.target.files) == null ? void 0 : _a[0]) != null ? _b : null);
5571
+ ]
5369
5572
  }
5370
- }
5371
- ),
5372
- preview ? /* @__PURE__ */ jsxs23("div", { className: "mt-2 flex items-center gap-2", children: [
5373
- /* @__PURE__ */ jsx27(
5374
- "img",
5573
+ ),
5574
+ /* @__PURE__ */ jsx28(
5575
+ FilterSelect,
5375
5576
  {
5376
- src: preview,
5377
- alt: "",
5378
- className: "h-8 w-8 rounded object-cover"
5577
+ icon: Filter2,
5578
+ label: "Filter by icon type",
5579
+ value: typeFilter,
5580
+ onChange: setTypeFilter,
5581
+ children: ICON_TYPES.map((type) => /* @__PURE__ */ jsx28("option", { value: type.value, children: type.label }, type.value))
5379
5582
  }
5380
- ),
5583
+ )
5584
+ ] }),
5585
+ libraryOpen ? /* @__PURE__ */ jsxs23("div", { className: "rounded-lg border border-ph-border bg-ph-surface p-2", children: [
5586
+ /* @__PURE__ */ jsxs23("div", { className: "relative mb-2", children: [
5587
+ /* @__PURE__ */ jsx28(
5588
+ Search2,
5589
+ {
5590
+ className: "pointer-events-none absolute left-2.5 top-1/2 h-4 w-4 -translate-y-1/2 text-ph-mutedtext",
5591
+ "aria-hidden": true
5592
+ }
5593
+ ),
5594
+ /* @__PURE__ */ jsx28(
5595
+ "input",
5596
+ {
5597
+ type: "search",
5598
+ autoFocus: true,
5599
+ value: libraryQuery,
5600
+ onChange: (event) => setLibraryQuery(event.target.value),
5601
+ placeholder: "Search libraries\u2026",
5602
+ "aria-label": "Search libraries",
5603
+ 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"
5604
+ }
5605
+ )
5606
+ ] }),
5381
5607
  /* @__PURE__ */ jsxs23(
5382
- "button",
5608
+ "ul",
5383
5609
  {
5384
- type: "button",
5385
- className: "text-xs text-ph-mutedtext hover:text-ph-ink",
5386
- onClick: onClear,
5610
+ role: "listbox",
5611
+ "aria-label": "Libraries",
5612
+ className: "max-h-56 overflow-y-auto",
5387
5613
  children: [
5388
- /* @__PURE__ */ jsx27(Trash, { className: "mr-1 inline h-3.5 w-3.5", "aria-hidden": true }),
5389
- " Remove custom image"
5614
+ /* @__PURE__ */ jsx28("li", { children: /* @__PURE__ */ jsx28(
5615
+ "button",
5616
+ {
5617
+ type: "button",
5618
+ role: "option",
5619
+ "aria-selected": !collectionFilter,
5620
+ onClick: () => {
5621
+ setCollectionFilter("");
5622
+ setLibraryOpen(false);
5623
+ },
5624
+ className: cn(
5625
+ "flex w-full items-center rounded-md px-2 py-1.5 text-left text-sm",
5626
+ !collectionFilter ? "bg-ph-muted text-ph-ink" : "text-ph-ink hover:bg-ph-muted"
5627
+ ),
5628
+ children: "All libraries"
5629
+ }
5630
+ ) }),
5631
+ filteredLibraries.map((collection) => /* @__PURE__ */ jsx28("li", { children: /* @__PURE__ */ jsxs23(
5632
+ "button",
5633
+ {
5634
+ type: "button",
5635
+ role: "option",
5636
+ "aria-selected": collectionFilter === collection.slug,
5637
+ onClick: () => {
5638
+ setCollectionFilter(collection.slug);
5639
+ setLibraryOpen(false);
5640
+ },
5641
+ className: cn(
5642
+ "flex w-full items-center justify-between gap-2 rounded-md px-2 py-1.5 text-left text-sm",
5643
+ collectionFilter === collection.slug ? "bg-ph-muted text-ph-ink" : "text-ph-ink hover:bg-ph-muted"
5644
+ ),
5645
+ children: [
5646
+ /* @__PURE__ */ jsx28("span", { className: "truncate", children: collection.name }),
5647
+ /* @__PURE__ */ jsx28("span", { className: "shrink-0 text-xs text-ph-mutedtext", children: collection.count })
5648
+ ]
5649
+ }
5650
+ ) }, collection.slug)),
5651
+ filteredLibraries.length === 0 ? /* @__PURE__ */ jsx28("li", { className: "px-2 py-4 text-center text-sm text-ph-mutedtext", children: "No libraries match." }) : null
5390
5652
  ]
5391
5653
  }
5392
5654
  )
5393
5655
  ] }) : null
5656
+ ] }),
5657
+ error ? /* @__PURE__ */ jsx28("p", { className: "text-sm text-ph-danger", children: error }) : loading ? /* @__PURE__ */ jsx28("p", { className: "py-8 text-center text-sm text-ph-mutedtext", children: "Loading icons\u2026" }) : icons.length === 0 ? /* @__PURE__ */ jsx28("p", { className: "py-8 text-center text-sm text-ph-mutedtext", children: "No icons matched. Try another word or filter." }) : /* @__PURE__ */ jsxs23(Fragment9, { children: [
5658
+ /* @__PURE__ */ jsx28("div", { className: "max-h-[320px] overflow-y-auto rounded-lg border border-ph-border p-2", children: /* @__PURE__ */ jsx28("div", { className: "grid grid-cols-6 gap-1.5 sm:grid-cols-8", children: icons.map((icon) => /* @__PURE__ */ jsx28(
5659
+ "button",
5660
+ {
5661
+ type: "button",
5662
+ onClick: () => onPick({ url: icon.url, name: icon.name }),
5663
+ title: icon.name,
5664
+ "aria-label": `Use ${icon.name}`,
5665
+ className: "flex h-10 items-center justify-center rounded-md border border-transparent p-1.5 hover:border-ph-brand hover:bg-ph-muted",
5666
+ children: /* @__PURE__ */ jsx28(
5667
+ "img",
5668
+ {
5669
+ src: icon.url,
5670
+ alt: "",
5671
+ loading: "lazy",
5672
+ decoding: "async",
5673
+ className: "h-6 w-6"
5674
+ }
5675
+ )
5676
+ },
5677
+ icon.id
5678
+ )) }) }),
5679
+ /* @__PURE__ */ jsxs23("div", { className: "flex items-center justify-between text-xs text-ph-mutedtext", children: [
5680
+ /* @__PURE__ */ jsxs23("span", { children: [
5681
+ icons.length,
5682
+ " of ",
5683
+ total,
5684
+ searching ? " matching" : activeLibrary ? ` in ${activeLibrary.name}` : " across all libraries"
5685
+ ] }),
5686
+ !searching && activeLibrary && icons.length < total ? /* @__PURE__ */ jsx28(
5687
+ "button",
5688
+ {
5689
+ type: "button",
5690
+ disabled: loadingMore,
5691
+ onClick: () => void loadCollection(activeLibrary.slug, page + 1),
5692
+ className: cn(
5693
+ "font-medium text-ph-brand hover:underline",
5694
+ loadingMore && "opacity-50"
5695
+ ),
5696
+ children: loadingMore ? "Loading\u2026" : "Load more"
5697
+ }
5698
+ ) : null
5699
+ ] })
5394
5700
  ] })
5395
5701
  ] });
5396
5702
  }
5397
- function DirectoryIcon({
5398
- item
5703
+
5704
+ // src/suite/components/suite-clients-projects-directory.tsx
5705
+ import { Fragment as Fragment10, jsx as jsx29, jsxs as jsxs24 } from "react/jsx-runtime";
5706
+ var DEFAULT_ICON = "";
5707
+ var DEFAULT_COLOR = "";
5708
+ function DirectoryIconPicker({
5709
+ preview,
5710
+ label,
5711
+ color,
5712
+ onFileChange,
5713
+ onClear,
5714
+ onBrowse
5399
5715
  }) {
5400
- const icon = item.icon && isDirectoryIcon(item.icon) ? item.icon : DEFAULT_ICON;
5401
- return /* @__PURE__ */ jsx27(
5402
- "span",
5403
- {
5404
- className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg text-white",
5405
- style: { backgroundColor: item.color || "var(--ph-brand)" },
5406
- children: item.icon_image ? (
5407
- // eslint-disable-next-line @next/next/no-img-element
5408
- /* @__PURE__ */ jsx27(
5409
- "img",
5716
+ return /* @__PURE__ */ jsxs24("div", { className: "space-y-2", children: [
5717
+ /* @__PURE__ */ jsx29("span", { className: "mb-1.5 block text-sm font-medium text-ph-ink", children: "Icon" }),
5718
+ /* @__PURE__ */ jsxs24("div", { className: "rounded-lg border border-ph-border bg-ph-muted p-3", children: [
5719
+ /* @__PURE__ */ jsxs24("div", { className: "flex items-center gap-3", children: [
5720
+ /* @__PURE__ */ jsx29(
5721
+ SuiteEntityIcon,
5410
5722
  {
5411
- src: item.icon_image,
5412
- alt: "",
5413
- className: "h-full w-full rounded-lg object-cover"
5723
+ imageUrl: preview,
5724
+ label,
5725
+ color,
5726
+ tinted: true,
5727
+ className: "h-9 w-9 text-base"
5414
5728
  }
5415
- )
5416
- ) : /* @__PURE__ */ jsx27(
5417
- "i",
5729
+ ),
5730
+ /* @__PURE__ */ jsxs24("div", { className: "min-w-0 flex-1", children: [
5731
+ /* @__PURE__ */ jsx29("p", { className: "text-sm font-medium text-ph-ink", children: preview ? "Custom image" : "No icon yet" }),
5732
+ /* @__PURE__ */ jsx29("p", { className: "text-xs text-ph-mutedtext", children: preview ? "Shown on cards and lists." : "Browse the library or upload your own." })
5733
+ ] }),
5734
+ onBrowse ? /* @__PURE__ */ jsx29(
5735
+ "button",
5736
+ {
5737
+ type: "button",
5738
+ onClick: onBrowse,
5739
+ 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",
5740
+ children: "Browse library"
5741
+ }
5742
+ ) : null
5743
+ ] }),
5744
+ /* @__PURE__ */ jsx29("div", { className: "mt-3", children: /* @__PURE__ */ jsx29(
5745
+ FileUpload,
5418
5746
  {
5419
- className: cn("ra", `ra-${icon}`, "text-base leading-none"),
5420
- "aria-hidden": true
5747
+ accept: "image/png,image/jpeg,image/gif,image/webp,image/svg+xml,.svg",
5748
+ onChange: (event) => {
5749
+ var _a2, _b;
5750
+ return onFileChange((_b = (_a2 = event.target.files) == null ? void 0 : _a2[0]) != null ? _b : null);
5751
+ }
5421
5752
  }
5422
- )
5753
+ ) }),
5754
+ preview ? /* @__PURE__ */ jsxs24(
5755
+ "button",
5756
+ {
5757
+ type: "button",
5758
+ 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",
5759
+ onClick: onClear,
5760
+ children: [
5761
+ /* @__PURE__ */ jsx29(Trash, { className: "h-3.5 w-3.5", "aria-hidden": true }),
5762
+ " Remove image"
5763
+ ]
5764
+ }
5765
+ ) : null
5766
+ ] })
5767
+ ] });
5768
+ }
5769
+ function DirectoryIcon({
5770
+ item
5771
+ }) {
5772
+ return /* @__PURE__ */ jsx29(
5773
+ SuiteEntityIcon,
5774
+ {
5775
+ imageUrl: item.icon_image,
5776
+ label: item.name,
5777
+ color: item.color,
5778
+ tinted: true,
5779
+ className: "h-8 w-8 text-sm",
5780
+ roundedClass: "rounded-lg"
5423
5781
  }
5424
5782
  );
5425
5783
  }
@@ -5435,51 +5793,53 @@ function SuiteClientsProjectsDirectory({
5435
5793
  onCreateProject,
5436
5794
  onUpdateProject,
5437
5795
  onDeleteProject,
5796
+ renderIconLibrary,
5438
5797
  dataTest = "suite-clients-projects-directory"
5439
5798
  }) {
5440
- var _a;
5441
- const [query, setQuery] = useState13("");
5442
- const [selectedClientId, setSelectedClientId] = useState13(null);
5443
- const [mobileDetail, setMobileDetail] = useState13(false);
5444
- const [editing, setEditing] = useState13(null);
5445
- const [draft, setDraft] = useState13({
5799
+ var _a2;
5800
+ const [query, setQuery] = useState14("");
5801
+ const [selectedClientId, setSelectedClientId] = useState14(null);
5802
+ const [mobileDetail, setMobileDetail] = useState14(false);
5803
+ const [editing, setEditing] = useState14(null);
5804
+ const [draft, setDraft] = useState14({
5446
5805
  name: "",
5447
5806
  icon: DEFAULT_ICON,
5448
5807
  color: DEFAULT_COLOR
5449
5808
  });
5450
- const [draftClientId, setDraftClientId] = useState13(null);
5451
- const [preview, setPreview] = useState13(null);
5452
- const [draftArchived, setDraftArchived] = useState13(false);
5453
- const [confirming, setConfirming] = useState13(null);
5454
- const [saving, setSaving] = useState13(false);
5455
- const [mutationError, setMutationError] = useState13(null);
5456
- const clientButtonRefs = useRef5({});
5457
- const backToClientsRef = useRef5(null);
5458
- const mobileFocusTarget = useRef5(null);
5459
- useEffect10(() => {
5460
- var _a2, _b;
5809
+ const [draftClientId, setDraftClientId] = useState14(null);
5810
+ const [preview, setPreview] = useState14(null);
5811
+ const [libraryOpen, setLibraryOpen] = useState14(false);
5812
+ const [draftArchived, setDraftArchived] = useState14(false);
5813
+ const [confirming, setConfirming] = useState14(null);
5814
+ const [saving, setSaving] = useState14(false);
5815
+ const [mutationError, setMutationError] = useState14(null);
5816
+ const clientButtonRefs = useRef6({});
5817
+ const backToClientsRef = useRef6(null);
5818
+ const mobileFocusTarget = useRef6(null);
5819
+ useEffect11(() => {
5820
+ var _a3, _b;
5461
5821
  if (selectedClientId && clients.some((client) => client.id === selectedClientId))
5462
5822
  return;
5463
- setSelectedClientId((_b = (_a2 = clients[0]) == null ? void 0 : _a2.id) != null ? _b : null);
5823
+ setSelectedClientId((_b = (_a3 = clients[0]) == null ? void 0 : _a3.id) != null ? _b : null);
5464
5824
  }, [clients, selectedClientId]);
5465
- useEffect10(() => {
5466
- var _a2, _b;
5825
+ useEffect11(() => {
5826
+ var _a3, _b;
5467
5827
  const target = mobileFocusTarget.current;
5468
5828
  if (!target) return;
5469
5829
  mobileFocusTarget.current = null;
5470
- if (target === "detail") (_a2 = backToClientsRef.current) == null ? void 0 : _a2.focus();
5830
+ if (target === "detail") (_a3 = backToClientsRef.current) == null ? void 0 : _a3.focus();
5471
5831
  else if (selectedClientId)
5472
5832
  (_b = clientButtonRefs.current[selectedClientId]) == null ? void 0 : _b.focus();
5473
5833
  }, [mobileDetail, selectedClientId]);
5474
- const filteredClients = useMemo3(() => {
5834
+ const filteredClients = useMemo4(() => {
5475
5835
  const value = query.trim().toLowerCase();
5476
5836
  return [...clients].sort((a, b) => a.name.localeCompare(b.name)).filter((client) => !value || client.name.toLowerCase().includes(value));
5477
5837
  }, [clients, query]);
5478
- const selectedClient = (_a = clients.find((client) => client.id === selectedClientId)) != null ? _a : null;
5838
+ const selectedClient = (_a2 = clients.find((client) => client.id === selectedClientId)) != null ? _a2 : null;
5479
5839
  const selectedProjects = projects.filter((project) => project.clientId === selectedClientId).sort((a, b) => a.name.localeCompare(b.name));
5480
5840
  function isMobileDirectoryView() {
5481
- var _a2, _b;
5482
- return (_b = (_a2 = window.matchMedia) == null ? void 0 : _a2.call(window, "(max-width: 1023px)").matches) != null ? _b : false;
5841
+ var _a3, _b;
5842
+ return (_b = (_a3 = window.matchMedia) == null ? void 0 : _a3.call(window, "(max-width: 1023px)").matches) != null ? _b : false;
5483
5843
  }
5484
5844
  function selectClient(client) {
5485
5845
  setSelectedClientId(client.id);
@@ -5487,7 +5847,7 @@ function SuiteClientsProjectsDirectory({
5487
5847
  if (isMobileDirectoryView()) mobileFocusTarget.current = "detail";
5488
5848
  }
5489
5849
  function moveClientSelection(event, index) {
5490
- var _a2;
5850
+ var _a3;
5491
5851
  let nextIndex = null;
5492
5852
  if (event.key === "ArrowDown") {
5493
5853
  nextIndex = (index + 1) % filteredClients.length;
@@ -5502,7 +5862,7 @@ function SuiteClientsProjectsDirectory({
5502
5862
  event.preventDefault();
5503
5863
  const client = filteredClients[nextIndex];
5504
5864
  selectClient(client);
5505
- if (!isMobileDirectoryView()) (_a2 = clientButtonRefs.current[client.id]) == null ? void 0 : _a2.focus();
5865
+ if (!isMobileDirectoryView()) (_a3 = clientButtonRefs.current[client.id]) == null ? void 0 : _a3.focus();
5506
5866
  }
5507
5867
  function openNew(kind) {
5508
5868
  setMutationError(null);
@@ -5511,6 +5871,7 @@ function SuiteClientsProjectsDirectory({
5511
5871
  icon: DEFAULT_ICON,
5512
5872
  color: DEFAULT_COLOR,
5513
5873
  iconImageFile: null,
5874
+ iconImageUrl: null,
5514
5875
  clearIconImage: false
5515
5876
  });
5516
5877
  setPreview(null);
@@ -5519,13 +5880,14 @@ function SuiteClientsProjectsDirectory({
5519
5880
  setEditing({ kind: kind === "client" ? "new-client" : "new-project" });
5520
5881
  }
5521
5882
  function openEdit(item, kind) {
5522
- var _a2;
5883
+ var _a3, _b;
5523
5884
  setMutationError(null);
5524
5885
  setDraft({
5525
5886
  name: item.name,
5526
- icon: item.icon && isDirectoryIcon(item.icon) ? item.icon : DEFAULT_ICON,
5887
+ icon: (_a3 = item.icon) != null ? _a3 : DEFAULT_ICON,
5527
5888
  color: item.color || DEFAULT_COLOR,
5528
5889
  iconImageFile: null,
5890
+ iconImageUrl: null,
5529
5891
  clearIconImage: false
5530
5892
  });
5531
5893
  setPreview(item.icon_image || null);
@@ -5533,7 +5895,7 @@ function SuiteClientsProjectsDirectory({
5533
5895
  kind === "project" && Boolean(item.isArchived)
5534
5896
  );
5535
5897
  setDraftClientId(
5536
- kind === "project" ? (_a2 = item.clientId) != null ? _a2 : null : null
5898
+ kind === "project" ? (_b = item.clientId) != null ? _b : null : null
5537
5899
  );
5538
5900
  setEditing({ kind, item });
5539
5901
  }
@@ -5547,6 +5909,7 @@ function SuiteClientsProjectsDirectory({
5547
5909
  if (preview == null ? void 0 : preview.startsWith("blob:")) URL.revokeObjectURL(preview);
5548
5910
  setDraft((current) => __spreadProps(__spreadValues({}, current), {
5549
5911
  iconImageFile: file,
5912
+ iconImageUrl: null,
5550
5913
  clearIconImage: false
5551
5914
  }));
5552
5915
  setPreview(URL.createObjectURL(file));
@@ -5556,9 +5919,21 @@ function SuiteClientsProjectsDirectory({
5556
5919
  setPreview(null);
5557
5920
  setDraft((current) => __spreadProps(__spreadValues({}, current), {
5558
5921
  iconImageFile: null,
5922
+ iconImageUrl: null,
5559
5923
  clearIconImage: true
5560
5924
  }));
5561
5925
  }
5926
+ function pickFromLibrary(icon) {
5927
+ if (preview == null ? void 0 : preview.startsWith("blob:")) URL.revokeObjectURL(preview);
5928
+ setMutationError(null);
5929
+ setPreview(icon.url);
5930
+ setDraft((current) => __spreadProps(__spreadValues({}, current), {
5931
+ iconImageFile: null,
5932
+ iconImageUrl: icon.url,
5933
+ clearIconImage: false
5934
+ }));
5935
+ setLibraryOpen(false);
5936
+ }
5562
5937
  function closeEditor() {
5563
5938
  if (!saving) setEditing(null);
5564
5939
  }
@@ -5594,14 +5969,14 @@ function SuiteClientsProjectsDirectory({
5594
5969
  setConfirming({ item, kind });
5595
5970
  }
5596
5971
  async function toggleArchive(project) {
5597
- var _a2;
5972
+ var _a3, _b;
5598
5973
  if (!onUpdateProject) return;
5599
5974
  try {
5600
5975
  await onUpdateProject(project, {
5601
5976
  name: project.name,
5602
- icon: project.icon && isDirectoryIcon(project.icon) ? project.icon : DEFAULT_ICON,
5977
+ icon: (_a3 = project.icon) != null ? _a3 : DEFAULT_ICON,
5603
5978
  color: project.color || DEFAULT_COLOR,
5604
- clientId: (_a2 = project.clientId) != null ? _a2 : null,
5979
+ clientId: (_b = project.clientId) != null ? _b : null,
5605
5980
  isArchived: !project.isArchived
5606
5981
  });
5607
5982
  } catch (err) {
@@ -5624,10 +5999,10 @@ function SuiteClientsProjectsDirectory({
5624
5999
  );
5625
6000
  }
5626
6001
  }
5627
- return /* @__PURE__ */ jsxs23("div", { "data-test": dataTest, className: "space-y-3", children: [
5628
- error || mutationError ? /* @__PURE__ */ jsx27(Alert, { status: "danger", live: "assertive", children: error || mutationError }) : null,
5629
- loading ? /* @__PURE__ */ jsx27("p", { className: "text-sm text-ph-mutedtext", children: "Loading directory..." }) : /* @__PURE__ */ jsxs23("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: [
5630
- /* @__PURE__ */ jsxs23(
6002
+ return /* @__PURE__ */ jsxs24("div", { "data-test": dataTest, className: "space-y-3", children: [
6003
+ error || mutationError ? /* @__PURE__ */ jsx29(Alert, { status: "danger", live: "assertive", children: error || mutationError }) : null,
6004
+ loading ? /* @__PURE__ */ jsx29("p", { className: "text-sm text-ph-mutedtext", children: "Loading directory..." }) : /* @__PURE__ */ jsxs24("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: [
6005
+ /* @__PURE__ */ jsxs24(
5631
6006
  "section",
5632
6007
  {
5633
6008
  className: cn(
@@ -5635,16 +6010,16 @@ function SuiteClientsProjectsDirectory({
5635
6010
  mobileDetail ? "hidden lg:block" : "block"
5636
6011
  ),
5637
6012
  children: [
5638
- /* @__PURE__ */ jsxs23("div", { className: "flex h-14 items-center gap-2 border-b border-ph-border px-3", children: [
5639
- /* @__PURE__ */ jsxs23("div", { className: "relative min-w-0 flex-1", children: [
5640
- /* @__PURE__ */ jsx27(
5641
- Search2,
6013
+ /* @__PURE__ */ jsxs24("div", { className: "flex h-14 items-center gap-2 border-b border-ph-border px-3", children: [
6014
+ /* @__PURE__ */ jsxs24("div", { className: "relative min-w-0 flex-1", children: [
6015
+ /* @__PURE__ */ jsx29(
6016
+ Search3,
5642
6017
  {
5643
6018
  className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-ph-mutedtext",
5644
6019
  "aria-hidden": true
5645
6020
  }
5646
6021
  ),
5647
- /* @__PURE__ */ jsx27(
6022
+ /* @__PURE__ */ jsx29(
5648
6023
  Input,
5649
6024
  {
5650
6025
  hideLabel: true,
@@ -5656,18 +6031,18 @@ function SuiteClientsProjectsDirectory({
5656
6031
  }
5657
6032
  )
5658
6033
  ] }),
5659
- canEdit && onCreateClient ? /* @__PURE__ */ jsx27(
6034
+ canEdit && onCreateClient ? /* @__PURE__ */ jsx29(
5660
6035
  Button,
5661
6036
  {
5662
6037
  size: "sm",
5663
6038
  variant: "primary",
5664
- icon: /* @__PURE__ */ jsx27(Plus2, { className: "h-4 w-4" }),
6039
+ icon: /* @__PURE__ */ jsx29(Plus2, { className: "h-4 w-4" }),
5665
6040
  onClick: () => openNew("client"),
5666
6041
  children: "New client"
5667
6042
  }
5668
6043
  ) : null
5669
6044
  ] }),
5670
- /* @__PURE__ */ jsx27(
6045
+ /* @__PURE__ */ jsx29(
5671
6046
  "ul",
5672
6047
  {
5673
6048
  role: "listbox",
@@ -5678,7 +6053,7 @@ function SuiteClientsProjectsDirectory({
5678
6053
  const count = projects.filter(
5679
6054
  (project) => project.clientId === client.id
5680
6055
  ).length;
5681
- return /* @__PURE__ */ jsx27("li", { role: "none", children: /* @__PURE__ */ jsxs23(
6056
+ return /* @__PURE__ */ jsx29("li", { role: "none", children: /* @__PURE__ */ jsxs24(
5682
6057
  "button",
5683
6058
  {
5684
6059
  type: "button",
@@ -5695,10 +6070,10 @@ function SuiteClientsProjectsDirectory({
5695
6070
  selected ? "bg-ph-muted" : "hover:bg-ph-canvas"
5696
6071
  ),
5697
6072
  children: [
5698
- /* @__PURE__ */ jsx27(DirectoryIcon, { item: client }),
5699
- /* @__PURE__ */ jsxs23("span", { className: "min-w-0 flex-1", children: [
5700
- /* @__PURE__ */ jsx27("span", { className: "block truncate text-sm font-medium text-ph-ink", children: client.name }),
5701
- /* @__PURE__ */ jsxs23("span", { className: "text-xs text-ph-mutedtext", children: [
6073
+ /* @__PURE__ */ jsx29(DirectoryIcon, { item: client }),
6074
+ /* @__PURE__ */ jsxs24("span", { className: "min-w-0 flex-1", children: [
6075
+ /* @__PURE__ */ jsx29("span", { className: "block truncate text-sm font-medium text-ph-ink", children: client.name }),
6076
+ /* @__PURE__ */ jsxs24("span", { className: "text-xs text-ph-mutedtext", children: [
5702
6077
  count,
5703
6078
  " project",
5704
6079
  count === 1 ? "" : "s"
@@ -5707,13 +6082,13 @@ function SuiteClientsProjectsDirectory({
5707
6082
  ]
5708
6083
  }
5709
6084
  ) }, client.id);
5710
- }) : /* @__PURE__ */ jsx27("li", { className: "px-3 py-8 text-center text-sm text-ph-mutedtext", children: clients.length ? "No matches." : "Add a client to get started." })
6085
+ }) : /* @__PURE__ */ jsx29("li", { className: "px-3 py-8 text-center text-sm text-ph-mutedtext", children: clients.length ? "No matches." : "Add a client to get started." })
5711
6086
  }
5712
6087
  )
5713
6088
  ]
5714
6089
  }
5715
6090
  ),
5716
- /* @__PURE__ */ jsxs23(
6091
+ /* @__PURE__ */ jsxs24(
5717
6092
  "section",
5718
6093
  {
5719
6094
  className: cn(
@@ -5721,8 +6096,8 @@ function SuiteClientsProjectsDirectory({
5721
6096
  mobileDetail ? "flex" : "hidden lg:flex"
5722
6097
  ),
5723
6098
  children: [
5724
- /* @__PURE__ */ jsx27("div", { className: "flex min-h-14 items-center gap-2 border-b border-ph-border px-3 py-2", children: selectedClient ? /* @__PURE__ */ jsxs23(Fragment9, { children: [
5725
- /* @__PURE__ */ jsx27(
6099
+ /* @__PURE__ */ jsx29("div", { className: "flex min-h-14 items-center gap-2 border-b border-ph-border px-3 py-2", children: selectedClient ? /* @__PURE__ */ jsxs24(Fragment10, { children: [
6100
+ /* @__PURE__ */ jsx29(
5726
6101
  "button",
5727
6102
  {
5728
6103
  type: "button",
@@ -5733,36 +6108,36 @@ function SuiteClientsProjectsDirectory({
5733
6108
  setMobileDetail(false);
5734
6109
  },
5735
6110
  "aria-label": "Back to clients",
5736
- children: /* @__PURE__ */ jsx27(ArrowLeft, { className: "h-4 w-4" })
6111
+ children: /* @__PURE__ */ jsx29(ArrowLeft, { className: "h-4 w-4" })
5737
6112
  }
5738
6113
  ),
5739
- /* @__PURE__ */ jsx27(DirectoryIcon, { item: selectedClient }),
5740
- /* @__PURE__ */ jsxs23("div", { className: "min-w-0 flex-1", children: [
5741
- /* @__PURE__ */ jsx27("h3", { className: "truncate text-sm font-semibold text-ph-ink", children: selectedClient.name }),
5742
- /* @__PURE__ */ jsxs23("p", { className: "text-xs text-ph-mutedtext", children: [
6114
+ /* @__PURE__ */ jsx29(DirectoryIcon, { item: selectedClient }),
6115
+ /* @__PURE__ */ jsxs24("div", { className: "min-w-0 flex-1", children: [
6116
+ /* @__PURE__ */ jsx29("h3", { className: "truncate text-sm font-semibold text-ph-ink", children: selectedClient.name }),
6117
+ /* @__PURE__ */ jsxs24("p", { className: "text-xs text-ph-mutedtext", children: [
5743
6118
  selectedProjects.length,
5744
6119
  " project",
5745
6120
  selectedProjects.length === 1 ? "" : "s"
5746
6121
  ] })
5747
6122
  ] }),
5748
- canEdit && (onUpdateClient || onDeleteClient) ? /* @__PURE__ */ jsx27("div", { onClick: (event) => event.stopPropagation(), children: /* @__PURE__ */ jsx27(
6123
+ canEdit && (onUpdateClient || onDeleteClient) ? /* @__PURE__ */ jsx29("div", { onClick: (event) => event.stopPropagation(), children: /* @__PURE__ */ jsx29(
5749
6124
  DropdownMenu,
5750
6125
  {
5751
6126
  "aria-label": `Actions for ${selectedClient.name}`,
5752
6127
  align: "end",
5753
- trigger: /* @__PURE__ */ jsxs23("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: [
5754
- /* @__PURE__ */ jsx27(MoreHorizontal, { className: "h-4 w-4", "aria-hidden": true }),
5755
- /* @__PURE__ */ jsx27("span", { className: "sr-only", children: "Client actions" })
6128
+ trigger: /* @__PURE__ */ jsxs24("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: [
6129
+ /* @__PURE__ */ jsx29(MoreHorizontal, { className: "h-4 w-4", "aria-hidden": true }),
6130
+ /* @__PURE__ */ jsx29("span", { className: "sr-only", children: "Client actions" })
5756
6131
  ] }),
5757
- children: /* @__PURE__ */ jsxs23("div", { className: "p-1", children: [
5758
- onUpdateClient ? /* @__PURE__ */ jsx27(
6132
+ children: /* @__PURE__ */ jsxs24("div", { className: "p-1", children: [
6133
+ onUpdateClient ? /* @__PURE__ */ jsx29(
5759
6134
  DropdownItem,
5760
6135
  {
5761
6136
  onClick: () => openEdit(selectedClient, "client"),
5762
6137
  children: "Edit client"
5763
6138
  }
5764
6139
  ) : null,
5765
- onDeleteClient ? /* @__PURE__ */ jsx27(
6140
+ onDeleteClient ? /* @__PURE__ */ jsx29(
5766
6141
  DropdownItem,
5767
6142
  {
5768
6143
  className: "text-red-600",
@@ -5773,32 +6148,32 @@ function SuiteClientsProjectsDirectory({
5773
6148
  ] })
5774
6149
  }
5775
6150
  ) }) : null
5776
- ] }) : /* @__PURE__ */ jsx27("p", { className: "text-sm text-ph-mutedtext", children: "Select a client" }) }),
5777
- canEdit && onCreateProject ? /* @__PURE__ */ jsx27("div", { className: "border-b border-ph-border p-3", children: /* @__PURE__ */ jsx27(
6151
+ ] }) : /* @__PURE__ */ jsx29("p", { className: "text-sm text-ph-mutedtext", children: "Select a client" }) }),
6152
+ canEdit && onCreateProject ? /* @__PURE__ */ jsx29("div", { className: "border-b border-ph-border p-3", children: /* @__PURE__ */ jsx29(
5778
6153
  Button,
5779
6154
  {
5780
6155
  variant: "primary",
5781
- icon: /* @__PURE__ */ jsx27(Plus2, { className: "h-4 w-4" }),
6156
+ icon: /* @__PURE__ */ jsx29(Plus2, { className: "h-4 w-4" }),
5782
6157
  onClick: () => openNew("project"),
5783
6158
  children: "Add project"
5784
6159
  }
5785
6160
  ) }) : null,
5786
- /* @__PURE__ */ jsx27("ul", { className: "flex-1 p-2", children: selectedClient && selectedProjects.length ? selectedProjects.map((project) => /* @__PURE__ */ jsx27("li", { children: /* @__PURE__ */ jsxs23(
6161
+ /* @__PURE__ */ jsx29("ul", { className: "flex-1 p-2", children: selectedClient && selectedProjects.length ? selectedProjects.map((project) => /* @__PURE__ */ jsx29("li", { children: /* @__PURE__ */ jsxs24(
5787
6162
  "div",
5788
6163
  {
5789
6164
  className: "flex items-center gap-3 rounded-lg px-2 py-1 hover:bg-ph-canvas",
5790
6165
  onClick: () => openEdit(project, "project"),
5791
6166
  children: [
5792
- /* @__PURE__ */ jsxs23(
6167
+ /* @__PURE__ */ jsxs24(
5793
6168
  "button",
5794
6169
  {
5795
6170
  type: "button",
5796
6171
  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",
5797
6172
  onClick: () => openEdit(project, "project"),
5798
6173
  children: [
5799
- /* @__PURE__ */ jsx27(DirectoryIcon, { item: project }),
5800
- /* @__PURE__ */ jsxs23("span", { className: "min-w-0 flex-1", children: [
5801
- /* @__PURE__ */ jsx27(
6174
+ /* @__PURE__ */ jsx29(DirectoryIcon, { item: project }),
6175
+ /* @__PURE__ */ jsxs24("span", { className: "min-w-0 flex-1", children: [
6176
+ /* @__PURE__ */ jsx29(
5802
6177
  "span",
5803
6178
  {
5804
6179
  className: cn(
@@ -5808,36 +6183,36 @@ function SuiteClientsProjectsDirectory({
5808
6183
  children: project.name
5809
6184
  }
5810
6185
  ),
5811
- /* @__PURE__ */ jsx27("span", { className: "text-xs text-ph-mutedtext", children: project.isArchived ? "Archived" : "Active" })
6186
+ /* @__PURE__ */ jsx29("span", { className: "text-xs text-ph-mutedtext", children: project.isArchived ? "Archived" : "Active" })
5812
6187
  ] })
5813
6188
  ]
5814
6189
  }
5815
6190
  ),
5816
- canEdit && (onUpdateProject || onDeleteProject) ? /* @__PURE__ */ jsx27("div", { onClick: (event) => event.stopPropagation(), children: /* @__PURE__ */ jsx27(
6191
+ canEdit && (onUpdateProject || onDeleteProject) ? /* @__PURE__ */ jsx29("div", { onClick: (event) => event.stopPropagation(), children: /* @__PURE__ */ jsx29(
5817
6192
  DropdownMenu,
5818
6193
  {
5819
6194
  "aria-label": `Actions for ${project.name}`,
5820
6195
  align: "end",
5821
- trigger: /* @__PURE__ */ jsxs23("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: [
5822
- /* @__PURE__ */ jsx27(
6196
+ trigger: /* @__PURE__ */ jsxs24("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: [
6197
+ /* @__PURE__ */ jsx29(
5823
6198
  MoreHorizontal,
5824
6199
  {
5825
6200
  className: "h-4 w-4",
5826
6201
  "aria-hidden": true
5827
6202
  }
5828
6203
  ),
5829
- /* @__PURE__ */ jsx27("span", { className: "sr-only", children: "Project actions" })
6204
+ /* @__PURE__ */ jsx29("span", { className: "sr-only", children: "Project actions" })
5830
6205
  ] }),
5831
- children: /* @__PURE__ */ jsxs23("div", { className: "p-1", children: [
5832
- onUpdateProject ? /* @__PURE__ */ jsxs23(Fragment9, { children: [
5833
- /* @__PURE__ */ jsx27(
6206
+ children: /* @__PURE__ */ jsxs24("div", { className: "p-1", children: [
6207
+ onUpdateProject ? /* @__PURE__ */ jsxs24(Fragment10, { children: [
6208
+ /* @__PURE__ */ jsx29(
5834
6209
  DropdownItem,
5835
6210
  {
5836
6211
  onClick: () => openEdit(project, "project"),
5837
6212
  children: "Edit project"
5838
6213
  }
5839
6214
  ),
5840
- /* @__PURE__ */ jsx27(
6215
+ /* @__PURE__ */ jsx29(
5841
6216
  DropdownItem,
5842
6217
  {
5843
6218
  onClick: () => void toggleArchive(project),
@@ -5845,7 +6220,7 @@ function SuiteClientsProjectsDirectory({
5845
6220
  }
5846
6221
  )
5847
6222
  ] }) : null,
5848
- onDeleteProject ? /* @__PURE__ */ jsx27(
6223
+ onDeleteProject ? /* @__PURE__ */ jsx29(
5849
6224
  DropdownItem,
5850
6225
  {
5851
6226
  className: "text-red-600",
@@ -5858,20 +6233,20 @@ function SuiteClientsProjectsDirectory({
5858
6233
  ) }) : null
5859
6234
  ]
5860
6235
  }
5861
- ) }, project.id)) : /* @__PURE__ */ jsx27("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." }) })
6236
+ ) }, project.id)) : /* @__PURE__ */ jsx29("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." }) })
5862
6237
  ]
5863
6238
  }
5864
6239
  )
5865
6240
  ] }),
5866
- /* @__PURE__ */ jsx27(
6241
+ /* @__PURE__ */ jsx29(
5867
6242
  Modal,
5868
6243
  {
5869
6244
  open: editing !== null,
5870
6245
  onClose: closeEditor,
5871
6246
  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",
5872
- footer: /* @__PURE__ */ jsxs23("div", { className: "flex justify-end gap-2", children: [
5873
- /* @__PURE__ */ jsx27(Button, { variant: "tertiary", onClick: closeEditor, disabled: saving, children: "Cancel" }),
5874
- /* @__PURE__ */ jsx27(
6247
+ footer: /* @__PURE__ */ jsxs24("div", { className: "flex justify-end gap-2", children: [
6248
+ /* @__PURE__ */ jsx29(Button, { variant: "tertiary", onClick: closeEditor, disabled: saving, children: "Cancel" }),
6249
+ /* @__PURE__ */ jsx29(
5875
6250
  Button,
5876
6251
  {
5877
6252
  variant: "primary",
@@ -5881,8 +6256,8 @@ function SuiteClientsProjectsDirectory({
5881
6256
  }
5882
6257
  )
5883
6258
  ] }),
5884
- children: /* @__PURE__ */ jsxs23("div", { className: "space-y-3", children: [
5885
- /* @__PURE__ */ jsx27(
6259
+ children: /* @__PURE__ */ jsxs24("div", { className: "space-y-3", children: [
6260
+ /* @__PURE__ */ jsx29(
5886
6261
  Input,
5887
6262
  {
5888
6263
  label: "Name",
@@ -5891,22 +6266,35 @@ function SuiteClientsProjectsDirectory({
5891
6266
  onChange: (event) => setDraft(__spreadProps(__spreadValues({}, draft), { name: event.target.value }))
5892
6267
  }
5893
6268
  ),
5894
- /* @__PURE__ */ jsx27(
6269
+ /* @__PURE__ */ jsx29(
5895
6270
  DirectoryIconPicker,
5896
6271
  {
5897
- value: isDirectoryIcon(draft.icon) ? draft.icon : DEFAULT_ICON,
5898
6272
  preview,
6273
+ label: draft.name,
6274
+ color: draft.color,
5899
6275
  onFileChange: chooseImage,
5900
6276
  onClear: clearImage,
5901
- onChange: (icon) => {
5902
- if (preview) clearImage();
5903
- setDraft((current) => __spreadProps(__spreadValues({}, current), { icon }));
5904
- }
6277
+ onBrowse: () => setLibraryOpen(true)
5905
6278
  }
5906
6279
  ),
5907
- /* @__PURE__ */ jsxs23("div", { children: [
5908
- /* @__PURE__ */ jsx27("span", { className: "mb-1.5 block text-sm font-medium text-ph-ink", children: "Colour" }),
5909
- /* @__PURE__ */ jsxs23("div", { className: "flex flex-wrap gap-2", children: [
6280
+ /* @__PURE__ */ jsxs24("div", { children: [
6281
+ /* @__PURE__ */ jsx29("span", { className: "mb-1.5 block text-sm font-medium text-ph-ink", children: "Colour" }),
6282
+ /* @__PURE__ */ jsxs24("div", { className: "flex flex-wrap items-center gap-2", children: [
6283
+ /* @__PURE__ */ jsx29(
6284
+ "button",
6285
+ {
6286
+ type: "button",
6287
+ "aria-label": "No colour",
6288
+ "aria-pressed": !draft.color,
6289
+ title: "No colour",
6290
+ onClick: () => setDraft(__spreadProps(__spreadValues({}, draft), { color: "" })),
6291
+ className: cn(
6292
+ "flex h-8 w-8 items-center justify-center rounded-full border border-ph-border bg-ph-surface text-ph-mutedtext ring-offset-2",
6293
+ !draft.color && "ring-2 ring-ph-brand"
6294
+ ),
6295
+ children: /* @__PURE__ */ jsx29(Prohibition, { className: "h-4 w-4", "aria-hidden": true })
6296
+ }
6297
+ ),
5910
6298
  [
5911
6299
  "#6366f1",
5912
6300
  "#0ea5e9",
@@ -5915,7 +6303,7 @@ function SuiteClientsProjectsDirectory({
5915
6303
  "#ef4444",
5916
6304
  "#a855f7",
5917
6305
  "#64748b"
5918
- ].map((color) => /* @__PURE__ */ jsx27(
6306
+ ].map((color) => /* @__PURE__ */ jsx29(
5919
6307
  "button",
5920
6308
  {
5921
6309
  type: "button",
@@ -5930,33 +6318,70 @@ function SuiteClientsProjectsDirectory({
5930
6318
  },
5931
6319
  color
5932
6320
  )),
5933
- /* @__PURE__ */ jsx27(
5934
- Input,
6321
+ /* @__PURE__ */ jsxs24(
6322
+ "label",
5935
6323
  {
5936
- hideLabel: true,
5937
- label: "Custom colour",
5938
- type: "color",
5939
- value: draft.color,
5940
- onChange: (event) => setDraft(__spreadProps(__spreadValues({}, draft), { color: event.target.value })),
5941
- className: "h-8 w-8 p-0"
6324
+ className: cn(
6325
+ "relative inline-flex h-8 w-8 cursor-pointer items-center justify-center rounded-full ring-1 ring-ph-border ring-offset-2",
6326
+ ![
6327
+ "#6366f1",
6328
+ "#0ea5e9",
6329
+ "#10b981",
6330
+ "#f59e0b",
6331
+ "#ef4444",
6332
+ "#a855f7",
6333
+ "#64748b"
6334
+ ].includes(draft.color) && "ring-2 ring-ph-brand"
6335
+ ),
6336
+ style: {
6337
+ background: "conic-gradient(from 0deg, #ef4444, #f59e0b, #eab308, #22c55e, #06b6d4, #3b82f6, #8b5cf6, #ec4899, #ef4444)"
6338
+ },
6339
+ title: "Custom colour",
6340
+ children: [
6341
+ /* @__PURE__ */ jsx29("span", { className: "flex h-4 w-4 items-center justify-center rounded-full bg-ph-surface", children: [
6342
+ "#6366f1",
6343
+ "#0ea5e9",
6344
+ "#10b981",
6345
+ "#f59e0b",
6346
+ "#ef4444",
6347
+ "#a855f7",
6348
+ "#64748b"
6349
+ ].includes(draft.color) ? /* @__PURE__ */ jsx29(Plus2, { className: "h-3 w-3 text-ph-ink", "aria-hidden": true }) : /* @__PURE__ */ jsx29(
6350
+ "span",
6351
+ {
6352
+ className: "h-2.5 w-2.5 rounded-full",
6353
+ style: { backgroundColor: draft.color }
6354
+ }
6355
+ ) }),
6356
+ /* @__PURE__ */ jsx29(
6357
+ "input",
6358
+ {
6359
+ type: "color",
6360
+ "aria-label": "Custom colour",
6361
+ value: draft.color,
6362
+ onChange: (event) => setDraft(__spreadProps(__spreadValues({}, draft), { color: event.target.value })),
6363
+ className: "sr-only"
6364
+ }
6365
+ )
6366
+ ]
5942
6367
  }
5943
6368
  )
5944
6369
  ] })
5945
6370
  ] }),
5946
- (editing == null ? void 0 : editing.kind.includes("project")) ? /* @__PURE__ */ jsxs23(
6371
+ (editing == null ? void 0 : editing.kind.includes("project")) ? /* @__PURE__ */ jsxs24(
5947
6372
  Select,
5948
6373
  {
5949
6374
  label: "Client",
5950
6375
  value: draftClientId != null ? draftClientId : "",
5951
6376
  onChange: (event) => setDraftClientId(event.target.value || null),
5952
6377
  children: [
5953
- /* @__PURE__ */ jsx27("option", { value: "", children: "No client" }),
5954
- clients.map((client) => /* @__PURE__ */ jsx27("option", { value: client.id, children: client.name }, client.id))
6378
+ /* @__PURE__ */ jsx29("option", { value: "", children: "No client" }),
6379
+ clients.map((client) => /* @__PURE__ */ jsx29("option", { value: client.id, children: client.name }, client.id))
5955
6380
  ]
5956
6381
  }
5957
6382
  ) : null,
5958
- (editing == null ? void 0 : editing.kind.includes("project")) ? /* @__PURE__ */ jsxs23("label", { className: "flex items-center gap-2 text-sm text-ph-ink", children: [
5959
- /* @__PURE__ */ jsx27(
6383
+ (editing == null ? void 0 : editing.kind.includes("project")) ? /* @__PURE__ */ jsxs24("label", { className: "flex items-center gap-2 text-sm text-ph-ink", children: [
6384
+ /* @__PURE__ */ jsx29(
5960
6385
  "input",
5961
6386
  {
5962
6387
  type: "checkbox",
@@ -5969,17 +6394,26 @@ function SuiteClientsProjectsDirectory({
5969
6394
  ] })
5970
6395
  }
5971
6396
  ),
5972
- /* @__PURE__ */ jsx27(
6397
+ libraryOpen ? /* @__PURE__ */ jsx29(
6398
+ Modal,
6399
+ {
6400
+ open: true,
6401
+ onClose: () => setLibraryOpen(false),
6402
+ title: "Icon library",
6403
+ children: renderIconLibrary ? renderIconLibrary({ onPick: pickFromLibrary }) : /* @__PURE__ */ jsx29(SuitePaletteLibrary, { onPick: pickFromLibrary })
6404
+ }
6405
+ ) : null,
6406
+ /* @__PURE__ */ jsx29(
5973
6407
  Modal,
5974
6408
  {
5975
6409
  open: confirming !== null,
5976
6410
  onClose: () => setConfirming(null),
5977
6411
  title: "Confirm deletion",
5978
- footer: /* @__PURE__ */ jsxs23("div", { className: "flex justify-end gap-2", children: [
5979
- /* @__PURE__ */ jsx27(Button, { variant: "tertiary", onClick: () => setConfirming(null), children: "Cancel" }),
5980
- /* @__PURE__ */ jsx27(Button, { variant: "primary", onClick: () => void confirmRemove(), children: "Delete" })
6412
+ footer: /* @__PURE__ */ jsxs24("div", { className: "flex justify-end gap-2", children: [
6413
+ /* @__PURE__ */ jsx29(Button, { variant: "tertiary", onClick: () => setConfirming(null), children: "Cancel" }),
6414
+ /* @__PURE__ */ jsx29(Button, { variant: "primary", onClick: () => void confirmRemove(), children: "Delete" })
5981
6415
  ] }),
5982
- children: /* @__PURE__ */ jsxs23("p", { className: "text-sm text-ph-ink", children: [
6416
+ children: /* @__PURE__ */ jsxs24("p", { className: "text-sm text-ph-ink", children: [
5983
6417
  "Delete ",
5984
6418
  confirming == null ? void 0 : confirming.item.name,
5985
6419
  "? This cannot be undone."
@@ -6024,6 +6458,7 @@ export {
6024
6458
  SuiteBreadcrumbs,
6025
6459
  SuiteClientsProjectsDirectory,
6026
6460
  SuiteEmptyState,
6461
+ SuiteEntityIcon,
6027
6462
  SuiteIcon,
6028
6463
  SuiteIntegrationPicker,
6029
6464
  SuiteIntegrationRules,
@@ -6033,6 +6468,7 @@ export {
6033
6468
  SuiteNotificationBell,
6034
6469
  SuitePage,
6035
6470
  SuitePageHeader,
6471
+ SuitePaletteLibrary,
6036
6472
  SuiteSectionHeader,
6037
6473
  SuiteSettingsLayout,
6038
6474
  SuiteSettingsMobileNav,
@@ -6065,6 +6501,9 @@ export {
6065
6501
  cn2 as cn,
6066
6502
  consumePendingAskAiPrompt,
6067
6503
  consumeSuiteAskAiOpenFromLocation,
6504
+ fetchPaletteCollection,
6505
+ fetchPaletteLibrary,
6506
+ findPaletteIcons,
6068
6507
  getTodayGreeting,
6069
6508
  m,
6070
6509
  openSuiteAskAi,