@xenide-io/the-old-ui-theme 0.6.2 → 0.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/suite.js CHANGED
@@ -306,12 +306,12 @@ function TodayPageFrame({ children }) {
306
306
  "div",
307
307
  {
308
308
  "data-test": "today-page",
309
- className: "today-page-frame relative flex min-h-0 w-full flex-1 flex-col overflow-x-hidden",
309
+ className: "today-page-frame relative flex min-h-0 w-full flex-1 flex-col overflow-x-clip",
310
310
  children: [
311
311
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
312
312
  "div",
313
313
  {
314
- className: "pointer-events-none absolute inset-0 overflow-hidden",
314
+ className: "today-page-frame__backdrop pointer-events-none overflow-hidden",
315
315
  "aria-hidden": true,
316
316
  children: [
317
317
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "today-page-frame__glow absolute inset-0" }),
@@ -1908,7 +1908,7 @@ function SuitePage({
1908
1908
  role,
1909
1909
  "aria-live": ariaLive,
1910
1910
  className: cn(
1911
- "suite-page-stage flex w-full min-w-0 flex-col",
1911
+ "suite-page-stage relative flex w-full min-w-0 flex-col",
1912
1912
  inset && "suite-page-inset",
1913
1913
  className
1914
1914
  ),
@@ -1933,20 +1933,28 @@ function SuitePageHeader({
1933
1933
  badge,
1934
1934
  /** Breadcrumb line rendered above the title. */
1935
1935
  breadcrumb,
1936
- /** Stick to the top of the scrollport (desktop page titles). */
1937
- sticky = false
1936
+ /**
1937
+ * Keep the title parked at the top of the scrollport while the page scrolls.
1938
+ * On by default — opt out only for pages that are not the page's own title.
1939
+ */
1940
+ sticky = true
1938
1941
  }) {
1939
1942
  const headerRef = (0, import_react6.useRef)(null);
1940
1943
  const [stuck, setStuck] = (0, import_react6.useState)(false);
1941
1944
  (0, import_react6.useEffect)(() => {
1942
- var _a;
1943
1945
  if (!sticky) return;
1946
+ if (typeof IntersectionObserver === "undefined") return;
1944
1947
  const el = headerRef.current;
1945
1948
  if (!el) return;
1949
+ const parent = el.parentElement;
1950
+ if (!parent) return;
1946
1951
  const sentinel = document.createElement("div");
1947
1952
  sentinel.setAttribute("aria-hidden", "true");
1948
- sentinel.style.cssText = "position:relative;height:1px;width:100%;margin:0;padding:0;pointer-events:none";
1949
- (_a = el.parentElement) == null ? void 0 : _a.insertBefore(sentinel, el);
1953
+ sentinel.style.cssText = "position:absolute;top:0;left:0;height:1px;width:1px;margin:0;padding:0;pointer-events:none";
1954
+ if (getComputedStyle(parent).position === "static") {
1955
+ parent.style.position = "relative";
1956
+ }
1957
+ parent.insertBefore(sentinel, el);
1950
1958
  const observer = new IntersectionObserver(
1951
1959
  ([entry]) => {
1952
1960
  setStuck(!entry.isIntersecting);
@@ -1963,7 +1971,7 @@ function SuitePageHeader({
1963
1971
  TodayTimeIcon,
1964
1972
  {
1965
1973
  className: cn(
1966
- "h-7 w-7 text-amber-500 sm:h-8 sm:w-8",
1974
+ "h-6 w-6 text-amber-500",
1967
1975
  todayIconClassName
1968
1976
  )
1969
1977
  }
@@ -1975,9 +1983,8 @@ function SuitePageHeader({
1975
1983
  "data-test": dataTest,
1976
1984
  "data-stuck": sticky ? stuck ? "true" : "false" : void 0,
1977
1985
  className: cn(
1978
- "flex min-w-0 flex-col items-start gap-3 pb-2 sm:flex-row sm:justify-between sm:gap-4 sm:pb-3",
1986
+ "flex min-w-0 shrink-0 flex-col items-start gap-3 pb-2 sm:flex-row sm:justify-between sm:gap-4 sm:pb-3",
1979
1987
  // No extra pt here — page inset sets the shared title baseline.
1980
- // Stuck state adds pad via .suite-page-header-sticky[data-stuck].
1981
1988
  sticky && "suite-page-header-sticky",
1982
1989
  className
1983
1990
  ),
@@ -1989,7 +1996,7 @@ function SuitePageHeader({
1989
1996
  resolvedIcon ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1990
1997
  "div",
1991
1998
  {
1992
- className: "hidden shrink-0 sm:flex sm:items-center [&_svg]:h-7 [&_svg]:w-7 sm:[&_svg]:h-8 sm:[&_svg]:w-8",
1999
+ className: "hidden shrink-0 sm:flex sm:items-center [&_svg]:h-6 [&_svg]:w-6",
1993
2000
  "aria-hidden": "true",
1994
2001
  children: resolvedIcon
1995
2002
  }
@@ -1999,7 +2006,7 @@ function SuitePageHeader({
1999
2006
  "h1",
2000
2007
  {
2001
2008
  className: cn(
2002
- "min-w-0 break-words font-display text-[1.625rem] font-bold leading-none tracking-tight text-ph-ink text-balance sm:text-[2.25rem]",
2009
+ "min-w-0 break-words font-display text-[1.375rem] font-semibold leading-tight tracking-tight text-ph-ink text-balance sm:text-2xl",
2003
2010
  titleClassName
2004
2011
  ),
2005
2012
  children: title
@@ -2013,7 +2020,7 @@ function SuitePageHeader({
2013
2020
  {
2014
2021
  className: cn(
2015
2022
  "mt-1.5 max-w-2xl text-pretty text-sm leading-5 text-ph-subtle",
2016
- resolvedIcon && "sm:pl-11"
2023
+ resolvedIcon && "sm:pl-9"
2017
2024
  ),
2018
2025
  children: description
2019
2026
  }
@@ -2296,6 +2303,20 @@ function computeInitials(name, email) {
2296
2303
  const source = (name || email || "?").trim();
2297
2304
  return source.split(/[\s@]+/).filter(Boolean).slice(0, 2).map((part) => part[0]).join("").toUpperCase();
2298
2305
  }
2306
+ var AVATAR_TOKENS = [
2307
+ "bg-ph-brand",
2308
+ "bg-ph-violet",
2309
+ "bg-ph-info",
2310
+ "bg-ph-success",
2311
+ "bg-ph-danger"
2312
+ ];
2313
+ function avatarColorClass(seed) {
2314
+ let hash = 0;
2315
+ for (let i = 0; i < seed.length; i += 1) {
2316
+ hash = seed.charCodeAt(i) + ((hash << 5) - hash);
2317
+ }
2318
+ return AVATAR_TOKENS[Math.abs(hash) % AVATAR_TOKENS.length];
2319
+ }
2299
2320
  function SuiteUserMenu({
2300
2321
  name,
2301
2322
  email,
@@ -2311,17 +2332,27 @@ function SuiteUserMenu({
2311
2332
  }) {
2312
2333
  const router = (0, import_navigation2.useRouter)();
2313
2334
  const initials = fallbackInitials != null ? fallbackInitials : computeInitials(name, email);
2314
- const avatar = /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "inline-flex h-11 w-11 items-center justify-center rounded-full ring-2 ring-ph-border ring-offset-1 ring-offset-ph-canvas transition-colors hover:bg-ph-muted", children: image ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2335
+ const fallbackColor = avatarColorClass(email || name || "?");
2336
+ const avatar = /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "inline-flex h-10 w-10 items-center justify-center overflow-hidden rounded-full border border-ph-border", children: image ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2315
2337
  import_image2.default,
2316
2338
  {
2317
2339
  src: image,
2318
2340
  alt: "",
2319
2341
  width: 40,
2320
2342
  height: 40,
2321
- className: "h-10 w-10 rounded-full object-cover",
2343
+ className: "h-full w-full object-cover",
2322
2344
  unoptimized: true
2323
2345
  }
2324
- ) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "flex h-10 w-10 items-center justify-center rounded-full bg-ph-muted text-sm font-semibold text-ph-brand", children: initials }) });
2346
+ ) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2347
+ "span",
2348
+ {
2349
+ className: cn(
2350
+ "flex h-full w-full items-center justify-center text-sm font-semibold text-white",
2351
+ fallbackColor
2352
+ ),
2353
+ children: initials
2354
+ }
2355
+ ) });
2325
2356
  const accountMenu = /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2326
2357
  DropdownMenu,
2327
2358
  {
@@ -2334,7 +2365,10 @@ function SuiteUserMenu({
2334
2365
  sideOffset: 6,
2335
2366
  collisionPadding: 16,
2336
2367
  modal: false,
2337
- className: showSignOutAction ? void 0 : className,
2368
+ className: cn(
2369
+ "[&_.ph-dropdown-trigger]:rounded-full",
2370
+ showSignOutAction ? void 0 : className
2371
+ ),
2338
2372
  "data-test": dataTest,
2339
2373
  children: [
2340
2374
  /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "px-2 py-1.5", children: [
@@ -2363,21 +2397,30 @@ function SuiteUserMenu({
2363
2397
  if (!showSignOutAction) {
2364
2398
  return accountMenu;
2365
2399
  }
2366
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: cn("flex min-w-0 items-center gap-2", className), children: [
2367
- accountMenu,
2368
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2369
- "button",
2370
- {
2371
- type: "button",
2372
- "data-test": `${dataTest}-visible-sign-out`,
2373
- title: "Sign out",
2374
- "aria-label": "Sign out",
2375
- className: "inline-flex h-11 w-11 shrink-0 items-center justify-center rounded-lg text-ph-mutedtext transition-colors hover:bg-ph-muted hover:text-ph-ink focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ph-focus-ring",
2376
- onClick: onSignOut,
2377
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_iconoir_react6.LogOut, { className: "h-4 w-4", "aria-hidden": true })
2378
- }
2379
- )
2380
- ] });
2400
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2401
+ "div",
2402
+ {
2403
+ className: cn(
2404
+ "flex w-full min-w-0 flex-1 items-center justify-between gap-2",
2405
+ className
2406
+ ),
2407
+ children: [
2408
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "shrink-0", children: accountMenu }),
2409
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2410
+ "button",
2411
+ {
2412
+ type: "button",
2413
+ "data-test": `${dataTest}-visible-sign-out`,
2414
+ title: "Sign out",
2415
+ "aria-label": "Sign out",
2416
+ className: "inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-lg text-ph-mutedtext transition-colors hover:bg-ph-muted hover:text-ph-ink focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ph-focus-ring",
2417
+ onClick: onSignOut,
2418
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_iconoir_react6.LogOut, { className: "h-4 w-4", "aria-hidden": true })
2419
+ }
2420
+ )
2421
+ ]
2422
+ }
2423
+ );
2381
2424
  }
2382
2425
 
2383
2426
  // src/suite/components/suite-bottom-nav.tsx
@@ -2592,11 +2635,14 @@ function SuiteAiPanel({
2592
2635
  const [hydrating, setHydrating] = (0, import_react10.useState)(false);
2593
2636
  const [error, setError] = (0, import_react10.useState)("");
2594
2637
  const [copiedId, setCopiedId] = (0, import_react10.useState)(null);
2638
+ const [atBottom, setAtBottom] = (0, import_react10.useState)(true);
2595
2639
  const [launcherSide, setLauncherSide] = (0, import_react10.useState)("right");
2596
2640
  const [panelSide, setPanelSide] = (0, import_react10.useState)("right");
2597
2641
  const [launcherPosition, setLauncherPosition] = (0, import_react10.useState)(null);
2598
2642
  const [draggingLauncher, setDraggingLauncher] = (0, import_react10.useState)(false);
2599
2643
  const scrollerRef = (0, import_react10.useRef)(null);
2644
+ const textareaRef = (0, import_react10.useRef)(null);
2645
+ const abortRef = (0, import_react10.useRef)(null);
2600
2646
  const launcherRef = (0, import_react10.useRef)(null);
2601
2647
  const launcherSideRef = (0, import_react10.useRef)("right");
2602
2648
  const launcherPositionRef = (0, import_react10.useRef)(null);
@@ -2648,10 +2694,17 @@ function SuiteAiPanel({
2648
2694
  window.addEventListener("resize", placeLauncher);
2649
2695
  return () => window.removeEventListener("resize", placeLauncher);
2650
2696
  }, []);
2651
- const scrollToBottom = (0, import_react10.useCallback)(() => {
2697
+ const scrollToBottom = (0, import_react10.useCallback)((behavior = "auto") => {
2652
2698
  const el = scrollerRef.current;
2653
2699
  if (!el) return;
2654
- el.scrollTop = el.scrollHeight;
2700
+ el.scrollTo({ top: el.scrollHeight, behavior });
2701
+ setAtBottom(true);
2702
+ }, []);
2703
+ const handleScroll = (0, import_react10.useCallback)(() => {
2704
+ const el = scrollerRef.current;
2705
+ if (!el) return;
2706
+ const distance = el.scrollHeight - el.scrollTop - el.clientHeight;
2707
+ setAtBottom(distance < 64);
2655
2708
  }, []);
2656
2709
  const hydrate = (0, import_react10.useCallback)(async () => {
2657
2710
  var _a;
@@ -2695,20 +2748,46 @@ function SuiteAiPanel({
2695
2748
  });
2696
2749
  }, [open, hydrate]);
2697
2750
  (0, import_react10.useEffect)(() => {
2698
- if (open) scrollToBottom();
2699
- }, [messages, loading, open, scrollToBottom]);
2751
+ if (open && atBottom) scrollToBottom();
2752
+ }, [messages, loading, open, atBottom, scrollToBottom]);
2753
+ (0, import_react10.useEffect)(() => {
2754
+ var _a;
2755
+ if (open && !hydrating) (_a = textareaRef.current) == null ? void 0 : _a.focus();
2756
+ }, [open, hydrating]);
2757
+ (0, import_react10.useEffect)(() => {
2758
+ if (!open) return;
2759
+ function onKey(event) {
2760
+ if (event.key === "Escape") setOpen(false);
2761
+ }
2762
+ window.addEventListener("keydown", onKey);
2763
+ return () => window.removeEventListener("keydown", onKey);
2764
+ }, [open]);
2765
+ (0, import_react10.useLayoutEffect)(() => {
2766
+ const el = textareaRef.current;
2767
+ if (!el) return;
2768
+ el.style.height = "auto";
2769
+ el.style.height = `${Math.min(el.scrollHeight, 176)}px`;
2770
+ }, [prompt, open]);
2700
2771
  async function ask(text) {
2701
2772
  var _a;
2702
2773
  const trimmed = text.trim();
2703
2774
  if (!trimmed || loading) return;
2775
+ const controller = new AbortController();
2776
+ abortRef.current = controller;
2704
2777
  setLoading(true);
2705
2778
  setError("");
2706
2779
  setPrompt("");
2780
+ setAtBottom(true);
2707
2781
  setMessages((prev) => [...prev, { role: "user", content: trimmed }]);
2708
2782
  try {
2709
- const result = await sendMessage({ prompt: trimmed });
2783
+ const result = await sendMessage({
2784
+ prompt: trimmed,
2785
+ signal: controller.signal
2786
+ });
2787
+ if (controller.signal.aborted) return;
2710
2788
  setMessages((_a = result.messages) != null ? _a : []);
2711
2789
  } catch (err) {
2790
+ if (controller.signal.aborted) return;
2712
2791
  setMessages(
2713
2792
  (prev) => {
2714
2793
  var _a2, _b;
@@ -2720,9 +2799,23 @@ function SuiteAiPanel({
2720
2799
  err instanceof Error ? err.message : "The AI request failed. Try again."
2721
2800
  );
2722
2801
  } finally {
2802
+ if (abortRef.current === controller) abortRef.current = null;
2723
2803
  setLoading(false);
2724
2804
  }
2725
2805
  }
2806
+ function stop() {
2807
+ var _a;
2808
+ (_a = abortRef.current) == null ? void 0 : _a.abort();
2809
+ abortRef.current = null;
2810
+ setLoading(false);
2811
+ }
2812
+ function retry() {
2813
+ var _a;
2814
+ const lastUser = (_a = [...messages].reverse().find((m2) => m2.role === "user")) == null ? void 0 : _a.content;
2815
+ setError("");
2816
+ if (lastUser) void ask(lastUser);
2817
+ else void hydrate();
2818
+ }
2726
2819
  async function handleClear() {
2727
2820
  if (loading) return;
2728
2821
  try {
@@ -2884,154 +2977,258 @@ function SuiteAiPanel({
2884
2977
  ),
2885
2978
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("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." })
2886
2979
  ] }) : null,
2887
- open ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "fixed inset-0 z-40", role: "dialog", "aria-modal": "true", children: [
2888
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2889
- "button",
2890
- {
2891
- type: "button",
2892
- className: "absolute inset-0 bg-black/25",
2893
- onClick: () => setOpen(false),
2894
- "aria-label": "Close Ask AI"
2895
- }
2896
- ),
2897
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
2898
- "aside",
2899
- {
2900
- className: `absolute inset-y-0 flex w-full max-w-md flex-col bg-ph-surface shadow-2xl ${panelSide === "left" ? "left-0 border-r border-ph-border" : "right-0 border-l border-ph-border"}`,
2901
- "data-test": "suite-ask-ai-panel",
2902
- children: [
2903
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center justify-between border-b border-ph-border px-4 py-3", children: [
2904
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "min-w-0", children: [
2905
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-2", children: [
2906
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Icon, { className: "h-4 w-4 shrink-0 text-ph-brand" }),
2907
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-sm font-semibold text-ph-ink", children: title })
2980
+ open ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
2981
+ "div",
2982
+ {
2983
+ className: "fixed inset-0 z-40",
2984
+ role: "dialog",
2985
+ "aria-modal": "true",
2986
+ "aria-label": title,
2987
+ children: [
2988
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2989
+ "button",
2990
+ {
2991
+ type: "button",
2992
+ className: "absolute inset-0 bg-ph-ink/25",
2993
+ onClick: () => setOpen(false),
2994
+ "aria-label": "Close Ask AI",
2995
+ tabIndex: -1
2996
+ }
2997
+ ),
2998
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
2999
+ "aside",
3000
+ {
3001
+ 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"}`,
3002
+ "data-test": "suite-ask-ai-panel",
3003
+ children: [
3004
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("header", { className: "flex items-center gap-2 px-4 py-3", children: [
3005
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h2", { className: "min-w-0 flex-1 truncate text-sm font-semibold text-ph-ink", children: title }),
3006
+ messages.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
3007
+ "button",
3008
+ {
3009
+ type: "button",
3010
+ onClick: () => void handleClear(),
3011
+ disabled: loading,
3012
+ 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",
3013
+ "data-test": "ask-ai-clear",
3014
+ children: [
3015
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_iconoir_react8.Erase, { className: "h-3.5 w-3.5" }),
3016
+ "Clear"
3017
+ ]
3018
+ }
3019
+ ) : null,
3020
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3021
+ "button",
3022
+ {
3023
+ type: "button",
3024
+ onClick: () => setOpen(false),
3025
+ 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",
3026
+ "aria-label": "Close Ask AI",
3027
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_iconoir_react8.Xmark, { className: "h-4 w-4" })
3028
+ }
3029
+ )
2908
3030
  ] }),
2909
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "mt-0.5 text-[11px] text-ph-mutedtext", children: "Shared across your suite \xB7 same chat in every app" })
2910
- ] }),
2911
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-1", children: [
2912
- messages.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2913
- "button",
2914
- {
2915
- type: "button",
2916
- onClick: () => void handleClear(),
2917
- disabled: loading,
2918
- className: "rounded-md px-2 py-1 text-xs text-ph-mutedtext hover:bg-ph-muted hover:text-ph-ink disabled:opacity-50",
2919
- "data-test": "ask-ai-clear",
2920
- children: "Clear"
2921
- }
2922
- ) : null,
2923
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2924
- "button",
2925
- {
2926
- type: "button",
2927
- onClick: () => setOpen(false),
2928
- className: "rounded p-1 hover:bg-ph-muted",
2929
- "aria-label": "Close",
2930
- children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_iconoir_react8.Xmark, { className: "h-4 w-4" })
2931
- }
2932
- )
2933
- ] })
2934
- ] }),
2935
- presets.length > 0 && messages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex flex-wrap gap-1.5 border-b border-ph-border px-4 py-2", children: presets.map((preset) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2936
- "button",
2937
- {
2938
- type: "button",
2939
- onClick: () => void ask(preset.prompt),
2940
- disabled: loading || hydrating,
2941
- className: "rounded-full border border-ph-border px-2.5 py-1 text-xs text-ph-ink hover:bg-ph-muted disabled:opacity-50",
2942
- children: preset.label
2943
- },
2944
- preset.label
2945
- )) }) : null,
2946
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
2947
- "div",
2948
- {
2949
- ref: scrollerRef,
2950
- className: "flex-1 space-y-3 overflow-y-auto p-4",
2951
- children: [
2952
- error ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "bg-ph-danger/10 rounded-lg px-3 py-2 text-sm text-ph-danger", children: error }) : null,
2953
- hydrating && messages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-2 text-sm text-ph-mutedtext", children: [
2954
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Spinner, { className: "h-4 w-4 animate-spin" }),
2955
- "Loading chat\u2026"
2956
- ] }) : null,
2957
- !hydrating && messages.length === 0 && !error ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "mt-10 px-2 text-center", children: [
2958
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "font-display text-base font-semibold text-ph-ink", children: "How can I help?" }),
2959
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "mt-2 text-sm leading-relaxed text-ph-subtle", children: emptyState })
2960
- ] }) : null,
2961
- messages.map((message, index) => {
2962
- const isUser = message.role === "user";
2963
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
2964
- "div",
2965
- {
2966
- className: isUser ? "ml-8 rounded-2xl bg-ph-brand/10 px-3.5 py-2.5 text-sm text-ph-ink" : "mr-4 rounded-2xl bg-ph-muted px-3.5 py-2.5 text-sm text-ph-ink",
2967
- "data-test": isUser ? "ask-ai-user" : "ask-ai-assistant",
2968
- children: [
2969
- isUser ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "whitespace-pre-wrap", children: message.content }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2970
- import_react10.Suspense,
2971
- {
2972
- fallback: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "whitespace-pre-wrap", children: message.content }),
2973
- children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(SuiteAiBlockNoteMessage2, { markdown: message.content })
2974
- }
2975
- ),
2976
- !isUser ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
3031
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "relative min-h-0 flex-1", children: [
3032
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
3033
+ "div",
3034
+ {
3035
+ ref: scrollerRef,
3036
+ onScroll: handleScroll,
3037
+ role: "log",
3038
+ "aria-live": "polite",
3039
+ "aria-label": "Conversation",
3040
+ className: "suite-scroll-lock h-full space-y-5 overflow-y-auto px-4 py-5",
3041
+ children: [
3042
+ hydrating && messages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-2 text-sm text-ph-subtle", children: [
3043
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Spinner, { className: "h-4 w-4 animate-spin" }),
3044
+ "Loading your chat\u2026"
3045
+ ] }) : null,
3046
+ !hydrating && messages.length === 0 && !error ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "mx-auto mt-6 flex max-w-sm flex-col items-center px-2 text-center", children: [
3047
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "flex h-12 w-12 items-center justify-center rounded-2xl bg-ph-brand/10 text-ph-brand", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Icon, { className: "h-6 w-6" }) }),
3048
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "mt-4 font-display text-lg font-semibold text-ph-ink", children: "How can I help?" }),
3049
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "mt-1.5 text-sm leading-relaxed text-ph-subtle", children: emptyState }),
3050
+ presets.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "mt-5 flex w-full flex-col gap-2", children: presets.map((preset) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
2977
3051
  "button",
2978
3052
  {
2979
3053
  type: "button",
2980
- onClick: () => void copyMessage(index, message.content),
2981
- className: "mt-2 inline-flex items-center gap-1 text-xs text-ph-mutedtext hover:text-ph-ink",
3054
+ onClick: () => void ask(preset.prompt),
3055
+ disabled: loading || hydrating,
3056
+ 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",
2982
3057
  children: [
2983
- copiedId === index ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_iconoir_react8.Check, { className: "h-3 w-3" }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_iconoir_react8.Copy, { className: "h-3 w-3" }),
2984
- copiedId === index ? "Copied" : "Copy"
3058
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_iconoir_react8.Sparks, { className: "h-4 w-4 shrink-0 text-ph-brand" }),
3059
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "min-w-0 flex-1 truncate", children: preset.label }),
3060
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_iconoir_react8.ArrowUp, { className: "h-3.5 w-3.5 shrink-0 rotate-45 text-ph-mutedtext transition-transform group-hover:translate-x-0.5" })
2985
3061
  ]
