@xenide-io/the-old-ui-theme 0.6.7 → 0.6.9

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
@@ -798,7 +798,7 @@ function TodayLayout({
798
798
  );
799
799
  }
800
800
  function TodayAskAiCard({
801
- title = "Ask AI",
801
+ title = "Shelly AI",
802
802
  description = "Ask about your workspace, draft something, or look a fact up online.",
803
803
  cta = "Ask",
804
804
  className,
@@ -1131,6 +1131,31 @@ function resolveSuiteNotificationHref(href, sourceApp) {
1131
1131
  if (!slug) return path;
1132
1132
  return `${suiteAppBaseUrl(slug)}${path}`;
1133
1133
  }
1134
+ function classifySuiteHref(href, bases, currentOrigin = "") {
1135
+ let url;
1136
+ try {
1137
+ url = new URL(href, currentOrigin || "http://local.invalid");
1138
+ } catch (e) {
1139
+ return null;
1140
+ }
1141
+ if (url.protocol !== "http:" && url.protocol !== "https:") return null;
1142
+ for (const slug of Object.keys(bases)) {
1143
+ const base = bases[slug];
1144
+ if (!base) continue;
1145
+ try {
1146
+ if (new URL(base).origin !== url.origin) continue;
1147
+ } catch (e) {
1148
+ continue;
1149
+ }
1150
+ const path = `${url.pathname}${url.search}${url.hash}` || "/";
1151
+ return {
1152
+ slug,
1153
+ path,
1154
+ sameApp: Boolean(currentOrigin && url.origin === currentOrigin)
1155
+ };
1156
+ }
1157
+ return null;
1158
+ }
1134
1159
 
1135
1160
  // src/suite/components/suite-notification-bell.tsx
1136
1161
  import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
@@ -2136,6 +2161,7 @@ import {
2136
2161
  Suspense,
2137
2162
  useCallback as useCallback2,
2138
2163
  useEffect as useEffect6,
2164
+ useId,
2139
2165
  useLayoutEffect,
2140
2166
  useRef as useRef3,
2141
2167
  useState as useState7
@@ -2143,18 +2169,18 @@ import {
2143
2169
  import {
2144
2170
  ArrowDown,
2145
2171
  ArrowUp,
2146
- Check as Check2,
2147
- Copy,
2148
2172
  Erase,
2149
2173
  Sparks,
2150
2174
  Square,
2151
- WarningTriangle,
2152
- Xmark as X2
2175
+ WarningTriangle
2153
2176
  } from "iconoir-react";
2154
- import { Fragment as Fragment5, jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
2177
+ import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
2155
2178
  var SuiteAiBlockNoteMessage = lazy(() => import("./ai-message-blocknote-DIUICX3G.mjs"));
2156
2179
  var SUITE_OPEN_ASK_AI_EVENT = "shellstack:open-ask-ai";
2180
+ var pendingAskAiPrompt = null;
2157
2181
  function openSuiteAskAi(detail) {
2182
+ var _a;
2183
+ pendingAskAiPrompt = ((_a = detail == null ? void 0 : detail.prompt) == null ? void 0 : _a.trim()) || null;
2158
2184
  if (typeof window === "undefined") return;
2159
2185
  window.dispatchEvent(
2160
2186
  new CustomEvent(SUITE_OPEN_ASK_AI_EVENT, {
@@ -2162,125 +2188,59 @@ function openSuiteAskAi(detail) {
2162
2188
  })
2163
2189
  );
2164
2190
  }
2165
- var LAUNCHER_EDGE_GAP = 12;
2166
- var LAUNCHER_STORAGE_KEY = "suite-ask-ai-launcher-position";
2167
- function resolveSuiteAiLauncherPosition(edge, desiredX, desiredY, viewportWidth, viewportHeight, launcherWidth, launcherHeight) {
2168
- const maxX = Math.max(
2169
- LAUNCHER_EDGE_GAP,
2170
- viewportWidth - launcherWidth - LAUNCHER_EDGE_GAP
2171
- );
2172
- const maxY = Math.max(
2173
- LAUNCHER_EDGE_GAP,
2174
- viewportHeight - launcherHeight - LAUNCHER_EDGE_GAP
2175
- );
2176
- const clampX = (x) => Math.min(Math.max(x, LAUNCHER_EDGE_GAP), maxX);
2177
- const clampY = (y) => Math.min(Math.max(y, LAUNCHER_EDGE_GAP), maxY);
2178
- switch (edge) {
2179
- case "left":
2180
- return { x: LAUNCHER_EDGE_GAP, y: clampY(desiredY) };
2181
- case "right":
2182
- return { x: maxX, y: clampY(desiredY) };
2183
- case "top":
2184
- return { x: clampX(desiredX), y: LAUNCHER_EDGE_GAP };
2185
- case "bottom":
2186
- return { x: clampX(desiredX), y: maxY };
2187
- }
2188
- }
2189
- function resolveSuiteAiNearestEdge(x, y, width, height, viewportWidth, viewportHeight) {
2190
- const centerX = x + width / 2;
2191
- const centerY = y + height / 2;
2192
- const candidates = [
2193
- { edge: "left", distance: centerX },
2194
- { edge: "right", distance: viewportWidth - centerX },
2195
- { edge: "top", distance: centerY },
2196
- { edge: "bottom", distance: viewportHeight - centerY }
2197
- ];
2198
- return candidates.reduce(
2199
- (nearest, candidate) => candidate.distance < nearest.distance ? candidate : nearest
2200
- ).edge;
2201
- }
2202
- function resolveSuiteAiPanelSide(edge, x, viewportWidth) {
2203
- if (edge === "left") return "left";
2204
- if (edge === "right") return "right";
2205
- return x < viewportWidth / 2 ? "left" : "right";
2191
+ function consumePendingAskAiPrompt() {
2192
+ const next = pendingAskAiPrompt;
2193
+ pendingAskAiPrompt = null;
2194
+ return next;
2206
2195
  }
2207
2196
  function SuiteAiPanel({
2208
2197
  presets = [],
2209
- emptyState = "Ask anything about your workspace, or look something up online.",
2210
- title = "Ask AI",
2198
+ emptyState = "Ask when you are ready \u2014 overdue work, a running timer, or anything else.",
2199
+ title = "Shelly AI",
2211
2200
  fetchChat,
2212
2201
  sendMessage,
2213
2202
  clearChat,
2214
2203
  brandIcon: BrandIcon,
2215
2204
  spinner: Spinner,
2216
- hideLauncher = false
2205
+ open: openProp,
2206
+ onOpenChange,
2207
+ suiteAppBases,
2208
+ onSwitchApp
2217
2209
  }) {
2218
- const [open, setOpen] = useState7(false);
2210
+ const inputId = useId();
2211
+ const [uncontrolledOpen, setUncontrolledOpen] = useState7(false);
2212
+ const open = openProp != null ? openProp : uncontrolledOpen;
2213
+ const setOpen = useCallback2(
2214
+ (next) => {
2215
+ if (openProp === void 0) setUncontrolledOpen(next);
2216
+ onOpenChange == null ? void 0 : onOpenChange(next);
2217
+ },
2218
+ [onOpenChange, openProp]
2219
+ );
2219
2220
  const [prompt, setPrompt] = useState7("");
2220
2221
  const [messages, setMessages] = useState7([]);
2221
2222
  const [loading, setLoading] = useState7(false);
2222
2223
  const [hydrating, setHydrating] = useState7(false);
2223
2224
  const [error, setError] = useState7("");
2224
- const [copiedId, setCopiedId] = useState7(null);
2225
2225
  const [atBottom, setAtBottom] = useState7(true);
2226
- const [launcherSide, setLauncherSide] = useState7("right");
2227
- const [panelSide, setPanelSide] = useState7("right");
2228
- const [launcherPosition, setLauncherPosition] = useState7(null);
2229
- const [draggingLauncher, setDraggingLauncher] = useState7(false);
2230
2226
  const scrollerRef = useRef3(null);
2231
2227
  const textareaRef = useRef3(null);
2232
2228
  const abortRef = useRef3(null);
2233
- const launcherRef = useRef3(null);
2234
- const launcherSideRef = useRef3("right");
2235
- const launcherPositionRef = useRef3(null);
2236
- const launcherDragRef = useRef3(null);
2237
- const suppressLauncherClickRef = useRef3(false);
2238
2229
  const pendingPromptRef = useRef3(null);
2239
2230
  useEffect6(() => {
2240
- const launcher = launcherRef.current;
2241
- if (!launcher) return;
2242
- let side = "right";
2243
- let desiredX = LAUNCHER_EDGE_GAP;
2244
- let desiredY = window.innerHeight - launcher.offsetHeight - 20;
2245
- try {
2246
- const stored = JSON.parse(
2247
- localStorage.getItem(LAUNCHER_STORAGE_KEY) || "null"
2248
- );
2249
- if ((stored == null ? void 0 : stored.side) === "top" || (stored == null ? void 0 : stored.side) === "right" || (stored == null ? void 0 : stored.side) === "bottom" || (stored == null ? void 0 : stored.side) === "left")
2250
- side = stored.side;
2251
- if (typeof (stored == null ? void 0 : stored.x) === "number") desiredX = stored.x;
2252
- if (typeof (stored == null ? void 0 : stored.y) === "number") desiredY = stored.y;
2253
- } catch (e) {
2231
+ function onOpen(event) {
2232
+ var _a;
2233
+ const detail = event.detail;
2234
+ const queued = ((_a = detail == null ? void 0 : detail.prompt) == null ? void 0 : _a.trim()) || consumePendingAskAiPrompt();
2235
+ setOpen(true);
2236
+ if (queued) {
2237
+ pendingPromptRef.current = queued;
2238
+ setPrompt(queued);
2239
+ }
2254
2240
  }
2255
- launcherSideRef.current = side;
2256
- setLauncherSide(side);
2257
- const placeLauncher = () => {
2258
- var _a, _b, _c, _d;
2259
- const element = launcherRef.current;
2260
- if (!element) return;
2261
- const next = resolveSuiteAiLauncherPosition(
2262
- launcherSideRef.current,
2263
- (_b = (_a = launcherPositionRef.current) == null ? void 0 : _a.x) != null ? _b : desiredX,
2264
- (_d = (_c = launcherPositionRef.current) == null ? void 0 : _c.y) != null ? _d : desiredY,
2265
- window.innerWidth,
2266
- window.innerHeight,
2267
- element.offsetWidth,
2268
- element.offsetHeight
2269
- );
2270
- launcherPositionRef.current = next;
2271
- setLauncherPosition(next);
2272
- setPanelSide(
2273
- resolveSuiteAiPanelSide(
2274
- launcherSideRef.current,
2275
- next.x,
2276
- window.innerWidth
2277
- )
2278
- );
2279
- };
2280
- placeLauncher();
2281
- window.addEventListener("resize", placeLauncher);
2282
- return () => window.removeEventListener("resize", placeLauncher);
2283
- }, []);
2241
+ window.addEventListener(SUITE_OPEN_ASK_AI_EVENT, onOpen);
2242
+ return () => window.removeEventListener(SUITE_OPEN_ASK_AI_EVENT, onOpen);
2243
+ }, [setOpen]);
2284
2244
  const scrollToBottom = useCallback2((behavior = "auto") => {
2285
2245
  const el = scrollerRef.current;
2286
2246
  if (!el) return;
@@ -2305,33 +2265,21 @@ function SuiteAiPanel({
2305
2265
  }
2306
2266
  } catch (err) {
2307
2267
  setError(
2308
- err instanceof Error ? err.message : "Could not load your Ask AI chat."
2268
+ err instanceof Error ? err.message : "Could not load Shelly AI."
2309
2269
  );
2310
2270
  } finally {
2311
2271
  setHydrating(false);
2312
2272
  }
2313
2273
  }, [fetchChat]);
2314
2274
  useEffect6(() => {
2315
- function onOpen(event) {
2316
- var _a;
2317
- const detail = event.detail;
2318
- setOpen(true);
2319
- if ((_a = detail == null ? void 0 : detail.prompt) == null ? void 0 : _a.trim()) {
2320
- pendingPromptRef.current = detail.prompt.trim();
2321
- setPrompt(detail.prompt.trim());
2322
- }
2323
- }
2324
- window.addEventListener(SUITE_OPEN_ASK_AI_EVENT, onOpen);
2325
- return () => window.removeEventListener(SUITE_OPEN_ASK_AI_EVENT, onOpen);
2326
- }, []);
2327
- useEffect6(() => {
2275
+ var _a;
2328
2276
  if (!open) return;
2277
+ const queued = (_a = pendingPromptRef.current) != null ? _a : consumePendingAskAiPrompt();
2278
+ pendingPromptRef.current = queued;
2329
2279
  void hydrate().then(() => {
2330
2280
  const pending = pendingPromptRef.current;
2331
2281
  pendingPromptRef.current = null;
2332
- if (pending) {
2333
- setPrompt(pending);
2334
- }
2282
+ if (pending) setPrompt(pending);
2335
2283
  });
2336
2284
  }, [open, hydrate]);
2337
2285
  useEffect6(() => {
@@ -2341,14 +2289,6 @@ function SuiteAiPanel({
2341
2289
  var _a;
2342
2290
  if (open && !hydrating) (_a = textareaRef.current) == null ? void 0 : _a.focus();
2343
2291
  }, [open, hydrating]);
2344
- useEffect6(() => {
2345
- if (!open) return;
2346
- function onKey(event) {
2347
- if (event.key === "Escape") setOpen(false);
2348
- }
2349
- window.addEventListener("keydown", onKey);
2350
- return () => window.removeEventListener("keydown", onKey);
2351
- }, [open]);
2352
2292
  useLayoutEffect(() => {
2353
2293
  const el = textareaRef.current;
2354
2294
  if (!el) return;
@@ -2398,7 +2338,7 @@ function SuiteAiPanel({
2398
2338
  }
2399
2339
  function retry() {
2400
2340
  var _a;
2401
- const lastUser = (_a = [...messages].reverse().find((m2) => m2.role === "user")) == null ? void 0 : _a.content;
2341
+ const lastUser = (_a = [...messages].reverse().find((message) => message.role === "user")) == null ? void 0 : _a.content;
2402
2342
  setError("");
2403
2343
  if (lastUser) void ask(lastUser);
2404
2344
  else void hydrate();
@@ -2415,421 +2355,350 @@ function SuiteAiPanel({
2415
2355
  );
2416
2356
  }
2417
2357
  }
2418
- async function copyMessage(index, content) {
2419
- try {
2420
- await navigator.clipboard.writeText(content);
2421
- setCopiedId(index);
2422
- window.setTimeout(() => setCopiedId(null), 1500);
2423
- } catch (e) {
2424
- }
2425
- }
2426
- function saveLauncherPosition(edge, position) {
2427
- try {
2428
- localStorage.setItem(
2429
- LAUNCHER_STORAGE_KEY,
2430
- JSON.stringify({ side: edge, x: position.x, y: position.y })
2431
- );
2432
- } catch (e) {
2433
- }
2434
- }
2435
- function dockLauncher(edge, desiredX, desiredY) {
2436
- const launcher = launcherRef.current;
2437
- if (!launcher) return;
2438
- const next = resolveSuiteAiLauncherPosition(
2439
- edge,
2440
- desiredX,
2441
- desiredY,
2442
- window.innerWidth,
2443
- window.innerHeight,
2444
- launcher.offsetWidth,
2445
- launcher.offsetHeight
2446
- );
2447
- launcherSideRef.current = edge;
2448
- launcherPositionRef.current = next;
2449
- setLauncherSide(edge);
2450
- setLauncherPosition(next);
2451
- setPanelSide(resolveSuiteAiPanelSide(edge, next.x, window.innerWidth));
2452
- saveLauncherPosition(edge, next);
2453
- }
2454
- function startLauncherDrag(event) {
2455
- if (event.pointerType === "mouse" && event.button !== 0) return;
2456
- const rect = event.currentTarget.getBoundingClientRect();
2457
- launcherDragRef.current = {
2458
- pointerId: event.pointerId,
2459
- offsetX: event.clientX - rect.left,
2460
- offsetY: event.clientY - rect.top,
2461
- startX: event.clientX,
2462
- startY: event.clientY
2463
- };
2464
- suppressLauncherClickRef.current = false;
2465
- event.currentTarget.setPointerCapture(event.pointerId);
2466
- setDraggingLauncher(true);
2467
- }
2468
- function moveLauncher(event) {
2469
- const drag = launcherDragRef.current;
2470
- if (!drag || drag.pointerId !== event.pointerId) return;
2471
- const launcher = event.currentTarget;
2472
- const maxX = Math.max(
2473
- LAUNCHER_EDGE_GAP,
2474
- window.innerWidth - launcher.offsetWidth - LAUNCHER_EDGE_GAP
2475
- );
2476
- const maxY = Math.max(
2477
- LAUNCHER_EDGE_GAP,
2478
- window.innerHeight - launcher.offsetHeight - LAUNCHER_EDGE_GAP
2479
- );
2480
- const next = {
2481
- x: Math.min(
2482
- Math.max(event.clientX - drag.offsetX, LAUNCHER_EDGE_GAP),
2483
- maxX
2484
- ),
2485
- y: Math.min(
2486
- Math.max(event.clientY - drag.offsetY, LAUNCHER_EDGE_GAP),
2487
- maxY
2488
- )
2489
- };
2490
- if (Math.hypot(event.clientX - drag.startX, event.clientY - drag.startY) > 4) {
2491
- suppressLauncherClickRef.current = true;
2492
- }
2493
- launcherPositionRef.current = next;
2494
- setLauncherPosition(next);
2495
- }
2496
- function finishLauncherDrag(event) {
2497
- var _a, _b, _c, _d;
2498
- const drag = launcherDragRef.current;
2499
- if (!drag || drag.pointerId !== event.pointerId) return;
2500
- if (event.currentTarget.hasPointerCapture(event.pointerId)) {
2501
- event.currentTarget.releasePointerCapture(event.pointerId);
2358
+ function onConversationClick(event) {
2359
+ var _a;
2360
+ if (event.defaultPrevented) return;
2361
+ if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
2362
+ return;
2502
2363
  }
2503
- launcherDragRef.current = null;
2504
- setDraggingLauncher(false);
2505
- const rect = event.currentTarget.getBoundingClientRect();
2506
- const currentX = (_b = (_a = launcherPositionRef.current) == null ? void 0 : _a.x) != null ? _b : rect.left;
2507
- const currentY = (_d = (_c = launcherPositionRef.current) == null ? void 0 : _c.y) != null ? _d : rect.top;
2508
- const edge = resolveSuiteAiNearestEdge(
2509
- currentX,
2510
- currentY,
2511
- rect.width,
2512
- rect.height,
2513
- window.innerWidth,
2514
- window.innerHeight
2364
+ const anchor = (_a = event.target) == null ? void 0 : _a.closest("a");
2365
+ if (!anchor || !suiteAppBases) return;
2366
+ const href = anchor.href;
2367
+ if (!href) return;
2368
+ const match = classifySuiteHref(
2369
+ href,
2370
+ suiteAppBases,
2371
+ window.location.origin
2515
2372
  );
2516
- dockLauncher(edge, currentX, currentY);
2517
- }
2518
- function moveLauncherWithKeyboard(event) {
2519
- var _a, _b, _c, _d;
2520
- const edgeByKey = {
2521
- ArrowLeft: "left",
2522
- ArrowRight: "right",
2523
- ArrowUp: "top",
2524
- ArrowDown: "bottom"
2525
- };
2526
- const edge = edgeByKey[event.key];
2527
- if (!edge) return;
2373
+ if (!match) return;
2528
2374
  event.preventDefault();
2529
- const rect = event.currentTarget.getBoundingClientRect();
2530
- const currentX = (_b = (_a = launcherPositionRef.current) == null ? void 0 : _a.x) != null ? _b : rect.left;
2531
- const currentY = (_d = (_c = launcherPositionRef.current) == null ? void 0 : _c.y) != null ? _d : rect.top;
2532
- dockLauncher(edge, currentX, currentY);
2375
+ if (match.sameApp) {
2376
+ window.location.assign(match.path);
2377
+ return;
2378
+ }
2379
+ if (onSwitchApp) onSwitchApp(match.slug, match.path);
2380
+ else window.location.assign(anchor.href);
2533
2381
  }
2382
+ if (!open) return null;
2534
2383
  const Icon = BrandIcon != null ? BrandIcon : Sparks;
2535
- return /* @__PURE__ */ jsxs15(Fragment5, { children: [
2536
- !hideLauncher ? /* @__PURE__ */ jsxs15(Fragment5, { children: [
2537
- /* @__PURE__ */ jsxs15(
2538
- "button",
2539
- {
2540
- ref: launcherRef,
2541
- type: "button",
2542
- "data-test": "ai-panel-launcher",
2543
- onClick: () => {
2544
- if (suppressLauncherClickRef.current) {
2545
- suppressLauncherClickRef.current = false;
2546
- return;
2547
- }
2548
- setOpen(true);
2549
- },
2550
- onPointerDown: startLauncherDrag,
2551
- onPointerMove: moveLauncher,
2552
- onPointerUp: finishLauncherDrag,
2553
- onPointerCancel: finishLauncherDrag,
2554
- onKeyDown: moveLauncherWithKeyboard,
2555
- className: `fixed z-30 flex touch-none select-none items-center gap-2 rounded-full border border-ph-border bg-ph-surface px-4 py-2.5 text-sm font-medium text-ph-ink shadow-ph hover:bg-ph-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-brand ${draggingLauncher ? "cursor-grabbing" : "cursor-grab"}`,
2556
- style: launcherPosition ? { left: launcherPosition.x, top: launcherPosition.y } : { bottom: 20, right: 20 },
2557
- "aria-label": "Open Ask AI",
2558
- "aria-describedby": "suite-ask-ai-launcher-help",
2559
- children: [
2560
- /* @__PURE__ */ jsx17(Icon, { className: "h-4 w-4 text-ph-brand" }),
2561
- "Ask AI"
2562
- ]
2563
- }
2564
- ),
2565
- /* @__PURE__ */ jsx17("span", { id: "suite-ask-ai-launcher-help", className: "sr-only", children: "Drag to reposition, or use arrow keys. The launcher docks to the nearest screen edge." })
2566
- ] }) : null,
2567
- open ? /* @__PURE__ */ jsxs15(
2568
- "div",
2569
- {
2570
- className: "fixed inset-0 z-40",
2571
- role: "dialog",
2572
- "aria-modal": "true",
2573
- "aria-label": title,
2574
- children: [
2575
- /* @__PURE__ */ jsx17(
2384
+ return /* @__PURE__ */ jsxs15(
2385
+ "aside",
2386
+ {
2387
+ className: "flex h-full min-h-0 flex-col bg-ph-canvas",
2388
+ "data-test": "suite-ask-ai-panel",
2389
+ "aria-label": title,
2390
+ children: [
2391
+ /* @__PURE__ */ jsxs15("header", { className: "flex items-center gap-2 px-2 pb-2", children: [
2392
+ /* @__PURE__ */ jsx17("h2", { className: "sr-only", children: title }),
2393
+ messages.length > 0 ? /* @__PURE__ */ jsxs15(
2576
2394
  "button",
2577
2395
  {
2578
2396
  type: "button",
2579
- className: "absolute inset-0 bg-ph-ink/25",
2580
- onClick: () => setOpen(false),
2581
- "aria-label": "Close Ask AI",
2582
- tabIndex: -1
2397
+ onClick: () => void handleClear(),
2398
+ disabled: loading,
2399
+ className: "ml-auto inline-flex h-9 items-center gap-1.5 rounded-lg px-2 text-xs font-medium text-ph-subtle transition-colors hover:bg-ph-muted hover:text-ph-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-focus disabled:opacity-40",
2400
+ "data-test": "ask-ai-clear",
2401
+ children: [
2402
+ /* @__PURE__ */ jsx17(Erase, { className: "h-3.5 w-3.5" }),
2403
+ "Clear"
2404
+ ]
2583
2405
  }
2584
- ),
2406
+ ) : null
2407
+ ] }),
2408
+ /* @__PURE__ */ jsxs15("div", { className: "relative min-h-0 flex-1", children: [
2585
2409
  /* @__PURE__ */ jsxs15(
2586
- "aside",
2410
+ "div",
2587
2411
  {
2588
- className: `absolute inset-y-0 flex w-full flex-col bg-ph-canvas shadow-2xl sm:max-w-xl ${panelSide === "left" ? "left-0 border-r border-ph-border" : "right-0 border-l border-ph-border"}`,
2589
- "data-test": "suite-ask-ai-panel",
2412
+ ref: scrollerRef,
2413
+ onScroll: handleScroll,
2414
+ onClick: onConversationClick,
2415
+ role: "log",
2416
+ "aria-live": "polite",
2417
+ "aria-label": "Conversation",
2418
+ className: "suite-scroll-lock h-full space-y-5 overflow-y-auto px-2 py-3",
2590
2419
  children: [
2591
- /* @__PURE__ */ jsxs15("header", { className: "flex items-center gap-2 px-4 py-3", children: [
2592
- /* @__PURE__ */ jsx17("h2", { className: "min-w-0 flex-1 truncate text-sm font-semibold text-ph-ink", children: title }),
2593
- messages.length > 0 ? /* @__PURE__ */ jsxs15(
2420
+ hydrating && messages.length === 0 ? /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2 text-sm text-ph-subtle", children: [
2421
+ /* @__PURE__ */ jsx17(Spinner, { className: "h-4 w-4 animate-spin" }),
2422
+ "Loading your chat\u2026"
2423
+ ] }) : null,
2424
+ !hydrating && messages.length === 0 && !error ? /* @__PURE__ */ jsxs15("div", { className: "mx-auto mt-4 flex max-w-sm flex-col items-center px-1 text-center", children: [
2425
+ /* @__PURE__ */ jsx17("span", { className: "flex h-10 w-10 items-center justify-center rounded-2xl bg-ph-brand/10 text-ph-brand", children: /* @__PURE__ */ jsx17(Icon, { className: "h-5 w-5" }) }),
2426
+ /* @__PURE__ */ jsx17("p", { className: "mt-3 font-display text-base font-semibold text-ph-ink", children: "How can I help?" }),
2427
+ /* @__PURE__ */ jsx17("p", { className: "mt-1 text-sm leading-relaxed text-ph-subtle", children: emptyState }),
2428
+ presets.length > 0 ? /* @__PURE__ */ jsx17("div", { className: "mt-4 flex w-full flex-col gap-2", children: presets.map((preset) => /* @__PURE__ */ jsxs15(
2594
2429
  "button",
2595
2430
  {
2596
2431
  type: "button",
2597
- onClick: () => void handleClear(),
2598
- disabled: loading,
2599
- className: "inline-flex h-10 items-center gap-1.5 rounded-lg px-2.5 text-xs font-medium text-ph-subtle transition-colors hover:bg-ph-muted hover:text-ph-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-focus disabled:opacity-40",
2600
- "data-test": "ask-ai-clear",
2432
+ onClick: () => void ask(preset.prompt),
2433
+ disabled: loading || hydrating,
2434
+ className: "group flex w-full items-center gap-2 rounded-xl border border-ph-border bg-ph-surface px-3 py-2 text-left text-sm text-ph-ink transition-colors hover:border-ph-brand/40 hover:bg-ph-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-focus disabled:opacity-40",
2601
2435
  children: [
2602
- /* @__PURE__ */ jsx17(Erase, { className: "h-3.5 w-3.5" }),
2603
- "Clear"
2436
+ /* @__PURE__ */ jsx17(Sparks, { className: "h-4 w-4 shrink-0 text-ph-brand" }),
2437
+ /* @__PURE__ */ jsx17("span", { className: "min-w-0 flex-1 truncate", children: preset.label }),
2438
+ /* @__PURE__ */ jsx17(ArrowUp, { className: "h-3.5 w-3.5 shrink-0 rotate-45 text-ph-mutedtext transition-transform group-hover:translate-x-0.5" })
2604
2439
  ]
2605
- }
2606
- ) : null,
2607
- /* @__PURE__ */ jsx17(
2608
- "button",
2609
- {
2610
- type: "button",
2611
- onClick: () => setOpen(false),
2612
- className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-lg text-ph-subtle transition-colors hover:bg-ph-muted hover:text-ph-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-focus",
2613
- "aria-label": "Close Ask AI",
2614
- children: /* @__PURE__ */ jsx17(X2, { className: "h-4 w-4" })
2615
- }
2616
- )
2617
- ] }),
2618
- /* @__PURE__ */ jsxs15("div", { className: "relative min-h-0 flex-1", children: [
2619
- /* @__PURE__ */ jsxs15(
2440
+ },
2441
+ preset.label
2442
+ )) }) : null
2443
+ ] }) : null,
2444
+ messages.map((message, index) => {
2445
+ const isUser = message.role === "user";
2446
+ if (isUser) {
2447
+ return /* @__PURE__ */ jsx17(
2448
+ "div",
2449
+ {
2450
+ className: "flex justify-end",
2451
+ "data-test": "ask-ai-user",
2452
+ children: /* @__PURE__ */ jsx17("div", { className: "w-fit max-w-[85%] whitespace-pre-wrap break-words rounded-2xl rounded-br-md bg-ph-brand px-3 py-2 text-sm leading-relaxed text-[var(--ph-on-accent)] [overflow-wrap:anywhere]", children: message.content })
2453
+ },
2454
+ `user-${index}`
2455
+ );
2456
+ }
2457
+ return /* @__PURE__ */ jsxs15(
2620
2458
  "div",
2621
2459
  {
2622
- ref: scrollerRef,
2623
- onScroll: handleScroll,
2624
- role: "log",
2625
- "aria-live": "polite",
2626
- "aria-label": "Conversation",
2627
- className: "suite-scroll-lock h-full space-y-5 overflow-y-auto px-4 py-5",
2460
+ className: "flex items-end gap-2",
2461
+ "data-test": "ask-ai-assistant",
2628
2462
  children: [
2629
- hydrating && messages.length === 0 ? /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2 text-sm text-ph-subtle", children: [
2630
- /* @__PURE__ */ jsx17(Spinner, { className: "h-4 w-4 animate-spin" }),
2631
- "Loading your chat\u2026"
2632
- ] }) : null,
2633
- !hydrating && messages.length === 0 && !error ? /* @__PURE__ */ jsxs15("div", { className: "mx-auto mt-6 flex max-w-sm flex-col items-center px-2 text-center", children: [
2634
- /* @__PURE__ */ jsx17("span", { className: "flex h-12 w-12 items-center justify-center rounded-2xl bg-ph-brand/10 text-ph-brand", children: /* @__PURE__ */ jsx17(Icon, { className: "h-6 w-6" }) }),
2635
- /* @__PURE__ */ jsx17("p", { className: "mt-4 font-display text-lg font-semibold text-ph-ink", children: "How can I help?" }),
2636
- /* @__PURE__ */ jsx17("p", { className: "mt-1.5 text-sm leading-relaxed text-ph-subtle", children: emptyState }),
2637
- presets.length > 0 ? /* @__PURE__ */ jsx17("div", { className: "mt-5 flex w-full flex-col gap-2", children: presets.map((preset) => /* @__PURE__ */ jsxs15(
2638
- "button",
2639
- {
2640
- type: "button",
2641
- onClick: () => void ask(preset.prompt),
2642
- disabled: loading || hydrating,
2643
- className: "group flex w-full items-center gap-2 rounded-xl border border-ph-border bg-ph-surface px-3.5 py-2.5 text-left text-sm text-ph-ink transition-colors hover:border-ph-brand/40 hover:bg-ph-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-focus disabled:opacity-40",
2644
- children: [
2645
- /* @__PURE__ */ jsx17(Sparks, { className: "h-4 w-4 shrink-0 text-ph-brand" }),
2646
- /* @__PURE__ */ jsx17("span", { className: "min-w-0 flex-1 truncate", children: preset.label }),
2647
- /* @__PURE__ */ jsx17(ArrowUp, { className: "h-3.5 w-3.5 shrink-0 rotate-45 text-ph-mutedtext transition-transform group-hover:translate-x-0.5" })
2648
- ]
2649
- },
2650
- preset.label
2651
- )) }) : null
2652
- ] }) : null,
2653
- messages.map((message, index) => {
2654
- const isUser = message.role === "user";
2655
- if (isUser) {
2656
- return /* @__PURE__ */ jsx17(
2657
- "div",
2658
- {
2659
- className: "flex justify-end",
2660
- "data-test": "ask-ai-user",
2661
- children: /* @__PURE__ */ jsx17("div", { className: "max-w-[min(85%,42rem)] whitespace-pre-wrap break-words rounded-2xl rounded-br-md bg-ph-brand/12 px-3.5 py-2.5 text-sm leading-relaxed text-ph-ink", children: message.content })
2662
- },
2663
- `user-${index}`
2664
- );
2463
+ /* @__PURE__ */ jsx17(
2464
+ "span",
2465
+ {
2466
+ className: "mb-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-ph-brand/10 text-ph-brand",
2467
+ "aria-hidden": true,
2468
+ children: /* @__PURE__ */ jsx17(Icon, { className: "h-3.5 w-3.5" })
2665
2469
  }
2666
- return /* @__PURE__ */ jsxs15(
2667
- "div",
2668
- {
2669
- className: "flex gap-3",
2670
- "data-test": "ask-ai-assistant",
2671
- children: [
2672
- /* @__PURE__ */ jsx17(
2673
- "span",
2674
- {
2675
- className: "mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-ph-brand/10 text-ph-brand",
2676
- "aria-hidden": true,
2677
- children: /* @__PURE__ */ jsx17(Icon, { className: "h-4 w-4" })
2678
- }
2679
- ),
2680
- /* @__PURE__ */ jsxs15("div", { className: "min-w-0 flex-1", children: [
2681
- /* @__PURE__ */ jsx17("div", { className: "text-sm leading-relaxed text-ph-ink", children: /* @__PURE__ */ jsx17(
2682
- Suspense,
2683
- {
2684
- fallback: /* @__PURE__ */ jsx17("p", { className: "whitespace-pre-wrap break-words", children: message.content }),
2685
- children: /* @__PURE__ */ jsx17(
2686
- SuiteAiBlockNoteMessage,
2687
- {
2688
- markdown: message.content
2689
- }
2690
- )
2691
- }
2692
- ) }),
2693
- /* @__PURE__ */ jsxs15(
2694
- "button",
2695
- {
2696
- type: "button",
2697
- onClick: () => void copyMessage(index, message.content),
2698
- className: "mt-1.5 inline-flex items-center gap-1 rounded-md px-1.5 py-0.5 text-xs text-ph-mutedtext transition-colors hover:bg-ph-muted hover:text-ph-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-focus",
2699
- children: [
2700
- copiedId === index ? /* @__PURE__ */ jsx17(Check2, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx17(Copy, { className: "h-3 w-3" }),
2701
- copiedId === index ? "Copied" : "Copy"
2702
- ]
2703
- }
2704
- )
2705
- ] })
2706
- ]
2707
- },
2708
- `assistant-${index}`
2709
- );
2710
- }),
2711
- loading ? /* @__PURE__ */ jsxs15("div", { className: "flex gap-3", "aria-hidden": true, children: [
2712
- /* @__PURE__ */ jsx17("span", { className: "mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-ph-brand/10 text-ph-brand", children: /* @__PURE__ */ jsx17(Icon, { className: "h-4 w-4" }) }),
2713
- /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-1.5 py-1.5", children: [
2714
- /* @__PURE__ */ jsx17("span", { className: "h-1.5 w-1.5 rounded-full bg-ph-mutedtext motion-safe:animate-bounce" }),
2715
- /* @__PURE__ */ jsx17("span", { className: "h-1.5 w-1.5 rounded-full bg-ph-mutedtext motion-safe:animate-bounce [animation-delay:0.15s]" }),
2716
- /* @__PURE__ */ jsx17("span", { className: "h-1.5 w-1.5 rounded-full bg-ph-mutedtext motion-safe:animate-bounce [animation-delay:0.3s]" })
2717
- ] })
2718
- ] }) : null,
2719
- loading ? /* @__PURE__ */ jsx17("span", { className: "sr-only", "aria-live": "polite", children: "Assistant is responding\u2026" }) : null,
2720
- error ? /* @__PURE__ */ jsxs15(
2721
- "div",
2470
+ ),
2471
+ /* @__PURE__ */ jsx17("div", { className: "min-w-0 max-w-[85%] rounded-2xl rounded-bl-md bg-ph-muted px-3 py-2 text-sm leading-relaxed text-ph-ink", children: /* @__PURE__ */ jsx17(
2472
+ Suspense,
2722
2473
  {
2723
- role: "alert",
2724
- className: "flex items-start gap-2.5 rounded-xl border border-ph-danger/30 bg-ph-danger/10 px-3.5 py-3 text-sm text-ph-ink",
2725
- children: [
2726
- /* @__PURE__ */ jsx17(WarningTriangle, { className: "mt-0.5 h-4 w-4 shrink-0 text-ph-danger" }),
2727
- /* @__PURE__ */ jsxs15("div", { className: "min-w-0 flex-1", children: [
2728
- /* @__PURE__ */ jsx17("p", { className: "font-medium text-ph-danger", children: "Something went wrong" }),
2729
- /* @__PURE__ */ jsx17("p", { className: "mt-0.5 text-ph-subtle", children: error }),
2730
- /* @__PURE__ */ jsx17(
2731
- "button",
2732
- {
2733
- type: "button",
2734
- onClick: retry,
2735
- disabled: loading,
2736
- className: "mt-2 inline-flex min-h-8 items-center gap-1.5 rounded-lg border border-ph-border bg-ph-surface px-2.5 text-xs font-medium text-ph-ink transition-colors hover:bg-ph-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-focus disabled:opacity-40",
2737
- children: "Try again"
2738
- }
2739
- )
2740
- ] })
2741
- ]
2474
+ fallback: /* @__PURE__ */ jsx17("p", { className: "whitespace-pre-wrap break-words", children: message.content }),
2475
+ children: /* @__PURE__ */ jsx17(SuiteAiBlockNoteMessage, { markdown: message.content })
2742
2476
  }
2743
- ) : null
2477
+ ) })
2744
2478
  ]
2745
- }
2746
- ),
2747
- !atBottom ? /* @__PURE__ */ jsx17(
2748
- "button",
2749
- {
2750
- type: "button",
2751
- onClick: () => scrollToBottom("smooth"),
2752
- className: "absolute bottom-3 left-1/2 flex h-9 w-9 -translate-x-1/2 items-center justify-center rounded-full border border-ph-border bg-ph-surface text-ph-subtle shadow-ph-md transition-colors hover:text-ph-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-focus motion-safe:animate-[suite-ai-fade_150ms_ease-out]",
2753
- "aria-label": "Scroll to latest",
2754
- children: /* @__PURE__ */ jsx17(ArrowDown, { className: "h-4 w-4" })
2755
- }
2756
- ) : null
2757
- ] }),
2758
- /* @__PURE__ */ jsxs15("div", { className: "px-3 pb-[max(0.75rem,env(safe-area-inset-bottom))] pt-1", children: [
2759
- /* @__PURE__ */ jsxs15("div", { className: "flex items-end gap-2 rounded-3xl border border-ph-border bg-ph-surface px-2 py-1 shadow-sm transition-colors focus-within:border-ph-brand/45 focus-within:ring-2 focus-within:ring-ph-focus/35", children: [
2760
- /* @__PURE__ */ jsx17("label", { htmlFor: "suite-ask-ai-input", className: "sr-only", children: "Ask a question" }),
2761
- /* @__PURE__ */ jsx17(
2762
- "textarea",
2763
- {
2764
- id: "suite-ask-ai-input",
2765
- ref: textareaRef,
2766
- value: prompt,
2767
- onChange: (e) => setPrompt(e.target.value),
2768
- onKeyDown: (e) => {
2769
- if (e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing) {
2770
- e.preventDefault();
2771
- void ask(prompt);
2479
+ },
2480
+ `assistant-${index}`
2481
+ );
2482
+ }),
2483
+ loading ? /* @__PURE__ */ jsxs15("div", { className: "flex items-end gap-2", "aria-hidden": true, children: [
2484
+ /* @__PURE__ */ jsx17("span", { className: "mb-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-ph-brand/10 text-ph-brand", children: /* @__PURE__ */ jsx17(Icon, { className: "h-3.5 w-3.5" }) }),
2485
+ /* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-1.5 rounded-2xl rounded-bl-md bg-ph-muted px-3 py-2.5", children: [
2486
+ /* @__PURE__ */ jsx17("span", { className: "h-1.5 w-1.5 rounded-full bg-ph-mutedtext motion-safe:animate-bounce" }),
2487
+ /* @__PURE__ */ jsx17("span", { className: "h-1.5 w-1.5 rounded-full bg-ph-mutedtext motion-safe:animate-bounce [animation-delay:0.15s]" }),
2488
+ /* @__PURE__ */ jsx17("span", { className: "h-1.5 w-1.5 rounded-full bg-ph-mutedtext motion-safe:animate-bounce [animation-delay:0.3s]" })
2489
+ ] })
2490
+ ] }) : null,
2491
+ loading ? /* @__PURE__ */ jsx17("span", { className: "sr-only", "aria-live": "polite", children: "Assistant is responding\u2026" }) : null,
2492
+ error ? /* @__PURE__ */ jsxs15(
2493
+ "div",
2494
+ {
2495
+ role: "alert",
2496
+ className: "flex items-start gap-2 rounded-xl border border-ph-danger/30 bg-ph-danger/10 px-3 py-2.5 text-sm text-ph-ink",
2497
+ children: [
2498
+ /* @__PURE__ */ jsx17(WarningTriangle, { className: "mt-0.5 h-4 w-4 shrink-0 text-ph-danger" }),
2499
+ /* @__PURE__ */ jsxs15("div", { className: "min-w-0 flex-1", children: [
2500
+ /* @__PURE__ */ jsx17("p", { className: "font-medium text-ph-danger", children: "Something went wrong" }),
2501
+ /* @__PURE__ */ jsx17("p", { className: "mt-0.5 text-ph-subtle", children: error }),
2502
+ /* @__PURE__ */ jsx17(
2503
+ "button",
2504
+ {
2505
+ type: "button",
2506
+ onClick: retry,
2507
+ disabled: loading,
2508
+ className: "mt-2 inline-flex min-h-8 items-center gap-1.5 rounded-lg border border-ph-border bg-ph-surface px-2.5 text-xs font-medium text-ph-ink transition-colors hover:bg-ph-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-focus disabled:opacity-40",
2509
+ children: "Try again"
2772
2510
  }
2773
- },
2774
- placeholder: "Ask anything\u2026",
2775
- rows: 1,
2776
- "data-test": "ask-ai-input",
2777
- className: "max-h-44 min-h-[44px] flex-1 resize-none bg-transparent px-2 py-2.5 text-sm leading-relaxed text-ph-ink outline-none placeholder:text-ph-mutedtext"
2778
- }
2779
- ),
2780
- loading ? /* @__PURE__ */ jsx17(
2781
- "button",
2782
- {
2783
- type: "button",
2784
- onClick: stop,
2785
- "data-test": "ask-ai-stop",
2786
- className: "flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-ph-muted text-ph-ink transition-colors hover:bg-ph-border focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-focus",
2787
- "aria-label": "Stop generating",
2788
- children: /* @__PURE__ */ jsx17(Square, { className: "h-3.5 w-3.5 fill-current" })
2789
- }
2790
- ) : /* @__PURE__ */ jsx17(
2791
- "button",
2511
+ )
2512
+ ] })
2513
+ ]
2514
+ }
2515
+ ) : null
2516
+ ]
2517
+ }
2518
+ ),
2519
+ !atBottom ? /* @__PURE__ */ jsx17("div", { className: "absolute bottom-3 left-1/2 -translate-x-1/2", children: /* @__PURE__ */ jsx17(Tooltip, { content: "Scroll to latest", children: /* @__PURE__ */ jsx17(
2520
+ "button",
2521
+ {
2522
+ type: "button",
2523
+ onClick: () => scrollToBottom("smooth"),
2524
+ className: "flex h-9 w-9 items-center justify-center rounded-full border border-ph-border bg-ph-surface text-ph-subtle shadow-ph-md transition-colors hover:text-ph-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-focus",
2525
+ "aria-label": "Scroll to latest",
2526
+ children: /* @__PURE__ */ jsx17(ArrowDown, { className: "h-4 w-4" })
2527
+ }
2528
+ ) }) }) : null
2529
+ ] }),
2530
+ /* @__PURE__ */ jsx17("div", { className: "px-2 pt-2 pb-[max(2rem,calc(env(safe-area-inset-bottom)+1rem))]", children: /* @__PURE__ */ jsxs15("div", { className: "flex items-end gap-1.5 rounded-2xl border border-ph-border bg-ph-surface px-1.5 py-1 transition-colors focus-within:border-ph-brand/45 focus-within:ring-2 focus-within:ring-ph-focus/35", children: [
2531
+ /* @__PURE__ */ jsx17("label", { htmlFor: inputId, className: "sr-only", children: "Ask a question" }),
2532
+ /* @__PURE__ */ jsx17(
2533
+ "textarea",
2534
+ {
2535
+ id: inputId,
2536
+ ref: textareaRef,
2537
+ value: prompt,
2538
+ onChange: (event) => setPrompt(event.target.value),
2539
+ onKeyDown: (event) => {
2540
+ if (event.key === "Enter" && !event.shiftKey && !event.nativeEvent.isComposing) {
2541
+ event.preventDefault();
2542
+ void ask(prompt);
2543
+ }
2544
+ },
2545
+ placeholder: "Ask anything\u2026",
2546
+ rows: 1,
2547
+ "data-test": "ask-ai-input",
2548
+ className: "max-h-36 min-h-10 flex-1 resize-none bg-transparent px-1.5 py-2 text-sm leading-relaxed text-ph-ink outline-none placeholder:text-ph-mutedtext"
2549
+ }
2550
+ ),
2551
+ loading ? /* @__PURE__ */ jsx17(Tooltip, { content: "Stop generating", children: /* @__PURE__ */ jsx17(
2552
+ "button",
2553
+ {
2554
+ type: "button",
2555
+ onClick: stop,
2556
+ "data-test": "ask-ai-stop",
2557
+ className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-ph-muted text-ph-ink transition-colors hover:bg-ph-border focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-focus",
2558
+ "aria-label": "Stop generating",
2559
+ children: /* @__PURE__ */ jsx17(Square, { className: "h-3.5 w-3.5 fill-current" })
2560
+ }
2561
+ ) }) : /* @__PURE__ */ jsx17(Tooltip, { content: "Send message", children: /* @__PURE__ */ jsx17(
2562
+ "button",
2563
+ {
2564
+ type: "button",
2565
+ onClick: () => void ask(prompt),
2566
+ disabled: !prompt.trim(),
2567
+ "data-test": "ask-ai-send",
2568
+ className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-ph-brand text-[color:var(--ph-on-accent)] transition-opacity hover:bg-ph-brand-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-focus disabled:opacity-40",
2569
+ "aria-label": "Send message",
2570
+ children: /* @__PURE__ */ jsx17(ArrowUp, { className: "h-4 w-4" })
2571
+ }
2572
+ ) })
2573
+ ] }) })
2574
+ ]
2575
+ }
2576
+ );
2577
+ }
2578
+
2579
+ // src/suite/components/workspace-switcher.tsx
2580
+ import { useState as useState8 } from "react";
2581
+ import { Building, Check as Check2, NavArrowDown } from "iconoir-react";
2582
+ import { Fragment as Fragment5, jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
2583
+ function SuiteWorkspaceSwitcher({
2584
+ workspaces = [],
2585
+ groups,
2586
+ currentId,
2587
+ onSelect,
2588
+ name,
2589
+ collapsed = false,
2590
+ emptyLabel = "No workspaces yet.",
2591
+ dropdownMenu: DropdownMenu2,
2592
+ dropdownItem: DropdownItem2,
2593
+ triggerId,
2594
+ triggerDataTest,
2595
+ footer
2596
+ }) {
2597
+ var _a;
2598
+ const [open, setOpen] = useState8(false);
2599
+ 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 }] : [];
2600
+ return /* @__PURE__ */ jsx18(
2601
+ DropdownMenu2,
2602
+ {
2603
+ "aria-label": "Switch workspace",
2604
+ triggerId: triggerId != null ? triggerId : "workspace-switcher-trigger",
2605
+ triggerDataTest: triggerDataTest != null ? triggerDataTest : "workspace-switcher-trigger",
2606
+ className: collapsed ? "w-11 shrink-0" : "w-full min-w-0 max-w-full [&_.ph-dropdown-trigger]:w-full",
2607
+ panelClassName: "w-64 max-w-full",
2608
+ align: "start",
2609
+ open,
2610
+ onOpenChange: setOpen,
2611
+ trigger: /* @__PURE__ */ jsxs16(
2612
+ "span",
2613
+ {
2614
+ className: cn(
2615
+ "flex min-w-0 max-w-full items-center gap-2 rounded-lg border border-ph-border bg-ph-muted text-left transition-colors hover:bg-ph-muted",
2616
+ collapsed ? "h-10 w-10 justify-center p-0" : "w-full px-3 py-2",
2617
+ open && "border-ph-brand/40"
2618
+ ),
2619
+ "data-test": "workspace-switcher-trigger",
2620
+ "aria-expanded": open,
2621
+ children: [
2622
+ /* @__PURE__ */ jsx18(Building, { className: "h-4 w-4 shrink-0 text-ph-ink", "aria-hidden": true }),
2623
+ !collapsed ? /* @__PURE__ */ jsxs16(Fragment5, { children: [
2624
+ /* @__PURE__ */ jsx18("span", { className: "min-w-0 flex-1 truncate text-sm font-semibold text-ph-ink", children: name }),
2625
+ /* @__PURE__ */ jsx18(
2626
+ NavArrowDown,
2627
+ {
2628
+ className: cn(
2629
+ "h-3.5 w-3.5 shrink-0 text-ph-mutedtext transition-transform",
2630
+ open && "rotate-180"
2631
+ ),
2632
+ "aria-hidden": true
2633
+ }
2634
+ )
2635
+ ] }) : null
2636
+ ]
2637
+ }
2638
+ ),
2639
+ children: /* @__PURE__ */ jsxs16(
2640
+ "div",
2641
+ {
2642
+ id: "workspace-switcher-menu",
2643
+ className: "p-1",
2644
+ "data-test": "workspace-switcher-menu",
2645
+ children: [
2646
+ sections.length === 0 ? /* @__PURE__ */ jsx18("p", { className: "px-3 py-2 text-sm text-ph-mutedtext", children: emptyLabel }) : sections.map((section) => /* @__PURE__ */ jsxs16("div", { children: [
2647
+ /* @__PURE__ */ jsx18("p", { className: "px-3 py-2 text-[10px] font-semibold uppercase tracking-[0.14em] text-ph-mutedtext", children: section.label }),
2648
+ section.workspaces.map((workspace) => /* @__PURE__ */ jsx18(
2649
+ DropdownItem2,
2650
+ {
2651
+ id: `workspace-option-${workspace.id}`,
2652
+ role: "option",
2653
+ "aria-selected": workspace.id === currentId,
2654
+ "data-test": "workspace-option",
2655
+ "data-workspace-id": workspace.id,
2656
+ onMouseDown: (event) => event.preventDefault(),
2657
+ onClick: () => {
2658
+ setOpen(false);
2659
+ onSelect(workspace);
2660
+ },
2661
+ className: appSwitcherMenuItemClass(),
2662
+ children: /* @__PURE__ */ jsxs16("span", { className: "flex min-w-0 w-full items-center gap-3", children: [
2663
+ /* @__PURE__ */ jsxs16("span", { className: "min-w-0 flex-1", children: [
2664
+ /* @__PURE__ */ jsx18("span", { className: "block truncate text-sm font-medium text-ph-ink", children: workspace.name }),
2665
+ workspace.description ? /* @__PURE__ */ jsx18("span", { className: "block truncate text-xs text-ph-mutedtext", children: workspace.description }) : null
2666
+ ] }),
2667
+ workspace.id === currentId ? /* @__PURE__ */ jsx18(
2668
+ Check2,
2792
2669
  {
2793
- type: "button",
2794
- onClick: () => void ask(prompt),
2795
- disabled: !prompt.trim(),
2796
- "data-test": "ask-ai-send",
2797
- className: "flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-ph-brand text-[color:var(--ph-on-accent)] transition-opacity hover:bg-ph-brand-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-focus disabled:opacity-40",
2798
- "aria-label": "Send message",
2799
- children: /* @__PURE__ */ jsx17(ArrowUp, { className: "h-[18px] w-[18px]" })
2670
+ className: "h-4 w-4 shrink-0 text-ph-brand",
2671
+ "aria-hidden": "true"
2800
2672
  }
2801
- )
2802
- ] }),
2803
- /* @__PURE__ */ jsxs15("p", { className: "mt-1.5 px-1 text-center text-xs text-ph-mutedtext", children: [
2804
- /* @__PURE__ */ jsx17("kbd", { className: "font-mono", children: "Enter" }),
2805
- " to send \xB7",
2806
- " ",
2807
- /* @__PURE__ */ jsx17("kbd", { className: "font-mono", children: "Shift" }),
2808
- "+",
2809
- /* @__PURE__ */ jsx17("kbd", { className: "font-mono", children: "Enter" }),
2810
- " for a new line"
2673
+ ) : null
2811
2674
  ] })
2812
- ] })
2813
- ]
2814
- }
2815
- )
2816
- ]
2817
- }
2818
- ) : null
2819
- ] });
2675
+ },
2676
+ workspace.id
2677
+ ))
2678
+ ] }, section.id)),
2679
+ footer ? /* @__PURE__ */ jsx18("div", { className: "mt-1 border-t border-ph-border pt-1", children: footer }) : null
2680
+ ]
2681
+ }
2682
+ )
2683
+ }
2684
+ );
2820
2685
  }
2821
2686
 
2822
2687
  // src/suite/lib/use-sidebar-width.ts
2823
2688
  import {
2824
2689
  useCallback as useCallback3,
2825
2690
  useEffect as useEffect7,
2826
- useState as useState8
2691
+ useState as useState9
2827
2692
  } from "react";
2828
2693
  var SIDEBAR_RAIL_WIDTH = 56;
2829
2694
  var SIDEBAR_COLLAPSE_THRESHOLD = 80;
2830
2695
  var SIDEBAR_MIN_EXPANDED_WIDTH = 180;
2831
- var SIDEBAR_MAX_WIDTH = 320;
2696
+ var SIDEBAR_MAX_WIDTH = 640;
2832
2697
  var SIDEBAR_DEFAULT_WIDTH = 320;
2698
+ function sidebarColumnWidth(width, collapsed, _chatOpen = false) {
2699
+ if (collapsed) return SIDEBAR_RAIL_WIDTH;
2700
+ return width;
2701
+ }
2833
2702
  function clampWidth(width) {
2834
2703
  return Math.min(SIDEBAR_MAX_WIDTH, Math.max(SIDEBAR_RAIL_WIDTH, width));
2835
2704
  }
@@ -2840,8 +2709,8 @@ function snapWidth(width) {
2840
2709
  }
2841
2710
  function useSidebarWidth(storageKey, defaultWidth = SIDEBAR_DEFAULT_WIDTH) {
2842
2711
  const fallbackWidth = snapWidth(clampWidth(defaultWidth));
2843
- const [width, setWidth] = useState8(fallbackWidth);
2844
- const [narrowViewport, setNarrowViewport] = useState8(false);
2712
+ const [width, setWidth] = useState9(fallbackWidth);
2713
+ const [narrowViewport, setNarrowViewport] = useState9(false);
2845
2714
  const collapsed = narrowViewport || width <= SIDEBAR_COLLAPSE_THRESHOLD;
2846
2715
  useEffect7(() => {
2847
2716
  let stored = null;
@@ -2922,9 +2791,9 @@ function useSidebarWidth(storageKey, defaultWidth = SIDEBAR_DEFAULT_WIDTH) {
2922
2791
 
2923
2792
  // src/suite/lib/motion.tsx
2924
2793
  import { LazyMotion, domAnimation, m } from "motion/react";
2925
- import { jsx as jsx18 } from "react/jsx-runtime";
2794
+ import { jsx as jsx19 } from "react/jsx-runtime";
2926
2795
  function SuiteMotionProvider({ children }) {
2927
- return /* @__PURE__ */ jsx18(LazyMotion, { features: domAnimation, strict: true, children });
2796
+ return /* @__PURE__ */ jsx19(LazyMotion, { features: domAnimation, strict: true, children });
2928
2797
  }
2929
2798
  var SUITE_SPRINGS = {
2930
2799
  /** Snappy panel/sheet entrances — small overshoot. */
@@ -2936,24 +2805,24 @@ var SUITE_SPRINGS = {
2936
2805
  };
2937
2806
 
2938
2807
  // src/suite/components/suite-skeleton.tsx
2939
- import { jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
2808
+ import { jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
2940
2809
  function SuiteSkeleton({
2941
2810
  className,
2942
2811
  lines = 1,
2943
2812
  circle,
2944
2813
  width
2945
2814
  }) {
2946
- return /* @__PURE__ */ jsx19(
2815
+ return /* @__PURE__ */ jsx20(
2947
2816
  "div",
2948
2817
  {
2949
2818
  className: cn("space-y-2", circle ? "flex flex-col items-center" : ""),
2950
2819
  "aria-hidden": true,
2951
- children: Array.from({ length: lines }).map((_, index) => /* @__PURE__ */ jsx19(
2820
+ children: Array.from({ length: lines }).map((_, index) => /* @__PURE__ */ jsx20(
2952
2821
  "div",
2953
2822
  {
2954
2823
  className: "animate-[skeleton-stagger_0.6s_ease-out_both]",
2955
2824
  style: { animationDelay: `${index * 80}ms` },
2956
- children: /* @__PURE__ */ jsx19(
2825
+ children: /* @__PURE__ */ jsx20(
2957
2826
  "div",
2958
2827
  {
2959
2828
  className: cn(
@@ -2977,7 +2846,7 @@ function SuiteSkeletonCard({
2977
2846
  rows = 3,
2978
2847
  header = true
2979
2848
  }) {
2980
- return /* @__PURE__ */ jsxs16(
2849
+ return /* @__PURE__ */ jsxs17(
2981
2850
  "div",
2982
2851
  {
2983
2852
  className: cn(
@@ -2986,26 +2855,26 @@ function SuiteSkeletonCard({
2986
2855
  ),
2987
2856
  "aria-hidden": true,
2988
2857
  children: [
2989
- header ? /* @__PURE__ */ jsxs16(
2858
+ header ? /* @__PURE__ */ jsxs17(
2990
2859
  "div",
2991
2860
  {
2992
2861
  className: "mb-5 flex items-center gap-3 animate-[skeleton-stagger_0.5s_ease-out_both]",
2993
2862
  style: { animationDelay: "100ms" },
2994
2863
  children: [
2995
- /* @__PURE__ */ jsx19("div", { className: "ph-skeleton h-10 w-10 rounded-xl" }),
2996
- /* @__PURE__ */ jsxs16("div", { className: "flex-1 space-y-2", children: [
2997
- /* @__PURE__ */ jsx19("div", { className: "ph-skeleton h-4 w-1/3" }),
2998
- /* @__PURE__ */ jsx19("div", { className: "ph-skeleton h-3 w-1/2" })
2864
+ /* @__PURE__ */ jsx20("div", { className: "ph-skeleton h-10 w-10 rounded-xl" }),
2865
+ /* @__PURE__ */ jsxs17("div", { className: "flex-1 space-y-2", children: [
2866
+ /* @__PURE__ */ jsx20("div", { className: "ph-skeleton h-4 w-1/3" }),
2867
+ /* @__PURE__ */ jsx20("div", { className: "ph-skeleton h-3 w-1/2" })
2999
2868
  ] })
3000
2869
  ]
3001
2870
  }
3002
2871
  ) : null,
3003
- /* @__PURE__ */ jsx19("div", { className: "space-y-3", children: Array.from({ length: rows }).map((_, index) => /* @__PURE__ */ jsx19(
2872
+ /* @__PURE__ */ jsx20("div", { className: "space-y-3", children: Array.from({ length: rows }).map((_, index) => /* @__PURE__ */ jsx20(
3004
2873
  "div",
3005
2874
  {
3006
2875
  className: "animate-[skeleton-stagger_0.5s_ease-out_both]",
3007
2876
  style: { animationDelay: `${200 + index * 80}ms` },
3008
- children: /* @__PURE__ */ jsx19(
2877
+ children: /* @__PURE__ */ jsx20(
3009
2878
  "div",
3010
2879
  {
3011
2880
  className: "ph-skeleton h-3",
@@ -3023,16 +2892,16 @@ function SuiteSkeletonList({
3023
2892
  className,
3024
2893
  items = 4
3025
2894
  }) {
3026
- return /* @__PURE__ */ jsx19("div", { className: cn("space-y-3", className), "aria-hidden": true, children: Array.from({ length: items }).map((_, index) => /* @__PURE__ */ jsx19(
2895
+ return /* @__PURE__ */ jsx20("div", { className: cn("space-y-3", className), "aria-hidden": true, children: Array.from({ length: items }).map((_, index) => /* @__PURE__ */ jsx20(
3027
2896
  "div",
3028
2897
  {
3029
2898
  className: "animate-[skeleton-stagger_0.6s_ease-out_both]",
3030
2899
  style: { animationDelay: `${index * 100}ms` },
3031
- children: /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-3 rounded-xl border border-ph-border bg-ph-surface p-4", children: [
3032
- /* @__PURE__ */ jsx19("div", { className: "ph-skeleton h-10 w-10 rounded-lg" }),
3033
- /* @__PURE__ */ jsxs16("div", { className: "min-w-0 flex-1 space-y-2", children: [
3034
- /* @__PURE__ */ jsx19("div", { className: "ph-skeleton h-3.5 w-3/4" }),
3035
- /* @__PURE__ */ jsx19("div", { className: "ph-skeleton h-3 w-1/2" })
2900
+ children: /* @__PURE__ */ jsxs17("div", { className: "flex items-center gap-3 rounded-xl border border-ph-border bg-ph-surface p-4", children: [
2901
+ /* @__PURE__ */ jsx20("div", { className: "ph-skeleton h-10 w-10 rounded-lg" }),
2902
+ /* @__PURE__ */ jsxs17("div", { className: "min-w-0 flex-1 space-y-2", children: [
2903
+ /* @__PURE__ */ jsx20("div", { className: "ph-skeleton h-3.5 w-3/4" }),
2904
+ /* @__PURE__ */ jsx20("div", { className: "ph-skeleton h-3 w-1/2" })
3036
2905
  ] })
3037
2906
  ] })
3038
2907
  },
@@ -3047,7 +2916,7 @@ function SuiteEmptyState({
3047
2916
  className,
3048
2917
  size = "md"
3049
2918
  }) {
3050
- return /* @__PURE__ */ jsxs16(
2919
+ return /* @__PURE__ */ jsxs17(
3051
2920
  "div",
3052
2921
  {
3053
2922
  className: cn(
@@ -3056,13 +2925,13 @@ function SuiteEmptyState({
3056
2925
  className
3057
2926
  ),
3058
2927
  children: [
3059
- /* @__PURE__ */ jsxs16("div", { className: "pointer-events-none absolute inset-0 overflow-hidden opacity-60", "aria-hidden": true, children: [
3060
- /* @__PURE__ */ jsx19("div", { className: "absolute -left-10 -top-10 h-40 w-40 rounded-full bg-ph-brand/10 blur-3xl" }),
3061
- /* @__PURE__ */ jsx19("div", { className: "absolute -bottom-10 -right-10 h-40 w-40 rounded-full bg-ph-accent/10 blur-3xl" })
2928
+ /* @__PURE__ */ jsxs17("div", { className: "pointer-events-none absolute inset-0 overflow-hidden opacity-60", "aria-hidden": true, children: [
2929
+ /* @__PURE__ */ jsx20("div", { className: "absolute -left-10 -top-10 h-40 w-40 rounded-full bg-ph-brand/10 blur-3xl" }),
2930
+ /* @__PURE__ */ jsx20("div", { className: "absolute -bottom-10 -right-10 h-40 w-40 rounded-full bg-ph-accent/10 blur-3xl" })
3062
2931
  ] }),
3063
- /* @__PURE__ */ jsxs16("div", { className: "relative", children: [
3064
- icon ? /* @__PURE__ */ jsx19("div", { className: "mx-auto mb-4 inline-flex items-center justify-center rounded-2xl bg-ph-muted p-3 shadow-sm ring-1 ring-black/[0.06]", children: icon }) : null,
3065
- /* @__PURE__ */ jsx19(
2932
+ /* @__PURE__ */ jsxs17("div", { className: "relative", children: [
2933
+ icon ? /* @__PURE__ */ jsx20("div", { className: "mx-auto mb-4 inline-flex items-center justify-center rounded-2xl bg-ph-muted p-3 shadow-sm ring-1 ring-black/[0.06]", children: icon }) : null,
2934
+ /* @__PURE__ */ jsx20(
3066
2935
  "h3",
3067
2936
  {
3068
2937
  className: cn(
@@ -3072,8 +2941,8 @@ function SuiteEmptyState({
3072
2941
  children: title
3073
2942
  }
3074
2943
  ),
3075
- description ? /* @__PURE__ */ jsx19("p", { className: "mx-auto mt-2 max-w-sm text-sm leading-relaxed text-ph-subtle", children: description }) : null,
3076
- action ? /* @__PURE__ */ jsx19("div", { className: "mt-5 flex flex-wrap items-center justify-center gap-2", children: action }) : null
2944
+ description ? /* @__PURE__ */ jsx20("p", { className: "mx-auto mt-2 max-w-sm text-sm leading-relaxed text-ph-subtle", children: description }) : null,
2945
+ action ? /* @__PURE__ */ jsx20("div", { className: "mt-5 flex flex-wrap items-center justify-center gap-2", children: action }) : null
3077
2946
  ] })
3078
2947
  ]
3079
2948
  }
@@ -3082,7 +2951,7 @@ function SuiteEmptyState({
3082
2951
 
3083
2952
  // src/suite/components/suite-settings-mobile-nav.tsx
3084
2953
  import { isValidElement } from "react";
3085
- import { jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
2954
+ import { jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
3086
2955
  function SuiteSettingsMobileNav({
3087
2956
  items,
3088
2957
  activeHref,
@@ -3091,16 +2960,16 @@ function SuiteSettingsMobileNav({
3091
2960
  ariaLabel = "Settings sections",
3092
2961
  className
3093
2962
  }) {
3094
- return /* @__PURE__ */ jsx20(
2963
+ return /* @__PURE__ */ jsx21(
3095
2964
  "nav",
3096
2965
  {
3097
2966
  "data-test": dataTest,
3098
2967
  "aria-label": ariaLabel,
3099
2968
  className: cn("suite-settings-mobile-nav lg:hidden", className),
3100
- children: /* @__PURE__ */ jsx20("div", { className: "flex snap-x gap-2 overflow-x-auto pb-3 pt-1 scrollbar-hide [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", children: items.map((item) => {
2969
+ children: /* @__PURE__ */ jsx21("div", { className: "flex snap-x gap-2 overflow-x-auto pb-3 pt-1 scrollbar-hide [-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", children: items.map((item) => {
3101
2970
  const Icon = item.icon;
3102
2971
  const active = activeHref === item.href || activeHref.startsWith(`${item.href}/`);
3103
- const iconNode = isValidElement(item.icon) ? item.icon : /* @__PURE__ */ jsx20(
2972
+ const iconNode = isValidElement(item.icon) ? item.icon : /* @__PURE__ */ jsx21(
3104
2973
  Icon,
3105
2974
  {
3106
2975
  className: cn(
@@ -3110,7 +2979,7 @@ function SuiteSettingsMobileNav({
3110
2979
  "aria-hidden": true
3111
2980
  }
3112
2981
  );
3113
- return /* @__PURE__ */ jsxs17(
2982
+ return /* @__PURE__ */ jsxs18(
3114
2983
  "button",
3115
2984
  {
3116
2985
  type: "button",
@@ -3125,8 +2994,8 @@ function SuiteSettingsMobileNav({
3125
2994
  ),
3126
2995
  children: [
3127
2996
  iconNode,
3128
- /* @__PURE__ */ jsx20("span", { className: "whitespace-nowrap", children: item.label }),
3129
- active ? /* @__PURE__ */ jsx20("span", { className: "absolute inset-x-0 -bottom-3 h-0.5 rounded-full bg-ph-ink lg:hidden" }) : null
2997
+ /* @__PURE__ */ jsx21("span", { className: "whitespace-nowrap", children: item.label }),
2998
+ active ? /* @__PURE__ */ jsx21("span", { className: "absolute inset-x-0 -bottom-3 h-0.5 rounded-full bg-ph-ink lg:hidden" }) : null
3130
2999
  ]
3131
3000
  },
3132
3001
  item.href
@@ -3138,7 +3007,9 @@ function SuiteSettingsMobileNav({
3138
3007
 
3139
3008
  // src/suite/components/suite-sidebar.tsx
3140
3009
  import Link2 from "next/link";
3141
- import { jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
3010
+ import { useEffect as useEffect8 } from "react";
3011
+ import { NavArrowLeft, Sparks as Sparks2 } from "iconoir-react";
3012
+ import { Fragment as Fragment6, jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
3142
3013
  function renderNode(node, collapsed) {
3143
3014
  if (typeof node === "function") return node(collapsed);
3144
3015
  return node;
@@ -3153,9 +3024,94 @@ function SuiteSidebar({
3153
3024
  footerExtras,
3154
3025
  collapsed = false,
3155
3026
  className,
3156
- surface = false
3027
+ surface = false,
3028
+ askAiOpen = false,
3029
+ onAskAiOpenChange,
3030
+ askAi,
3031
+ onRequestExpand
3157
3032
  }) {
3158
- return /* @__PURE__ */ jsxs18(
3033
+ const showAskAi = Boolean(onAskAiOpenChange && askAi);
3034
+ const chatOpen = showAskAi && askAiOpen && !collapsed;
3035
+ useEffect8(() => {
3036
+ if (!onAskAiOpenChange) return;
3037
+ function onOpen() {
3038
+ onRequestExpand == null ? void 0 : onRequestExpand();
3039
+ onAskAiOpenChange == null ? void 0 : onAskAiOpenChange(true);
3040
+ }
3041
+ window.addEventListener(SUITE_OPEN_ASK_AI_EVENT, onOpen);
3042
+ return () => window.removeEventListener(SUITE_OPEN_ASK_AI_EVENT, onOpen);
3043
+ }, [onAskAiOpenChange, onRequestExpand]);
3044
+ useEffect8(() => {
3045
+ if (!chatOpen) return;
3046
+ function onKey(event) {
3047
+ if (event.key === "Escape") onAskAiOpenChange == null ? void 0 : onAskAiOpenChange(false);
3048
+ }
3049
+ window.addEventListener("keydown", onKey);
3050
+ return () => window.removeEventListener("keydown", onKey);
3051
+ }, [chatOpen, onAskAiOpenChange]);
3052
+ function toggleAskAi() {
3053
+ if (askAiOpen) {
3054
+ onAskAiOpenChange == null ? void 0 : onAskAiOpenChange(false);
3055
+ return;
3056
+ }
3057
+ if (collapsed) onRequestExpand == null ? void 0 : onRequestExpand();
3058
+ onAskAiOpenChange == null ? void 0 : onAskAiOpenChange(true);
3059
+ }
3060
+ const askAiButton = /* @__PURE__ */ jsx22(
3061
+ "button",
3062
+ {
3063
+ type: "button",
3064
+ "data-test": "suite-ask-ai-toggle",
3065
+ "aria-pressed": askAiOpen,
3066
+ "aria-label": askAiOpen ? "Back to navigation" : "Shelly AI",
3067
+ onClick: toggleAskAi,
3068
+ className: cn(
3069
+ "inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-lg transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ph-focus-ring",
3070
+ askAiOpen ? "bg-ph-brand/10 text-ph-brand" : "text-ph-mutedtext hover:bg-ph-muted hover:text-ph-ink"
3071
+ ),
3072
+ children: /* @__PURE__ */ jsx22(Sparks2, { className: "h-4 w-4", "aria-hidden": true })
3073
+ }
3074
+ );
3075
+ if (chatOpen) {
3076
+ return /* @__PURE__ */ jsxs19(
3077
+ "div",
3078
+ {
3079
+ "data-suite-chat-open": "",
3080
+ className: cn(
3081
+ "flex h-full w-full min-w-0 flex-col text-ph-ink",
3082
+ surface ? "bg-ph-surface" : "bg-ph-canvas",
3083
+ className
3084
+ ),
3085
+ children: [
3086
+ /* @__PURE__ */ jsxs19(
3087
+ "div",
3088
+ {
3089
+ className: cn(
3090
+ "flex h-14 shrink-0 items-center gap-1 border-b border-ph-border px-2",
3091
+ surface ? "bg-ph-surface" : "bg-ph-canvas"
3092
+ ),
3093
+ children: [
3094
+ /* @__PURE__ */ jsx22(Tooltip, { content: "Back to navigation", children: /* @__PURE__ */ jsx22(
3095
+ "button",
3096
+ {
3097
+ type: "button",
3098
+ "data-test": "suite-ask-ai-back",
3099
+ "aria-label": "Back to navigation",
3100
+ onClick: () => onAskAiOpenChange == null ? void 0 : onAskAiOpenChange(false),
3101
+ className: "inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-lg text-ph-subtle transition-colors hover:bg-ph-muted hover:text-ph-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-brand",
3102
+ children: /* @__PURE__ */ jsx22(NavArrowLeft, { className: "h-4 w-4", "aria-hidden": true })
3103
+ }
3104
+ ) }),
3105
+ /* @__PURE__ */ jsx22("span", { className: "min-w-0 flex-1 truncate text-sm font-semibold text-ph-ink", children: "Shelly AI" })
3106
+ ]
3107
+ }
3108
+ ),
3109
+ /* @__PURE__ */ jsx22("div", { className: "min-h-0 flex-1", children: askAi })
3110
+ ]
3111
+ }
3112
+ );
3113
+ }
3114
+ return /* @__PURE__ */ jsxs19(
3159
3115
  "div",
3160
3116
  {
3161
3117
  className: cn(
@@ -3164,7 +3120,7 @@ function SuiteSidebar({
3164
3120
  className
3165
3121
  ),
3166
3122
  children: [
3167
- /* @__PURE__ */ jsxs18(
3123
+ appSwitcher || notificationBell ? /* @__PURE__ */ jsxs19(
3168
3124
  "div",
3169
3125
  {
3170
3126
  className: cn(
@@ -3173,27 +3129,46 @@ function SuiteSidebar({
3173
3129
  collapsed ? "flex-col items-center gap-1 px-1 py-2" : "h-14 items-center justify-between gap-2 px-3"
3174
3130
  ),
3175
3131
  children: [
3176
- /* @__PURE__ */ jsx21("div", { className: cn("min-w-0", collapsed ? "shrink-0" : "flex-1"), children: renderNode(appSwitcher, collapsed) }),
3177
- collapsed ? null : /* @__PURE__ */ jsx21("div", { className: "shrink-0", children: renderNode(notificationBell, collapsed) })
3132
+ /* @__PURE__ */ jsx22("div", { className: cn("min-w-0", collapsed ? "shrink-0" : "flex-1"), children: renderNode(appSwitcher, collapsed) }),
3133
+ collapsed ? null : /* @__PURE__ */ jsx22("div", { className: "shrink-0", children: renderNode(notificationBell, collapsed) })
3178
3134
  ]
3179
3135
  }
3180
- ),
3181
- /* @__PURE__ */ jsxs18(
3136
+ ) : null,
3137
+ /* @__PURE__ */ jsxs19(
3182
3138
  "div",
3183
3139
  {
3184
3140
  className: cn(
3185
- "flex min-h-0 flex-1 flex-col overflow-y-auto",
3141
+ "flex min-h-0 flex-1 flex-col",
3186
3142
  surface ? "bg-ph-surface" : "bg-ph-canvas",
3143
+ chatOpen ? "min-h-0" : "overflow-y-auto",
3187
3144
  collapsed ? "px-1.5 py-2" : "p-2"
3188
3145
  ),
3189
3146
  children: [
3190
- /* @__PURE__ */ jsxs18("nav", { "aria-label": "Pages", className: "shrink-0 space-y-0.5", children: [
3191
- /* @__PURE__ */ jsx21("div", { className: cn("mb-3", collapsed && "flex justify-center"), children: renderNode(contextSwitcher, collapsed) }),
3192
- /* @__PURE__ */ jsx21("div", { className: "space-y-0.5", children: navItems.map((item) => {
3147
+ /* @__PURE__ */ jsx22("div", { className: cn("mb-3 w-full shrink-0", collapsed && "flex justify-center"), children: renderNode(contextSwitcher, collapsed) }),
3148
+ chatOpen ? /* @__PURE__ */ jsxs19("div", { className: "flex min-h-0 flex-1 flex-col", children: [
3149
+ /* @__PURE__ */ jsxs19("div", { className: "mb-2 flex shrink-0 items-center gap-1", children: [
3150
+ /* @__PURE__ */ jsxs19(
3151
+ "button",
3152
+ {
3153
+ type: "button",
3154
+ "data-test": "suite-ask-ai-back",
3155
+ onClick: () => onAskAiOpenChange == null ? void 0 : onAskAiOpenChange(false),
3156
+ className: "inline-flex h-9 items-center gap-1 rounded-lg px-2 text-sm font-medium text-ph-subtle transition-colors hover:bg-ph-muted hover:text-ph-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-brand",
3157
+ children: [
3158
+ /* @__PURE__ */ jsx22(NavArrowLeft, { className: "h-4 w-4", "aria-hidden": true }),
3159
+ "Nav"
3160
+ ]
3161
+ }
3162
+ ),
3163
+ /* @__PURE__ */ jsx22("span", { className: "truncate text-sm font-semibold text-ph-ink", children: "Shelly AI" })
3164
+ ] }),
3165
+ /* @__PURE__ */ jsx22("div", { className: "min-h-0 flex-1", children: askAi })
3166
+ ] }) : /* @__PURE__ */ jsxs19(Fragment6, { children: [
3167
+ /* @__PURE__ */ jsx22("nav", { "aria-label": "Pages", className: "shrink-0 space-y-0.5", children: /* @__PURE__ */ jsx22("div", { className: "space-y-0.5", children: navItems.map((item) => {
3193
3168
  var _a;
3194
3169
  const Icon = item.icon;
3195
3170
  const active = Boolean(item.active);
3196
- const link = /* @__PURE__ */ jsxs18(
3171
+ const link = /* @__PURE__ */ jsxs19(
3197
3172
  Link2,
3198
3173
  {
3199
3174
  href: item.href,
@@ -3207,7 +3182,7 @@ function SuiteSidebar({
3207
3182
  collapsed ? "mx-auto size-11 shrink-0 justify-center gap-0 px-0 py-0" : "w-full px-2.5 py-2"
3208
3183
  ),
3209
3184
  children: [
3210
- /* @__PURE__ */ jsx21(
3185
+ /* @__PURE__ */ jsx22(
3211
3186
  "span",
3212
3187
  {
3213
3188
  className: cn(
@@ -3215,7 +3190,7 @@ function SuiteSidebar({
3215
3190
  item.iconClassName
3216
3191
  ),
3217
3192
  "aria-hidden": true,
3218
- children: /* @__PURE__ */ jsx21(
3193
+ children: /* @__PURE__ */ jsx22(
3219
3194
  Icon,
3220
3195
  {
3221
3196
  className: "h-full w-full",
@@ -3224,7 +3199,7 @@ function SuiteSidebar({
3224
3199
  )
3225
3200
  }
3226
3201
  ),
3227
- /* @__PURE__ */ jsx21(
3202
+ /* @__PURE__ */ jsx22(
3228
3203
  "span",
3229
3204
  {
3230
3205
  className: cn(
@@ -3235,26 +3210,26 @@ function SuiteSidebar({
3235
3210
  children: item.label
3236
3211
  }
3237
3212
  ),
3238
- !collapsed && item.badge ? /* @__PURE__ */ jsx21("span", { className: "relative ml-auto shrink-0", children: item.badge }) : null
3213
+ !collapsed && item.badge ? /* @__PURE__ */ jsx22("span", { className: "relative ml-auto shrink-0", children: item.badge }) : null
3239
3214
  ]
3240
3215
  },
3241
3216
  item.label
3242
3217
  );
3243
- return collapsed ? /* @__PURE__ */ jsx21(Tooltip, { content: item.label, side: "right", children: link }, item.label) : link;
3244
- }) })
3245
- ] }),
3246
- secondaryNav ? /* @__PURE__ */ jsx21(
3247
- "div",
3248
- {
3249
- className: "min-h-0 flex-1",
3250
- "data-test": "suite-sidebar-secondary-nav",
3251
- children: secondaryNav
3252
- }
3253
- ) : null
3218
+ return collapsed ? /* @__PURE__ */ jsx22(Tooltip, { content: item.label, side: "right", children: link }, item.label) : link;
3219
+ }) }) }),
3220
+ secondaryNav ? /* @__PURE__ */ jsx22(
3221
+ "div",
3222
+ {
3223
+ className: "min-h-0 flex-1",
3224
+ "data-test": "suite-sidebar-secondary-nav",
3225
+ children: secondaryNav
3226
+ }
3227
+ ) : null
3228
+ ] })
3254
3229
  ]
3255
3230
  }
3256
3231
  ),
3257
- /* @__PURE__ */ jsx21(
3232
+ /* @__PURE__ */ jsx22(
3258
3233
  "div",
3259
3234
  {
3260
3235
  className: cn(
@@ -3262,16 +3237,23 @@ function SuiteSidebar({
3262
3237
  surface ? "bg-ph-surface" : "bg-ph-canvas",
3263
3238
  collapsed ? "p-1.5" : "p-3"
3264
3239
  ),
3265
- children: /* @__PURE__ */ jsxs18(
3240
+ children: /* @__PURE__ */ jsxs19(
3266
3241
  "div",
3267
3242
  {
3268
3243
  className: cn(
3269
3244
  "flex items-center gap-2",
3270
- collapsed ? "flex-col items-center justify-center [&_[data-test$='-visible-sign-out']]:hidden [&>div]:w-auto" : "w-full min-w-0"
3245
+ collapsed ? "flex-col items-center justify-center [&>div]:w-auto" : "w-full min-w-0"
3271
3246
  ),
3272
3247
  children: [
3273
3248
  renderNode(userMenu, collapsed),
3274
- footerExtras ? /* @__PURE__ */ jsx21("div", { className: cn("shrink-0", collapsed ? "mt-2" : "ml-auto"), children: renderNode(footerExtras, collapsed) }) : null
3249
+ showAskAi ? /* @__PURE__ */ jsx22(
3250
+ "div",
3251
+ {
3252
+ className: cn("shrink-0", collapsed ? "mt-2" : "ml-auto"),
3253
+ children: /* @__PURE__ */ jsx22(Tooltip, { content: "Shelly AI", side: collapsed ? "right" : "top", children: askAiButton })
3254
+ }
3255
+ ) : footerExtras ? /* @__PURE__ */ jsx22("div", { className: cn("shrink-0", collapsed ? "mt-2" : "ml-auto"), children: renderNode(footerExtras, collapsed) }) : null,
3256
+ showAskAi && footerExtras ? /* @__PURE__ */ jsx22("div", { className: cn("shrink-0", collapsed && "mt-2"), children: renderNode(footerExtras, collapsed) }) : null
3275
3257
  ]
3276
3258
  }
3277
3259
  )
@@ -3283,7 +3265,7 @@ function SuiteSidebar({
3283
3265
  }
3284
3266
 
3285
3267
  // src/suite/components/suite-app-layout.tsx
3286
- import { jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
3268
+ import { jsx as jsx23, jsxs as jsxs20 } from "react/jsx-runtime";
3287
3269
  function SuiteAppLayout({
3288
3270
  sidebar,
3289
3271
  children,
@@ -3297,7 +3279,7 @@ function SuiteAppLayout({
3297
3279
  onResetWidth,
3298
3280
  className
3299
3281
  }) {
3300
- return /* @__PURE__ */ jsxs19(
3282
+ return /* @__PURE__ */ jsxs20(
3301
3283
  "div",
3302
3284
  {
3303
3285
  "data-test": "app-shell",
@@ -3306,15 +3288,15 @@ function SuiteAppLayout({
3306
3288
  className
3307
3289
  ),
3308
3290
  children: [
3309
- /* @__PURE__ */ jsxs19(
3291
+ /* @__PURE__ */ jsxs20(
3310
3292
  "aside",
3311
3293
  {
3312
3294
  className: "relative hidden shrink-0 flex-col overflow-visible border-r border-ph-border ease-out lg:flex",
3313
3295
  style: { width: `${sidebarWidth}px` },
3314
3296
  "data-collapsed": collapsed ? "true" : "false",
3315
3297
  children: [
3316
- sidebar,
3317
- onStartResize ? /* @__PURE__ */ jsx22(
3298
+ /* @__PURE__ */ jsx23("div", { className: "relative z-0 h-full min-h-0 isolate", children: sidebar }),
3299
+ onStartResize ? /* @__PURE__ */ jsx23(
3318
3300
  "div",
3319
3301
  {
3320
3302
  role: "separator",
@@ -3336,15 +3318,15 @@ function SuiteAppLayout({
3336
3318
  onResizeBy == null ? void 0 : onResizeBy(16);
3337
3319
  }
3338
3320
  },
3339
- className: "absolute inset-y-0 -right-1 z-10 w-2 cursor-col-resize touch-none transition-colors hover:bg-[color-mix(in_oklab,var(--ph-accent)_30%,transparent)]"
3321
+ className: "absolute inset-y-0 right-0 z-20 w-2 cursor-col-resize touch-none transition-colors hover:bg-[color-mix(in_oklab,var(--ph-accent)_30%,transparent)]"
3340
3322
  }
3341
3323
  ) : null
3342
3324
  ]
3343
3325
  }
3344
3326
  ),
3345
- /* @__PURE__ */ jsxs19("div", { className: "flex min-h-0 min-w-0 flex-1 flex-col", children: [
3346
- mobileHeader ? /* @__PURE__ */ jsx22("div", { className: "shrink-0 lg:hidden", children: mobileHeader }) : null,
3347
- /* @__PURE__ */ jsx22(
3327
+ /* @__PURE__ */ jsxs20("div", { className: "flex min-h-0 min-w-0 flex-1 flex-col", children: [
3328
+ mobileHeader ? /* @__PURE__ */ jsx23("div", { className: "shrink-0 lg:hidden", children: mobileHeader }) : null,
3329
+ /* @__PURE__ */ jsx23(
3348
3330
  "main",
3349
3331
  {
3350
3332
  id: "main-content",
@@ -3358,7 +3340,7 @@ function SuiteAppLayout({
3358
3340
  children
3359
3341
  }
3360
3342
  ),
3361
- bottomNav ? /* @__PURE__ */ jsx22("div", { className: "shrink-0 lg:hidden", children: bottomNav }) : null
3343
+ bottomNav ? /* @__PURE__ */ jsx23("div", { className: "shrink-0 lg:hidden", children: bottomNav }) : null
3362
3344
  ] })
3363
3345
  ]
3364
3346
  }
@@ -3411,6 +3393,7 @@ export {
3411
3393
  SuiteThemeProvider,
3412
3394
  SuiteToolbar,
3413
3395
  SuiteUserMenu,
3396
+ SuiteWorkspaceSwitcher,
3414
3397
  TodayAskAiCard,
3415
3398
  TodayCalibrating,
3416
3399
  TodayEmptyAction,
@@ -3426,11 +3409,14 @@ export {
3426
3409
  appSwitcherMarkClass,
3427
3410
  appSwitcherMenuItemClass,
3428
3411
  appSwitcherTriggerClass,
3412
+ classifySuiteHref,
3429
3413
  cn,
3414
+ consumePendingAskAiPrompt,
3430
3415
  getTodayGreeting,
3431
3416
  m,
3432
3417
  openSuiteAskAi,
3433
3418
  resolveSuiteNotificationHref,
3419
+ sidebarColumnWidth,
3434
3420
  sourceToSuiteApp,
3435
3421
  suiteAppBaseUrl,
3436
3422
  suiteAppLabel,