2986
- }
2987
- ) : null
2988
- ]
2989
- },
2990
- `${message.role}-${index}-${message.content.slice(0, 24)}`
2991
- );
2992
- }),
2993
- loading ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-2 text-sm text-ph-mutedtext", children: [
2994
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Spinner, { className: "h-4 w-4 animate-spin" }),
2995
- "Thinking\u2026"
2996
- ] }) : null
2997
- ]
2998
- }
2999
- ),
3000
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "border-t border-ph-border p-3", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex gap-2", children: [
3001
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3002
- "textarea",
3003
- {
3004
- value: prompt,
3005
- onChange: (e) => setPrompt(e.target.value),
3006
- onKeyDown: (e) => {
3007
- if (e.key === "Enter" && !e.shiftKey) {
3008
- e.preventDefault();
3009
- void ask(prompt);
3062
+ },
3063
+ preset.label
3064
+ )) }) : null
3065
+ ] }) : null,
3066
+ messages.map((message, index) => {
3067
+ const isUser = message.role === "user";
3068
+ if (isUser) {
3069
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3070
+ "div",
3071
+ {
3072
+ className: "flex justify-end",
3073
+ "data-test": "ask-ai-user",
3074
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("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 })
3075
+ },
3076
+ `user-${index}`
3077
+ );
3078
+ }
3079
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
3080
+ "div",
3081
+ {
3082
+ className: "flex gap-3",
3083
+ "data-test": "ask-ai-assistant",
3084
+ children: [
3085
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3086
+ "span",
3087
+ {
3088
+ className: "mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-ph-brand/10 text-ph-brand",
3089
+ "aria-hidden": true,
3090
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Icon, { className: "h-4 w-4" })
3091
+ }
3092
+ ),
3093
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "min-w-0 flex-1", children: [
3094
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "text-sm leading-relaxed text-ph-ink", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3095
+ import_react10.Suspense,
3096
+ {
3097
+ fallback: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "whitespace-pre-wrap break-words", children: message.content }),
3098
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3099
+ SuiteAiBlockNoteMessage2,
3100
+ {
3101
+ markdown: message.content
3102
+ }
3103
+ )
3104
+ }
3105
+ ) }),
3106
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
3107
+ "button",
3108
+ {
3109
+ type: "button",
3110
+ onClick: () => void copyMessage(index, message.content),
3111
+ 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",
3112
+ children: [
3113
+ copiedId === index ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_iconoir_react8.Check, { className: "h-3 w-3" }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_iconoir_react8.Copy, { className: "h-3 w-3" }),
3114
+ copiedId === index ? "Copied" : "Copy"
3115
+ ]
3116
+ }
3117
+ )
3118
+ ] })
3119
+ ]
3120
+ },
3121
+ `assistant-${index}`
3122
+ );
3123
+ }),
3124
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex gap-3", "aria-hidden": true, children: [
3125
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("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__ */ (0, import_jsx_runtime20.jsx)(Icon, { className: "h-4 w-4" }) }),
3126
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-1.5 py-1.5", children: [
3127
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "h-1.5 w-1.5 rounded-full bg-ph-mutedtext motion-safe:animate-bounce" }),
3128
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "h-1.5 w-1.5 rounded-full bg-ph-mutedtext motion-safe:animate-bounce [animation-delay:0.15s]" }),
3129
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "h-1.5 w-1.5 rounded-full bg-ph-mutedtext motion-safe:animate-bounce [animation-delay:0.3s]" })
3130
+ ] })
3131
+ ] }) : null,
3132
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "sr-only", "aria-live": "polite", children: "Assistant is responding\u2026" }) : null,
3133
+ error ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
3134
+ "div",
3135
+ {
3136
+ role: "alert",
3137
+ 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",
3138
+ children: [
3139
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_iconoir_react8.WarningTriangle, { className: "mt-0.5 h-4 w-4 shrink-0 text-ph-danger" }),
3140
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "min-w-0 flex-1", children: [
3141
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "font-medium text-ph-danger", children: "Something went wrong" }),
3142
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "mt-0.5 text-ph-subtle", children: error }),
3143
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3144
+ "button",
3145
+ {
3146
+ type: "button",
3147
+ onClick: retry,
3148
+ disabled: loading,
3149
+ 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",
3150
+ children: "Try again"
3151
+ }
3152
+ )
3153
+ ] })
3154
+ ]
3155
+ }
3156
+ ) : null
3157
+ ]
3010
3158
  }
3011
- },
3012
- placeholder: "Ask anything\u2026",
3013
- rows: 2,
3014
- disabled: loading,
3015
- "data-test": "ask-ai-input",
3016
- className: "flex-1 resize-none rounded-xl border border-ph-border bg-ph-canvas p-2.5 text-sm text-ph-ink outline-none focus:ring-1 focus:ring-ph-brand"
3017
- }
3018
- ),
3019
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3020
- "button",
3021
- {
3022
- type: "button",
3023
- onClick: () => void ask(prompt),
3024
- disabled: loading || !prompt.trim(),
3025
- "data-test": "ask-ai-send",
3026
- className: "self-end rounded-xl bg-ph-brand px-3.5 py-2 text-sm font-medium text-white disabled:opacity-50",
3027
- children: "Ask"
3028
- }
3029
- )
3030
- ] }) })
3031
- ]
3032
- }
3033
- )
3034
- ] }) : null
3159
+ ),
3160
+ !atBottom ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3161
+ "button",
3162
+ {
3163
+ type: "button",
3164
+ onClick: () => scrollToBottom("smooth"),
3165
+ 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]",
3166
+ "aria-label": "Scroll to latest",
3167
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_iconoir_react8.ArrowDown, { className: "h-4 w-4" })
3168
+ }
3169
+ ) : null
3170
+ ] }),
3171
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "px-3 pb-[max(0.75rem,env(safe-area-inset-bottom))] pt-1", children: [
3172
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("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: [
3173
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("label", { htmlFor: "suite-ask-ai-input", className: "sr-only", children: "Ask a question" }),
3174
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3175
+ "textarea",
3176
+ {
3177
+ id: "suite-ask-ai-input",
3178
+ ref: textareaRef,
3179
+ value: prompt,
3180
+ onChange: (e) => setPrompt(e.target.value),
3181
+ onKeyDown: (e) => {
3182
+ if (e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing) {
3183
+ e.preventDefault();
3184
+ void ask(prompt);
3185
+ }
3186
+ },
3187
+ placeholder: "Ask anything\u2026",
3188
+ rows: 1,
3189
+ "data-test": "ask-ai-input",
3190
+ 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"
3191
+ }
3192
+ ),
3193
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3194
+ "button",
3195
+ {
3196
+ type: "button",
3197
+ onClick: stop,
3198
+ "data-test": "ask-ai-stop",
3199
+ 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",
3200
+ "aria-label": "Stop generating",
3201
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_iconoir_react8.Square, { className: "h-3.5 w-3.5 fill-current" })
3202
+ }
3203
+ ) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3204
+ "button",
3205
+ {
3206
+ type: "button",
3207
+ onClick: () => void ask(prompt),
3208
+ disabled: !prompt.trim(),
3209
+ "data-test": "ask-ai-send",
3210
+ 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",
3211
+ "aria-label": "Send message",
3212
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_iconoir_react8.ArrowUp, { className: "h-[18px] w-[18px]" })
3213
+ }
3214
+ )
3215
+ ] }),
3216
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("p", { className: "mt-1.5 px-1 text-center text-xs text-ph-mutedtext", children: [
3217
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("kbd", { className: "font-mono", children: "Enter" }),
3218
+ " to send \xB7",
3219
+ " ",
3220
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("kbd", { className: "font-mono", children: "Shift" }),
3221
+ "+",
3222
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("kbd", { className: "font-mono", children: "Enter" }),
3223
+ " for a new line"
3224
+ ] })
3225
+ ] })
3226
+ ]
3227
+ }
3228
+ )
3229
+ ]
3230
+ }
3231
+ ) : null
3035
3232
  ] });
3036
3233
  }
3037
3234
 
@@ -3616,7 +3813,7 @@ function SuiteSidebar({
3616
3813
  {
3617
3814
  className: cn(
3618
3815
  "flex items-center gap-2",
3619
- collapsed ? "flex-col justify-center" : "min-w-0"
3816
+ collapsed ? "flex-col items-center justify-center [&_[data-test$='-visible-sign-out']]:hidden [&>div]:w-auto" : "w-full min-w-0"
3620
3817
  ),
3621
3818
  children: [
3622
3819
  renderNode(userMenu, collapsed),