@xenide-io/the-old-ui-theme 0.6.7 → 0.6.8
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/{chunk-3G43JEI3.mjs → chunk-VOCHIR3W.mjs} +2 -2
- package/dist/index.js +2 -2
- package/dist/index.mjs +1 -1
- package/dist/suite.d.mts +64 -15
- package/dist/suite.d.ts +64 -15
- package/dist/suite.js +750 -758
- package/dist/suite.mjs +571 -585
- package/dist/ui.js +2 -2
- package/dist/ui.mjs +1 -1
- package/package.json +1 -1
- package/src/styles/suite-skin.css +6 -0
- package/src/styles/themes.css +35 -33
- package/src/suite/components/ai-panel.test.ts +14 -40
- package/src/suite/components/ai-panel.tsx +305 -633
- package/src/suite/components/suite-app-layout.tsx +3 -2
- package/src/suite/components/suite-layout.test.tsx +36 -2
- package/src/suite/components/suite-sidebar.tsx +235 -102
- package/src/suite/components/today-ui.tsx +1 -1
- package/src/suite/components/workspace-switcher.tsx +162 -0
- package/src/suite/index.ts +9 -0
- package/src/suite/lib/apps.test.ts +40 -0
- package/src/suite/lib/apps.ts +37 -0
- package/src/suite/lib/use-sidebar-width.ts +11 -1
package/dist/suite.js
CHANGED
|
@@ -166,8 +166,8 @@ function SuiteAiBlockNoteMessage({
|
|
|
166
166
|
markdown
|
|
167
167
|
}) {
|
|
168
168
|
const { resolvedTheme } = useSuiteTheme();
|
|
169
|
-
const editor = (0,
|
|
170
|
-
(0,
|
|
169
|
+
const editor = (0, import_react10.useCreateBlockNote)({ schema: assistantSchema });
|
|
170
|
+
(0, import_react9.useEffect)(() => {
|
|
171
171
|
try {
|
|
172
172
|
const blocks = editor.tryParseMarkdownToBlocks(markdown);
|
|
173
173
|
editor.replaceBlocks(
|
|
@@ -180,8 +180,8 @@ function SuiteAiBlockNoteMessage({
|
|
|
180
180
|
]);
|
|
181
181
|
}
|
|
182
182
|
}, [editor, markdown]);
|
|
183
|
-
return /* @__PURE__ */ (0,
|
|
184
|
-
|
|
183
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
184
|
+
import_react10.BlockNoteViewRaw,
|
|
185
185
|
{
|
|
186
186
|
editor,
|
|
187
187
|
editable: false,
|
|
@@ -197,17 +197,17 @@ function SuiteAiBlockNoteMessage({
|
|
|
197
197
|
}
|
|
198
198
|
);
|
|
199
199
|
}
|
|
200
|
-
var
|
|
200
|
+
var import_react9, import_core, import_react10, import_style, import_jsx_runtime20, assistantSchema;
|
|
201
201
|
var init_ai_message_blocknote = __esm({
|
|
202
202
|
"src/suite/components/ai-message-blocknote.tsx"() {
|
|
203
203
|
"use strict";
|
|
204
204
|
"use client";
|
|
205
|
-
|
|
205
|
+
import_react9 = require("react");
|
|
206
206
|
import_core = require("@blocknote/core");
|
|
207
|
-
|
|
207
|
+
import_react10 = require("@blocknote/react");
|
|
208
208
|
import_style = require("@blocknote/react/style.css");
|
|
209
209
|
init_theme_provider();
|
|
210
|
-
|
|
210
|
+
import_jsx_runtime20 = require("react/jsx-runtime");
|
|
211
211
|
assistantSchema = import_core.BlockNoteSchema.create({
|
|
212
212
|
blockSpecs: {
|
|
213
213
|
paragraph: import_core.defaultBlockSpecs.paragraph,
|
|
@@ -273,6 +273,7 @@ __export(suite_exports, {
|
|
|
273
273
|
SuiteThemeProvider: () => SuiteThemeProvider,
|
|
274
274
|
SuiteToolbar: () => SuiteToolbar,
|
|
275
275
|
SuiteUserMenu: () => SuiteUserMenu,
|
|
276
|
+
SuiteWorkspaceSwitcher: () => SuiteWorkspaceSwitcher,
|
|
276
277
|
TodayAskAiCard: () => TodayAskAiCard,
|
|
277
278
|
TodayCalibrating: () => TodayCalibrating,
|
|
278
279
|
TodayEmptyAction: () => TodayEmptyAction,
|
|
@@ -288,11 +289,14 @@ __export(suite_exports, {
|
|
|
288
289
|
appSwitcherMarkClass: () => appSwitcherMarkClass,
|
|
289
290
|
appSwitcherMenuItemClass: () => appSwitcherMenuItemClass,
|
|
290
291
|
appSwitcherTriggerClass: () => appSwitcherTriggerClass,
|
|
292
|
+
classifySuiteHref: () => classifySuiteHref,
|
|
291
293
|
cn: () => cn,
|
|
294
|
+
consumePendingAskAiPrompt: () => consumePendingAskAiPrompt,
|
|
292
295
|
getTodayGreeting: () => getTodayGreeting,
|
|
293
|
-
m: () =>
|
|
296
|
+
m: () => import_react14.m,
|
|
294
297
|
openSuiteAskAi: () => openSuiteAskAi,
|
|
295
298
|
resolveSuiteNotificationHref: () => resolveSuiteNotificationHref,
|
|
299
|
+
sidebarColumnWidth: () => sidebarColumnWidth,
|
|
296
300
|
sourceToSuiteApp: () => sourceToSuiteApp,
|
|
297
301
|
suiteAppBaseUrl: () => suiteAppBaseUrl,
|
|
298
302
|
suiteAppLabel: () => suiteAppLabel,
|
|
@@ -1088,7 +1092,7 @@ function TodayLayout({
|
|
|
1088
1092
|
);
|
|
1089
1093
|
}
|
|
1090
1094
|
function TodayAskAiCard({
|
|
1091
|
-
title = "
|
|
1095
|
+
title = "Shelly AI",
|
|
1092
1096
|
description = "Ask about your workspace, draft something, or look a fact up online.",
|
|
1093
1097
|
cta = "Ask",
|
|
1094
1098
|
className,
|
|
@@ -1421,6 +1425,31 @@ function resolveSuiteNotificationHref(href, sourceApp) {
|
|
|
1421
1425
|
if (!slug) return path;
|
|
1422
1426
|
return `${suiteAppBaseUrl(slug)}${path}`;
|
|
1423
1427
|
}
|
|
1428
|
+
function classifySuiteHref(href, bases, currentOrigin = "") {
|
|
1429
|
+
let url;
|
|
1430
|
+
try {
|
|
1431
|
+
url = new URL(href, currentOrigin || "http://local.invalid");
|
|
1432
|
+
} catch (e) {
|
|
1433
|
+
return null;
|
|
1434
|
+
}
|
|
1435
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return null;
|
|
1436
|
+
for (const slug of Object.keys(bases)) {
|
|
1437
|
+
const base = bases[slug];
|
|
1438
|
+
if (!base) continue;
|
|
1439
|
+
try {
|
|
1440
|
+
if (new URL(base).origin !== url.origin) continue;
|
|
1441
|
+
} catch (e) {
|
|
1442
|
+
continue;
|
|
1443
|
+
}
|
|
1444
|
+
const path = `${url.pathname}${url.search}${url.hash}` || "/";
|
|
1445
|
+
return {
|
|
1446
|
+
slug,
|
|
1447
|
+
path,
|
|
1448
|
+
sameApp: Boolean(currentOrigin && url.origin === currentOrigin)
|
|
1449
|
+
};
|
|
1450
|
+
}
|
|
1451
|
+
return null;
|
|
1452
|
+
}
|
|
1424
1453
|
|
|
1425
1454
|
// src/suite/components/suite-notification-bell.tsx
|
|
1426
1455
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
@@ -2565,12 +2594,152 @@ function TodayCalibrating({
|
|
|
2565
2594
|
init_theme_provider();
|
|
2566
2595
|
|
|
2567
2596
|
// src/suite/components/ai-panel.tsx
|
|
2568
|
-
var
|
|
2597
|
+
var import_react11 = require("react");
|
|
2569
2598
|
var import_iconoir_react8 = require("iconoir-react");
|
|
2570
|
-
|
|
2571
|
-
|
|
2599
|
+
|
|
2600
|
+
// src/components/ui/Tooltip.tsx
|
|
2601
|
+
var import_react8 = require("react");
|
|
2602
|
+
var import_react_dom = require("react-dom");
|
|
2603
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
2604
|
+
var TooltipDelayContext = (0, import_react8.createContext)(0);
|
|
2605
|
+
function tooltipPosition(trigger, side, align, offset) {
|
|
2606
|
+
const horizontal = align === "start" ? trigger.left : align === "end" ? trigger.right : trigger.left + trigger.width / 2;
|
|
2607
|
+
const vertical = align === "start" ? trigger.top : align === "end" ? trigger.bottom : trigger.top + trigger.height / 2;
|
|
2608
|
+
if (side === "top")
|
|
2609
|
+
return {
|
|
2610
|
+
left: horizontal,
|
|
2611
|
+
top: trigger.top - offset,
|
|
2612
|
+
transform: "translate(-50%, -100%)"
|
|
2613
|
+
};
|
|
2614
|
+
if (side === "bottom")
|
|
2615
|
+
return {
|
|
2616
|
+
left: horizontal,
|
|
2617
|
+
top: trigger.bottom + offset,
|
|
2618
|
+
transform: "translate(-50%, 0)"
|
|
2619
|
+
};
|
|
2620
|
+
if (side === "left")
|
|
2621
|
+
return {
|
|
2622
|
+
left: trigger.left - offset,
|
|
2623
|
+
top: vertical,
|
|
2624
|
+
transform: "translate(-100%, -50%)"
|
|
2625
|
+
};
|
|
2626
|
+
return {
|
|
2627
|
+
left: trigger.right + offset,
|
|
2628
|
+
top: vertical,
|
|
2629
|
+
transform: "translate(0, -50%)"
|
|
2630
|
+
};
|
|
2631
|
+
}
|
|
2632
|
+
function Tooltip({
|
|
2633
|
+
content,
|
|
2634
|
+
children,
|
|
2635
|
+
side = "top",
|
|
2636
|
+
align = "center",
|
|
2637
|
+
sideOffset = 7,
|
|
2638
|
+
className,
|
|
2639
|
+
open,
|
|
2640
|
+
defaultOpen = false,
|
|
2641
|
+
onOpenChange,
|
|
2642
|
+
delayDuration
|
|
2643
|
+
}) {
|
|
2644
|
+
const providerDelay = (0, import_react8.useContext)(TooltipDelayContext);
|
|
2645
|
+
const generatedId = (0, import_react8.useId)().replace(/:/g, "");
|
|
2646
|
+
const triggerRef = (0, import_react8.useRef)(null);
|
|
2647
|
+
const timerRef = (0, import_react8.useRef)(null);
|
|
2648
|
+
const [internalOpen, setInternalOpen] = (0, import_react8.useState)(defaultOpen);
|
|
2649
|
+
const [position, setPosition] = (0, import_react8.useState)(null);
|
|
2650
|
+
const isOpen = open != null ? open : internalOpen;
|
|
2651
|
+
const triggerId = children.props.id;
|
|
2652
|
+
const tooltipId = triggerId ? `${triggerId}-tooltip` : `ph-tooltip-${generatedId}`;
|
|
2653
|
+
function setOpen(next) {
|
|
2654
|
+
if (open === void 0) setInternalOpen(next);
|
|
2655
|
+
onOpenChange == null ? void 0 : onOpenChange(next);
|
|
2656
|
+
}
|
|
2657
|
+
function clearTimer() {
|
|
2658
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2659
|
+
timerRef.current = null;
|
|
2660
|
+
}
|
|
2661
|
+
function updatePosition() {
|
|
2662
|
+
if (!triggerRef.current) return;
|
|
2663
|
+
setPosition(
|
|
2664
|
+
tooltipPosition(
|
|
2665
|
+
triggerRef.current.getBoundingClientRect(),
|
|
2666
|
+
side,
|
|
2667
|
+
align,
|
|
2668
|
+
sideOffset
|
|
2669
|
+
)
|
|
2670
|
+
);
|
|
2671
|
+
}
|
|
2672
|
+
function show(immediate) {
|
|
2673
|
+
clearTimer();
|
|
2674
|
+
updatePosition();
|
|
2675
|
+
const delay = immediate ? 0 : delayDuration != null ? delayDuration : providerDelay;
|
|
2676
|
+
if (!delay) setOpen(true);
|
|
2677
|
+
else timerRef.current = setTimeout(() => setOpen(true), delay);
|
|
2678
|
+
}
|
|
2679
|
+
function hide() {
|
|
2680
|
+
clearTimer();
|
|
2681
|
+
setOpen(false);
|
|
2682
|
+
}
|
|
2683
|
+
(0, import_react8.useEffect)(() => {
|
|
2684
|
+
if (!isOpen) return;
|
|
2685
|
+
const reposition = () => updatePosition();
|
|
2686
|
+
window.addEventListener("resize", reposition);
|
|
2687
|
+
window.addEventListener("scroll", reposition, true);
|
|
2688
|
+
return () => {
|
|
2689
|
+
window.removeEventListener("resize", reposition);
|
|
2690
|
+
window.removeEventListener("scroll", reposition, true);
|
|
2691
|
+
};
|
|
2692
|
+
});
|
|
2693
|
+
(0, import_react8.useEffect)(() => () => clearTimer(), []);
|
|
2694
|
+
const describedBy = [children.props["aria-describedby"], tooltipId].filter(Boolean).join(" ");
|
|
2695
|
+
const trigger = (0, import_react8.cloneElement)(children, { "aria-describedby": describedBy });
|
|
2696
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
|
|
2697
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2698
|
+
"span",
|
|
2699
|
+
{
|
|
2700
|
+
ref: triggerRef,
|
|
2701
|
+
className: "inline-flex",
|
|
2702
|
+
onMouseEnter: () => show(false),
|
|
2703
|
+
onMouseLeave: hide,
|
|
2704
|
+
onFocusCapture: () => show(true),
|
|
2705
|
+
onBlurCapture: hide,
|
|
2706
|
+
onKeyDown: (event) => {
|
|
2707
|
+
if (event.key === "Escape") hide();
|
|
2708
|
+
},
|
|
2709
|
+
children: trigger
|
|
2710
|
+
}
|
|
2711
|
+
),
|
|
2712
|
+
isOpen && position && typeof document !== "undefined" ? (0, import_react_dom.createPortal)(
|
|
2713
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2714
|
+
"span",
|
|
2715
|
+
{
|
|
2716
|
+
style: __spreadValues({ position: "fixed" }, position),
|
|
2717
|
+
className: "pointer-events-none z-[200]",
|
|
2718
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
2719
|
+
"span",
|
|
2720
|
+
{
|
|
2721
|
+
id: tooltipId,
|
|
2722
|
+
role: "tooltip",
|
|
2723
|
+
"data-side": side,
|
|
2724
|
+
className: cn2("ph-tooltip-content", className),
|
|
2725
|
+
children: content
|
|
2726
|
+
}
|
|
2727
|
+
)
|
|
2728
|
+
}
|
|
2729
|
+
),
|
|
2730
|
+
document.body
|
|
2731
|
+
) : null
|
|
2732
|
+
] });
|
|
2733
|
+
}
|
|
2734
|
+
|
|
2735
|
+
// src/suite/components/ai-panel.tsx
|
|
2736
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
2737
|
+
var SuiteAiBlockNoteMessage2 = (0, import_react11.lazy)(() => Promise.resolve().then(() => (init_ai_message_blocknote(), ai_message_blocknote_exports)));
|
|
2572
2738
|
var SUITE_OPEN_ASK_AI_EVENT = "shellstack:open-ask-ai";
|
|
2739
|
+
var pendingAskAiPrompt = null;
|
|
2573
2740
|
function openSuiteAskAi(detail) {
|
|
2741
|
+
var _a;
|
|
2742
|
+
pendingAskAiPrompt = ((_a = detail == null ? void 0 : detail.prompt) == null ? void 0 : _a.trim()) || null;
|
|
2574
2743
|
if (typeof window === "undefined") return;
|
|
2575
2744
|
window.dispatchEvent(
|
|
2576
2745
|
new CustomEvent(SUITE_OPEN_ASK_AI_EVENT, {
|
|
@@ -2578,138 +2747,72 @@ function openSuiteAskAi(detail) {
|
|
|
2578
2747
|
})
|
|
2579
2748
|
);
|
|
2580
2749
|
}
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
LAUNCHER_EDGE_GAP,
|
|
2586
|
-
viewportWidth - launcherWidth - LAUNCHER_EDGE_GAP
|
|
2587
|
-
);
|
|
2588
|
-
const maxY = Math.max(
|
|
2589
|
-
LAUNCHER_EDGE_GAP,
|
|
2590
|
-
viewportHeight - launcherHeight - LAUNCHER_EDGE_GAP
|
|
2591
|
-
);
|
|
2592
|
-
const clampX = (x) => Math.min(Math.max(x, LAUNCHER_EDGE_GAP), maxX);
|
|
2593
|
-
const clampY = (y) => Math.min(Math.max(y, LAUNCHER_EDGE_GAP), maxY);
|
|
2594
|
-
switch (edge) {
|
|
2595
|
-
case "left":
|
|
2596
|
-
return { x: LAUNCHER_EDGE_GAP, y: clampY(desiredY) };
|
|
2597
|
-
case "right":
|
|
2598
|
-
return { x: maxX, y: clampY(desiredY) };
|
|
2599
|
-
case "top":
|
|
2600
|
-
return { x: clampX(desiredX), y: LAUNCHER_EDGE_GAP };
|
|
2601
|
-
case "bottom":
|
|
2602
|
-
return { x: clampX(desiredX), y: maxY };
|
|
2603
|
-
}
|
|
2604
|
-
}
|
|
2605
|
-
function resolveSuiteAiNearestEdge(x, y, width, height, viewportWidth, viewportHeight) {
|
|
2606
|
-
const centerX = x + width / 2;
|
|
2607
|
-
const centerY = y + height / 2;
|
|
2608
|
-
const candidates = [
|
|
2609
|
-
{ edge: "left", distance: centerX },
|
|
2610
|
-
{ edge: "right", distance: viewportWidth - centerX },
|
|
2611
|
-
{ edge: "top", distance: centerY },
|
|
2612
|
-
{ edge: "bottom", distance: viewportHeight - centerY }
|
|
2613
|
-
];
|
|
2614
|
-
return candidates.reduce(
|
|
2615
|
-
(nearest, candidate) => candidate.distance < nearest.distance ? candidate : nearest
|
|
2616
|
-
).edge;
|
|
2617
|
-
}
|
|
2618
|
-
function resolveSuiteAiPanelSide(edge, x, viewportWidth) {
|
|
2619
|
-
if (edge === "left") return "left";
|
|
2620
|
-
if (edge === "right") return "right";
|
|
2621
|
-
return x < viewportWidth / 2 ? "left" : "right";
|
|
2750
|
+
function consumePendingAskAiPrompt() {
|
|
2751
|
+
const next = pendingAskAiPrompt;
|
|
2752
|
+
pendingAskAiPrompt = null;
|
|
2753
|
+
return next;
|
|
2622
2754
|
}
|
|
2623
2755
|
function SuiteAiPanel({
|
|
2624
2756
|
presets = [],
|
|
2625
2757
|
emptyState = "Ask anything about your workspace, or look something up online.",
|
|
2626
|
-
title = "
|
|
2758
|
+
title = "Shelly AI",
|
|
2627
2759
|
fetchChat,
|
|
2628
2760
|
sendMessage,
|
|
2629
2761
|
clearChat,
|
|
2630
2762
|
brandIcon: BrandIcon,
|
|
2631
2763
|
spinner: Spinner,
|
|
2632
|
-
|
|
2764
|
+
open: openProp,
|
|
2765
|
+
onOpenChange,
|
|
2766
|
+
suiteAppBases,
|
|
2767
|
+
onSwitchApp
|
|
2633
2768
|
}) {
|
|
2634
|
-
const
|
|
2635
|
-
const [
|
|
2636
|
-
const
|
|
2637
|
-
const
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
const [
|
|
2645
|
-
const [
|
|
2646
|
-
const
|
|
2647
|
-
const
|
|
2648
|
-
const
|
|
2649
|
-
const
|
|
2650
|
-
const
|
|
2651
|
-
const
|
|
2652
|
-
const
|
|
2653
|
-
const
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
);
|
|
2665
|
-
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")
|
|
2666
|
-
side = stored.side;
|
|
2667
|
-
if (typeof (stored == null ? void 0 : stored.x) === "number") desiredX = stored.x;
|
|
2668
|
-
if (typeof (stored == null ? void 0 : stored.y) === "number") desiredY = stored.y;
|
|
2669
|
-
} catch (e) {
|
|
2769
|
+
const inputId = (0, import_react11.useId)();
|
|
2770
|
+
const [uncontrolledOpen, setUncontrolledOpen] = (0, import_react11.useState)(false);
|
|
2771
|
+
const open = openProp != null ? openProp : uncontrolledOpen;
|
|
2772
|
+
const setOpen = (0, import_react11.useCallback)(
|
|
2773
|
+
(next) => {
|
|
2774
|
+
if (openProp === void 0) setUncontrolledOpen(next);
|
|
2775
|
+
onOpenChange == null ? void 0 : onOpenChange(next);
|
|
2776
|
+
},
|
|
2777
|
+
[onOpenChange, openProp]
|
|
2778
|
+
);
|
|
2779
|
+
const [prompt, setPrompt] = (0, import_react11.useState)("");
|
|
2780
|
+
const [messages, setMessages] = (0, import_react11.useState)([]);
|
|
2781
|
+
const [loading, setLoading] = (0, import_react11.useState)(false);
|
|
2782
|
+
const [hydrating, setHydrating] = (0, import_react11.useState)(false);
|
|
2783
|
+
const [error, setError] = (0, import_react11.useState)("");
|
|
2784
|
+
const [atBottom, setAtBottom] = (0, import_react11.useState)(true);
|
|
2785
|
+
const scrollerRef = (0, import_react11.useRef)(null);
|
|
2786
|
+
const textareaRef = (0, import_react11.useRef)(null);
|
|
2787
|
+
const abortRef = (0, import_react11.useRef)(null);
|
|
2788
|
+
const pendingPromptRef = (0, import_react11.useRef)(null);
|
|
2789
|
+
(0, import_react11.useEffect)(() => {
|
|
2790
|
+
function onOpen(event) {
|
|
2791
|
+
var _a;
|
|
2792
|
+
const detail = event.detail;
|
|
2793
|
+
const queued = ((_a = detail == null ? void 0 : detail.prompt) == null ? void 0 : _a.trim()) || consumePendingAskAiPrompt();
|
|
2794
|
+
setOpen(true);
|
|
2795
|
+
if (queued) {
|
|
2796
|
+
pendingPromptRef.current = queued;
|
|
2797
|
+
setPrompt(queued);
|
|
2798
|
+
}
|
|
2670
2799
|
}
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
const element = launcherRef.current;
|
|
2676
|
-
if (!element) return;
|
|
2677
|
-
const next = resolveSuiteAiLauncherPosition(
|
|
2678
|
-
launcherSideRef.current,
|
|
2679
|
-
(_b = (_a = launcherPositionRef.current) == null ? void 0 : _a.x) != null ? _b : desiredX,
|
|
2680
|
-
(_d = (_c = launcherPositionRef.current) == null ? void 0 : _c.y) != null ? _d : desiredY,
|
|
2681
|
-
window.innerWidth,
|
|
2682
|
-
window.innerHeight,
|
|
2683
|
-
element.offsetWidth,
|
|
2684
|
-
element.offsetHeight
|
|
2685
|
-
);
|
|
2686
|
-
launcherPositionRef.current = next;
|
|
2687
|
-
setLauncherPosition(next);
|
|
2688
|
-
setPanelSide(
|
|
2689
|
-
resolveSuiteAiPanelSide(
|
|
2690
|
-
launcherSideRef.current,
|
|
2691
|
-
next.x,
|
|
2692
|
-
window.innerWidth
|
|
2693
|
-
)
|
|
2694
|
-
);
|
|
2695
|
-
};
|
|
2696
|
-
placeLauncher();
|
|
2697
|
-
window.addEventListener("resize", placeLauncher);
|
|
2698
|
-
return () => window.removeEventListener("resize", placeLauncher);
|
|
2699
|
-
}, []);
|
|
2700
|
-
const scrollToBottom = (0, import_react10.useCallback)((behavior = "auto") => {
|
|
2800
|
+
window.addEventListener(SUITE_OPEN_ASK_AI_EVENT, onOpen);
|
|
2801
|
+
return () => window.removeEventListener(SUITE_OPEN_ASK_AI_EVENT, onOpen);
|
|
2802
|
+
}, [setOpen]);
|
|
2803
|
+
const scrollToBottom = (0, import_react11.useCallback)((behavior = "auto") => {
|
|
2701
2804
|
const el = scrollerRef.current;
|
|
2702
2805
|
if (!el) return;
|
|
2703
2806
|
el.scrollTo({ top: el.scrollHeight, behavior });
|
|
2704
2807
|
setAtBottom(true);
|
|
2705
2808
|
}, []);
|
|
2706
|
-
const handleScroll = (0,
|
|
2809
|
+
const handleScroll = (0, import_react11.useCallback)(() => {
|
|
2707
2810
|
const el = scrollerRef.current;
|
|
2708
2811
|
if (!el) return;
|
|
2709
2812
|
const distance = el.scrollHeight - el.scrollTop - el.clientHeight;
|
|
2710
2813
|
setAtBottom(distance < 64);
|
|
2711
2814
|
}, []);
|
|
2712
|
-
const hydrate = (0,
|
|
2815
|
+
const hydrate = (0, import_react11.useCallback)(async () => {
|
|
2713
2816
|
var _a;
|
|
2714
2817
|
setHydrating(true);
|
|
2715
2818
|
setError("");
|
|
@@ -2721,51 +2824,31 @@ function SuiteAiPanel({
|
|
|
2721
2824
|
}
|
|
2722
2825
|
} catch (err) {
|
|
2723
2826
|
setError(
|
|
2724
|
-
err instanceof Error ? err.message : "Could not load
|
|
2827
|
+
err instanceof Error ? err.message : "Could not load Shelly AI."
|
|
2725
2828
|
);
|
|
2726
2829
|
} finally {
|
|
2727
2830
|
setHydrating(false);
|
|
2728
2831
|
}
|
|
2729
2832
|
}, [fetchChat]);
|
|
2730
|
-
(0,
|
|
2731
|
-
|
|
2732
|
-
var _a;
|
|
2733
|
-
const detail = event.detail;
|
|
2734
|
-
setOpen(true);
|
|
2735
|
-
if ((_a = detail == null ? void 0 : detail.prompt) == null ? void 0 : _a.trim()) {
|
|
2736
|
-
pendingPromptRef.current = detail.prompt.trim();
|
|
2737
|
-
setPrompt(detail.prompt.trim());
|
|
2738
|
-
}
|
|
2739
|
-
}
|
|
2740
|
-
window.addEventListener(SUITE_OPEN_ASK_AI_EVENT, onOpen);
|
|
2741
|
-
return () => window.removeEventListener(SUITE_OPEN_ASK_AI_EVENT, onOpen);
|
|
2742
|
-
}, []);
|
|
2743
|
-
(0, import_react10.useEffect)(() => {
|
|
2833
|
+
(0, import_react11.useEffect)(() => {
|
|
2834
|
+
var _a;
|
|
2744
2835
|
if (!open) return;
|
|
2836
|
+
const queued = (_a = pendingPromptRef.current) != null ? _a : consumePendingAskAiPrompt();
|
|
2837
|
+
pendingPromptRef.current = queued;
|
|
2745
2838
|
void hydrate().then(() => {
|
|
2746
2839
|
const pending = pendingPromptRef.current;
|
|
2747
2840
|
pendingPromptRef.current = null;
|
|
2748
|
-
if (pending)
|
|
2749
|
-
setPrompt(pending);
|
|
2750
|
-
}
|
|
2841
|
+
if (pending) setPrompt(pending);
|
|
2751
2842
|
});
|
|
2752
2843
|
}, [open, hydrate]);
|
|
2753
|
-
(0,
|
|
2844
|
+
(0, import_react11.useEffect)(() => {
|
|
2754
2845
|
if (open && atBottom) scrollToBottom();
|
|
2755
2846
|
}, [messages, loading, open, atBottom, scrollToBottom]);
|
|
2756
|
-
(0,
|
|
2847
|
+
(0, import_react11.useEffect)(() => {
|
|
2757
2848
|
var _a;
|
|
2758
2849
|
if (open && !hydrating) (_a = textareaRef.current) == null ? void 0 : _a.focus();
|
|
2759
2850
|
}, [open, hydrating]);
|
|
2760
|
-
(0,
|
|
2761
|
-
if (!open) return;
|
|
2762
|
-
function onKey(event) {
|
|
2763
|
-
if (event.key === "Escape") setOpen(false);
|
|
2764
|
-
}
|
|
2765
|
-
window.addEventListener("keydown", onKey);
|
|
2766
|
-
return () => window.removeEventListener("keydown", onKey);
|
|
2767
|
-
}, [open]);
|
|
2768
|
-
(0, import_react10.useLayoutEffect)(() => {
|
|
2851
|
+
(0, import_react11.useLayoutEffect)(() => {
|
|
2769
2852
|
const el = textareaRef.current;
|
|
2770
2853
|
if (!el) return;
|
|
2771
2854
|
el.style.height = "auto";
|
|
@@ -2814,7 +2897,7 @@ function SuiteAiPanel({
|
|
|
2814
2897
|
}
|
|
2815
2898
|
function retry() {
|
|
2816
2899
|
var _a;
|
|
2817
|
-
const lastUser = (_a = [...messages].reverse().find((
|
|
2900
|
+
const lastUser = (_a = [...messages].reverse().find((message) => message.role === "user")) == null ? void 0 : _a.content;
|
|
2818
2901
|
setError("");
|
|
2819
2902
|
if (lastUser) void ask(lastUser);
|
|
2820
2903
|
else void hydrate();
|
|
@@ -2831,417 +2914,346 @@ function SuiteAiPanel({
|
|
|
2831
2914
|
);
|
|
2832
2915
|
}
|
|
2833
2916
|
}
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
} catch (e) {
|
|
2840
|
-
}
|
|
2841
|
-
}
|
|
2842
|
-
function saveLauncherPosition(edge, position) {
|
|
2843
|
-
try {
|
|
2844
|
-
localStorage.setItem(
|
|
2845
|
-
LAUNCHER_STORAGE_KEY,
|
|
2846
|
-
JSON.stringify({ side: edge, x: position.x, y: position.y })
|
|
2847
|
-
);
|
|
2848
|
-
} catch (e) {
|
|
2849
|
-
}
|
|
2850
|
-
}
|
|
2851
|
-
function dockLauncher(edge, desiredX, desiredY) {
|
|
2852
|
-
const launcher = launcherRef.current;
|
|
2853
|
-
if (!launcher) return;
|
|
2854
|
-
const next = resolveSuiteAiLauncherPosition(
|
|
2855
|
-
edge,
|
|
2856
|
-
desiredX,
|
|
2857
|
-
desiredY,
|
|
2858
|
-
window.innerWidth,
|
|
2859
|
-
window.innerHeight,
|
|
2860
|
-
launcher.offsetWidth,
|
|
2861
|
-
launcher.offsetHeight
|
|
2862
|
-
);
|
|
2863
|
-
launcherSideRef.current = edge;
|
|
2864
|
-
launcherPositionRef.current = next;
|
|
2865
|
-
setLauncherSide(edge);
|
|
2866
|
-
setLauncherPosition(next);
|
|
2867
|
-
setPanelSide(resolveSuiteAiPanelSide(edge, next.x, window.innerWidth));
|
|
2868
|
-
saveLauncherPosition(edge, next);
|
|
2869
|
-
}
|
|
2870
|
-
function startLauncherDrag(event) {
|
|
2871
|
-
if (event.pointerType === "mouse" && event.button !== 0) return;
|
|
2872
|
-
const rect = event.currentTarget.getBoundingClientRect();
|
|
2873
|
-
launcherDragRef.current = {
|
|
2874
|
-
pointerId: event.pointerId,
|
|
2875
|
-
offsetX: event.clientX - rect.left,
|
|
2876
|
-
offsetY: event.clientY - rect.top,
|
|
2877
|
-
startX: event.clientX,
|
|
2878
|
-
startY: event.clientY
|
|
2879
|
-
};
|
|
2880
|
-
suppressLauncherClickRef.current = false;
|
|
2881
|
-
event.currentTarget.setPointerCapture(event.pointerId);
|
|
2882
|
-
setDraggingLauncher(true);
|
|
2883
|
-
}
|
|
2884
|
-
function moveLauncher(event) {
|
|
2885
|
-
const drag = launcherDragRef.current;
|
|
2886
|
-
if (!drag || drag.pointerId !== event.pointerId) return;
|
|
2887
|
-
const launcher = event.currentTarget;
|
|
2888
|
-
const maxX = Math.max(
|
|
2889
|
-
LAUNCHER_EDGE_GAP,
|
|
2890
|
-
window.innerWidth - launcher.offsetWidth - LAUNCHER_EDGE_GAP
|
|
2891
|
-
);
|
|
2892
|
-
const maxY = Math.max(
|
|
2893
|
-
LAUNCHER_EDGE_GAP,
|
|
2894
|
-
window.innerHeight - launcher.offsetHeight - LAUNCHER_EDGE_GAP
|
|
2895
|
-
);
|
|
2896
|
-
const next = {
|
|
2897
|
-
x: Math.min(
|
|
2898
|
-
Math.max(event.clientX - drag.offsetX, LAUNCHER_EDGE_GAP),
|
|
2899
|
-
maxX
|
|
2900
|
-
),
|
|
2901
|
-
y: Math.min(
|
|
2902
|
-
Math.max(event.clientY - drag.offsetY, LAUNCHER_EDGE_GAP),
|
|
2903
|
-
maxY
|
|
2904
|
-
)
|
|
2905
|
-
};
|
|
2906
|
-
if (Math.hypot(event.clientX - drag.startX, event.clientY - drag.startY) > 4) {
|
|
2907
|
-
suppressLauncherClickRef.current = true;
|
|
2917
|
+
function onConversationClick(event) {
|
|
2918
|
+
var _a;
|
|
2919
|
+
if (event.defaultPrevented) return;
|
|
2920
|
+
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
|
|
2921
|
+
return;
|
|
2908
2922
|
}
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
event.currentTarget.releasePointerCapture(event.pointerId);
|
|
2918
|
-
}
|
|
2919
|
-
launcherDragRef.current = null;
|
|
2920
|
-
setDraggingLauncher(false);
|
|
2921
|
-
const rect = event.currentTarget.getBoundingClientRect();
|
|
2922
|
-
const currentX = (_b = (_a = launcherPositionRef.current) == null ? void 0 : _a.x) != null ? _b : rect.left;
|
|
2923
|
-
const currentY = (_d = (_c = launcherPositionRef.current) == null ? void 0 : _c.y) != null ? _d : rect.top;
|
|
2924
|
-
const edge = resolveSuiteAiNearestEdge(
|
|
2925
|
-
currentX,
|
|
2926
|
-
currentY,
|
|
2927
|
-
rect.width,
|
|
2928
|
-
rect.height,
|
|
2929
|
-
window.innerWidth,
|
|
2930
|
-
window.innerHeight
|
|
2923
|
+
const anchor = (_a = event.target) == null ? void 0 : _a.closest("a");
|
|
2924
|
+
if (!anchor || !suiteAppBases) return;
|
|
2925
|
+
const href = anchor.href;
|
|
2926
|
+
if (!href) return;
|
|
2927
|
+
const match = classifySuiteHref(
|
|
2928
|
+
href,
|
|
2929
|
+
suiteAppBases,
|
|
2930
|
+
window.location.origin
|
|
2931
2931
|
);
|
|
2932
|
-
|
|
2933
|
-
}
|
|
2934
|
-
function moveLauncherWithKeyboard(event) {
|
|
2935
|
-
var _a, _b, _c, _d;
|
|
2936
|
-
const edgeByKey = {
|
|
2937
|
-
ArrowLeft: "left",
|
|
2938
|
-
ArrowRight: "right",
|
|
2939
|
-
ArrowUp: "top",
|
|
2940
|
-
ArrowDown: "bottom"
|
|
2941
|
-
};
|
|
2942
|
-
const edge = edgeByKey[event.key];
|
|
2943
|
-
if (!edge) return;
|
|
2932
|
+
if (!match) return;
|
|
2944
2933
|
event.preventDefault();
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2934
|
+
if (match.sameApp) {
|
|
2935
|
+
window.location.assign(match.path);
|
|
2936
|
+
return;
|
|
2937
|
+
}
|
|
2938
|
+
if (onSwitchApp) onSwitchApp(match.slug, match.path);
|
|
2939
|
+
else window.location.assign(anchor.href);
|
|
2949
2940
|
}
|
|
2941
|
+
if (!open) return null;
|
|
2950
2942
|
const Icon = BrandIcon != null ? BrandIcon : import_iconoir_react8.Sparks;
|
|
2951
|
-
return /* @__PURE__ */ (0,
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
suppressLauncherClickRef.current = false;
|
|
2962
|
-
return;
|
|
2963
|
-
}
|
|
2964
|
-
setOpen(true);
|
|
2965
|
-
},
|
|
2966
|
-
onPointerDown: startLauncherDrag,
|
|
2967
|
-
onPointerMove: moveLauncher,
|
|
2968
|
-
onPointerUp: finishLauncherDrag,
|
|
2969
|
-
onPointerCancel: finishLauncherDrag,
|
|
2970
|
-
onKeyDown: moveLauncherWithKeyboard,
|
|
2971
|
-
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"}`,
|
|
2972
|
-
style: launcherPosition ? { left: launcherPosition.x, top: launcherPosition.y } : { bottom: 20, right: 20 },
|
|
2973
|
-
"aria-label": "Open Ask AI",
|
|
2974
|
-
"aria-describedby": "suite-ask-ai-launcher-help",
|
|
2975
|
-
children: [
|
|
2976
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Icon, { className: "h-4 w-4 text-ph-brand" }),
|
|
2977
|
-
"Ask AI"
|
|
2978
|
-
]
|
|
2979
|
-
}
|
|
2980
|
-
),
|
|
2981
|
-
/* @__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." })
|
|
2982
|
-
] }) : null,
|
|
2983
|
-
open ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
2984
|
-
"div",
|
|
2985
|
-
{
|
|
2986
|
-
className: "fixed inset-0 z-40",
|
|
2987
|
-
role: "dialog",
|
|
2988
|
-
"aria-modal": "true",
|
|
2989
|
-
"aria-label": title,
|
|
2990
|
-
children: [
|
|
2991
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
2943
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
2944
|
+
"aside",
|
|
2945
|
+
{
|
|
2946
|
+
className: "flex h-full min-h-0 flex-col bg-ph-canvas",
|
|
2947
|
+
"data-test": "suite-ask-ai-panel",
|
|
2948
|
+
"aria-label": title,
|
|
2949
|
+
children: [
|
|
2950
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("header", { className: "flex items-center gap-2 px-2 pb-2", children: [
|
|
2951
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h2", { className: "sr-only", children: title }),
|
|
2952
|
+
messages.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
2992
2953
|
"button",
|
|
2993
2954
|
{
|
|
2994
2955
|
type: "button",
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
"
|
|
2998
|
-
|
|
2956
|
+
onClick: () => void handleClear(),
|
|
2957
|
+
disabled: loading,
|
|
2958
|
+
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",
|
|
2959
|
+
"data-test": "ask-ai-clear",
|
|
2960
|
+
children: [
|
|
2961
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_iconoir_react8.Erase, { className: "h-3.5 w-3.5" }),
|
|
2962
|
+
"Clear"
|
|
2963
|
+
]
|
|
2999
2964
|
}
|
|
3000
|
-
)
|
|
3001
|
-
|
|
3002
|
-
|
|
2965
|
+
) : null
|
|
2966
|
+
] }),
|
|
2967
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "relative min-h-0 flex-1", children: [
|
|
2968
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
2969
|
+
"div",
|
|
3003
2970
|
{
|
|
3004
|
-
|
|
3005
|
-
|
|
2971
|
+
ref: scrollerRef,
|
|
2972
|
+
onScroll: handleScroll,
|
|
2973
|
+
onClick: onConversationClick,
|
|
2974
|
+
role: "log",
|
|
2975
|
+
"aria-live": "polite",
|
|
2976
|
+
"aria-label": "Conversation",
|
|
2977
|
+
className: "suite-scroll-lock h-full space-y-5 overflow-y-auto px-2 py-3",
|
|
3006
2978
|
children: [
|
|
3007
|
-
/* @__PURE__ */ (0,
|
|
3008
|
-
/* @__PURE__ */ (0,
|
|
3009
|
-
|
|
2979
|
+
hydrating && messages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-2 text-sm text-ph-subtle", children: [
|
|
2980
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Spinner, { className: "h-4 w-4 animate-spin" }),
|
|
2981
|
+
"Loading your chat\u2026"
|
|
2982
|
+
] }) : null,
|
|
2983
|
+
!hydrating && messages.length === 0 && !error ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "mx-auto mt-4 flex max-w-sm flex-col items-center px-1 text-center", children: [
|
|
2984
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "flex h-10 w-10 items-center justify-center rounded-2xl bg-ph-brand/10 text-ph-brand", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Icon, { className: "h-5 w-5" }) }),
|
|
2985
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "mt-3 font-display text-base font-semibold text-ph-ink", children: "How can I help?" }),
|
|
2986
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "mt-1 text-sm leading-relaxed text-ph-subtle", children: emptyState }),
|
|
2987
|
+
presets.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "mt-4 flex w-full flex-col gap-2", children: presets.map((preset) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
3010
2988
|
"button",
|
|
3011
2989
|
{
|
|
3012
2990
|
type: "button",
|
|
3013
|
-
onClick: () => void
|
|
3014
|
-
disabled: loading,
|
|
3015
|
-
className: "
|
|
3016
|
-
"data-test": "ask-ai-clear",
|
|
2991
|
+
onClick: () => void ask(preset.prompt),
|
|
2992
|
+
disabled: loading || hydrating,
|
|
2993
|
+
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",
|
|
3017
2994
|
children: [
|
|
3018
|
-
/* @__PURE__ */ (0,
|
|
3019
|
-
"
|
|
2995
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_iconoir_react8.Sparks, { className: "h-4 w-4 shrink-0 text-ph-brand" }),
|
|
2996
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "min-w-0 flex-1 truncate", children: preset.label }),
|
|
2997
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.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" })
|
|
3020
2998
|
]
|
|
3021
|
-
}
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
"
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
2999
|
+
},
|
|
3000
|
+
preset.label
|
|
3001
|
+
)) }) : null
|
|
3002
|
+
] }) : null,
|
|
3003
|
+
messages.map((message, index) => {
|
|
3004
|
+
const isUser = message.role === "user";
|
|
3005
|
+
if (isUser) {
|
|
3006
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3007
|
+
"div",
|
|
3008
|
+
{
|
|
3009
|
+
className: "flex justify-end",
|
|
3010
|
+
"data-test": "ask-ai-user",
|
|
3011
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("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 })
|
|
3012
|
+
},
|
|
3013
|
+
`user-${index}`
|
|
3014
|
+
);
|
|
3015
|
+
}
|
|
3016
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
3036
3017
|
"div",
|
|
3037
3018
|
{
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
role: "log",
|
|
3041
|
-
"aria-live": "polite",
|
|
3042
|
-
"aria-label": "Conversation",
|
|
3043
|
-
className: "suite-scroll-lock h-full space-y-5 overflow-y-auto px-4 py-5",
|
|
3019
|
+
className: "flex items-end gap-2",
|
|
3020
|
+
"data-test": "ask-ai-assistant",
|
|
3044
3021
|
children: [
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "mt-4 font-display text-lg font-semibold text-ph-ink", children: "How can I help?" }),
|
|
3052
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "mt-1.5 text-sm leading-relaxed text-ph-subtle", children: emptyState }),
|
|
3053
|
-
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)(
|
|
3054
|
-
"button",
|
|
3055
|
-
{
|
|
3056
|
-
type: "button",
|
|
3057
|
-
onClick: () => void ask(preset.prompt),
|
|
3058
|
-
disabled: loading || hydrating,
|
|
3059
|
-
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",
|
|
3060
|
-
children: [
|
|
3061
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_iconoir_react8.Sparks, { className: "h-4 w-4 shrink-0 text-ph-brand" }),
|
|
3062
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "min-w-0 flex-1 truncate", children: preset.label }),
|
|
3063
|
-
/* @__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" })
|
|
3064
|
-
]
|
|
3065
|
-
},
|
|
3066
|
-
preset.label
|
|
3067
|
-
)) }) : null
|
|
3068
|
-
] }) : null,
|
|
3069
|
-
messages.map((message, index) => {
|
|
3070
|
-
const isUser = message.role === "user";
|
|
3071
|
-
if (isUser) {
|
|
3072
|
-
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
3073
|
-
"div",
|
|
3074
|
-
{
|
|
3075
|
-
className: "flex justify-end",
|
|
3076
|
-
"data-test": "ask-ai-user",
|
|
3077
|
-
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 })
|
|
3078
|
-
},
|
|
3079
|
-
`user-${index}`
|
|
3080
|
-
);
|
|
3022
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3023
|
+
"span",
|
|
3024
|
+
{
|
|
3025
|
+
className: "mb-0.5 flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-ph-brand/10 text-ph-brand",
|
|
3026
|
+
"aria-hidden": true,
|
|
3027
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Icon, { className: "h-3.5 w-3.5" })
|
|
3081
3028
|
}
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
className: "flex gap-3",
|
|
3086
|
-
"data-test": "ask-ai-assistant",
|
|
3087
|
-
children: [
|
|
3088
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
3089
|
-
"span",
|
|
3090
|
-
{
|
|
3091
|
-
className: "mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-ph-brand/10 text-ph-brand",
|
|
3092
|
-
"aria-hidden": true,
|
|
3093
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Icon, { className: "h-4 w-4" })
|
|
3094
|
-
}
|
|
3095
|
-
),
|
|
3096
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "min-w-0 flex-1", children: [
|
|
3097
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "text-sm leading-relaxed text-ph-ink", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
3098
|
-
import_react10.Suspense,
|
|
3099
|
-
{
|
|
3100
|
-
fallback: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "whitespace-pre-wrap break-words", children: message.content }),
|
|
3101
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
3102
|
-
SuiteAiBlockNoteMessage2,
|
|
3103
|
-
{
|
|
3104
|
-
markdown: message.content
|
|
3105
|
-
}
|
|
3106
|
-
)
|
|
3107
|
-
}
|
|
3108
|
-
) }),
|
|
3109
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
3110
|
-
"button",
|
|
3111
|
-
{
|
|
3112
|
-
type: "button",
|
|
3113
|
-
onClick: () => void copyMessage(index, message.content),
|
|
3114
|
-
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",
|
|
3115
|
-
children: [
|
|
3116
|
-
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" }),
|
|
3117
|
-
copiedId === index ? "Copied" : "Copy"
|
|
3118
|
-
]
|
|
3119
|
-
}
|
|
3120
|
-
)
|
|
3121
|
-
] })
|
|
3122
|
-
]
|
|
3123
|
-
},
|
|
3124
|
-
`assistant-${index}`
|
|
3125
|
-
);
|
|
3126
|
-
}),
|
|
3127
|
-
loading ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex gap-3", "aria-hidden": true, children: [
|
|
3128
|
-
/* @__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" }) }),
|
|
3129
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-1.5 py-1.5", children: [
|
|
3130
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "h-1.5 w-1.5 rounded-full bg-ph-mutedtext motion-safe:animate-bounce" }),
|
|
3131
|
-
/* @__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]" }),
|
|
3132
|
-
/* @__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]" })
|
|
3133
|
-
] })
|
|
3134
|
-
] }) : null,
|
|
3135
|
-
loading ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "sr-only", "aria-live": "polite", children: "Assistant is responding\u2026" }) : null,
|
|
3136
|
-
error ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
3137
|
-
"div",
|
|
3029
|
+
),
|
|
3030
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("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__ */ (0, import_jsx_runtime21.jsx)(
|
|
3031
|
+
import_react11.Suspense,
|
|
3138
3032
|
{
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
children: [
|
|
3142
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_iconoir_react8.WarningTriangle, { className: "mt-0.5 h-4 w-4 shrink-0 text-ph-danger" }),
|
|
3143
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "min-w-0 flex-1", children: [
|
|
3144
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "font-medium text-ph-danger", children: "Something went wrong" }),
|
|
3145
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "mt-0.5 text-ph-subtle", children: error }),
|
|
3146
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
3147
|
-
"button",
|
|
3148
|
-
{
|
|
3149
|
-
type: "button",
|
|
3150
|
-
onClick: retry,
|
|
3151
|
-
disabled: loading,
|
|
3152
|
-
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",
|
|
3153
|
-
children: "Try again"
|
|
3154
|
-
}
|
|
3155
|
-
)
|
|
3156
|
-
] })
|
|
3157
|
-
]
|
|
3033
|
+
fallback: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "whitespace-pre-wrap break-words", children: message.content }),
|
|
3034
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(SuiteAiBlockNoteMessage2, { markdown: message.content })
|
|
3158
3035
|
}
|
|
3159
|
-
)
|
|
3036
|
+
) })
|
|
3160
3037
|
]
|
|
3161
|
-
}
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
}
|
|
3172
|
-
) : null
|
|
3173
|
-
] }),
|
|
3174
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "px-3 pb-[max(0.75rem,env(safe-area-inset-bottom))] pt-1", children: [
|
|
3175
|
-
/* @__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: [
|
|
3176
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("label", { htmlFor: "suite-ask-ai-input", className: "sr-only", children: "Ask a question" }),
|
|
3177
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
3178
|
-
"textarea",
|
|
3179
|
-
{
|
|
3180
|
-
id: "suite-ask-ai-input",
|
|
3181
|
-
ref: textareaRef,
|
|
3182
|
-
value: prompt,
|
|
3183
|
-
onChange: (e) => setPrompt(e.target.value),
|
|
3184
|
-
onKeyDown: (e) => {
|
|
3185
|
-
if (e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing) {
|
|
3186
|
-
e.preventDefault();
|
|
3187
|
-
void ask(prompt);
|
|
3188
|
-
}
|
|
3189
|
-
},
|
|
3190
|
-
placeholder: "Ask anything\u2026",
|
|
3191
|
-
rows: 1,
|
|
3192
|
-
"data-test": "ask-ai-input",
|
|
3193
|
-
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"
|
|
3194
|
-
}
|
|
3195
|
-
),
|
|
3196
|
-
loading ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
3197
|
-
"button",
|
|
3198
|
-
{
|
|
3199
|
-
type: "button",
|
|
3200
|
-
onClick: stop,
|
|
3201
|
-
"data-test": "ask-ai-stop",
|
|
3202
|
-
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",
|
|
3203
|
-
"aria-label": "Stop generating",
|
|
3204
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_iconoir_react8.Square, { className: "h-3.5 w-3.5 fill-current" })
|
|
3205
|
-
}
|
|
3206
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
3207
|
-
"button",
|
|
3208
|
-
{
|
|
3209
|
-
type: "button",
|
|
3210
|
-
onClick: () => void ask(prompt),
|
|
3211
|
-
disabled: !prompt.trim(),
|
|
3212
|
-
"data-test": "ask-ai-send",
|
|
3213
|
-
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",
|
|
3214
|
-
"aria-label": "Send message",
|
|
3215
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_iconoir_react8.ArrowUp, { className: "h-[18px] w-[18px]" })
|
|
3216
|
-
}
|
|
3217
|
-
)
|
|
3218
|
-
] }),
|
|
3219
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("p", { className: "mt-1.5 px-1 text-center text-xs text-ph-mutedtext", children: [
|
|
3220
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("kbd", { className: "font-mono", children: "Enter" }),
|
|
3221
|
-
" to send \xB7",
|
|
3222
|
-
" ",
|
|
3223
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("kbd", { className: "font-mono", children: "Shift" }),
|
|
3224
|
-
"+",
|
|
3225
|
-
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("kbd", { className: "font-mono", children: "Enter" }),
|
|
3226
|
-
" for a new line"
|
|
3038
|
+
},
|
|
3039
|
+
`assistant-${index}`
|
|
3040
|
+
);
|
|
3041
|
+
}),
|
|
3042
|
+
loading ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-end gap-2", "aria-hidden": true, children: [
|
|
3043
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("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__ */ (0, import_jsx_runtime21.jsx)(Icon, { className: "h-3.5 w-3.5" }) }),
|
|
3044
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-1.5 rounded-2xl rounded-bl-md bg-ph-muted px-3 py-2.5", children: [
|
|
3045
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "h-1.5 w-1.5 rounded-full bg-ph-mutedtext motion-safe:animate-bounce" }),
|
|
3046
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "h-1.5 w-1.5 rounded-full bg-ph-mutedtext motion-safe:animate-bounce [animation-delay:0.15s]" }),
|
|
3047
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "h-1.5 w-1.5 rounded-full bg-ph-mutedtext motion-safe:animate-bounce [animation-delay:0.3s]" })
|
|
3227
3048
|
] })
|
|
3228
|
-
] })
|
|
3049
|
+
] }) : null,
|
|
3050
|
+
loading ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "sr-only", "aria-live": "polite", children: "Assistant is responding\u2026" }) : null,
|
|
3051
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
3052
|
+
"div",
|
|
3053
|
+
{
|
|
3054
|
+
role: "alert",
|
|
3055
|
+
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",
|
|
3056
|
+
children: [
|
|
3057
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_iconoir_react8.WarningTriangle, { className: "mt-0.5 h-4 w-4 shrink-0 text-ph-danger" }),
|
|
3058
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "min-w-0 flex-1", children: [
|
|
3059
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "font-medium text-ph-danger", children: "Something went wrong" }),
|
|
3060
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "mt-0.5 text-ph-subtle", children: error }),
|
|
3061
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3062
|
+
"button",
|
|
3063
|
+
{
|
|
3064
|
+
type: "button",
|
|
3065
|
+
onClick: retry,
|
|
3066
|
+
disabled: loading,
|
|
3067
|
+
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",
|
|
3068
|
+
children: "Try again"
|
|
3069
|
+
}
|
|
3070
|
+
)
|
|
3071
|
+
] })
|
|
3072
|
+
]
|
|
3073
|
+
}
|
|
3074
|
+
) : null
|
|
3229
3075
|
]
|
|
3230
3076
|
}
|
|
3231
|
-
)
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3077
|
+
),
|
|
3078
|
+
!atBottom ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "absolute bottom-3 left-1/2 -translate-x-1/2", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Tooltip, { content: "Scroll to latest", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3079
|
+
"button",
|
|
3080
|
+
{
|
|
3081
|
+
type: "button",
|
|
3082
|
+
onClick: () => scrollToBottom("smooth"),
|
|
3083
|
+
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",
|
|
3084
|
+
"aria-label": "Scroll to latest",
|
|
3085
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_iconoir_react8.ArrowDown, { className: "h-4 w-4" })
|
|
3086
|
+
}
|
|
3087
|
+
) }) }) : null
|
|
3088
|
+
] }),
|
|
3089
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "px-2 pt-2 pb-[max(2rem,calc(env(safe-area-inset-bottom)+1rem))]", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("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: [
|
|
3090
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("label", { htmlFor: inputId, className: "sr-only", children: "Ask a question" }),
|
|
3091
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3092
|
+
"textarea",
|
|
3093
|
+
{
|
|
3094
|
+
id: inputId,
|
|
3095
|
+
ref: textareaRef,
|
|
3096
|
+
value: prompt,
|
|
3097
|
+
onChange: (event) => setPrompt(event.target.value),
|
|
3098
|
+
onKeyDown: (event) => {
|
|
3099
|
+
if (event.key === "Enter" && !event.shiftKey && !event.nativeEvent.isComposing) {
|
|
3100
|
+
event.preventDefault();
|
|
3101
|
+
void ask(prompt);
|
|
3102
|
+
}
|
|
3103
|
+
},
|
|
3104
|
+
placeholder: "Ask anything\u2026",
|
|
3105
|
+
rows: 1,
|
|
3106
|
+
"data-test": "ask-ai-input",
|
|
3107
|
+
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"
|
|
3108
|
+
}
|
|
3109
|
+
),
|
|
3110
|
+
loading ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Tooltip, { content: "Stop generating", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3111
|
+
"button",
|
|
3112
|
+
{
|
|
3113
|
+
type: "button",
|
|
3114
|
+
onClick: stop,
|
|
3115
|
+
"data-test": "ask-ai-stop",
|
|
3116
|
+
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",
|
|
3117
|
+
"aria-label": "Stop generating",
|
|
3118
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_iconoir_react8.Square, { className: "h-3.5 w-3.5 fill-current" })
|
|
3119
|
+
}
|
|
3120
|
+
) }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Tooltip, { content: "Send message", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
3121
|
+
"button",
|
|
3122
|
+
{
|
|
3123
|
+
type: "button",
|
|
3124
|
+
onClick: () => void ask(prompt),
|
|
3125
|
+
disabled: !prompt.trim(),
|
|
3126
|
+
"data-test": "ask-ai-send",
|
|
3127
|
+
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",
|
|
3128
|
+
"aria-label": "Send message",
|
|
3129
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_iconoir_react8.ArrowUp, { className: "h-4 w-4" })
|
|
3130
|
+
}
|
|
3131
|
+
) })
|
|
3132
|
+
] }) })
|
|
3133
|
+
]
|
|
3134
|
+
}
|
|
3135
|
+
);
|
|
3136
|
+
}
|
|
3137
|
+
|
|
3138
|
+
// src/suite/components/workspace-switcher.tsx
|
|
3139
|
+
var import_react12 = require("react");
|
|
3140
|
+
var import_iconoir_react9 = require("iconoir-react");
|
|
3141
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
3142
|
+
function SuiteWorkspaceSwitcher({
|
|
3143
|
+
workspaces = [],
|
|
3144
|
+
groups,
|
|
3145
|
+
currentId,
|
|
3146
|
+
onSelect,
|
|
3147
|
+
name,
|
|
3148
|
+
collapsed = false,
|
|
3149
|
+
emptyLabel = "No workspaces yet.",
|
|
3150
|
+
dropdownMenu: DropdownMenu2,
|
|
3151
|
+
dropdownItem: DropdownItem2,
|
|
3152
|
+
triggerId,
|
|
3153
|
+
triggerDataTest,
|
|
3154
|
+
footer
|
|
3155
|
+
}) {
|
|
3156
|
+
var _a;
|
|
3157
|
+
const [open, setOpen] = (0, import_react12.useState)(false);
|
|
3158
|
+
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 }] : [];
|
|
3159
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
3160
|
+
DropdownMenu2,
|
|
3161
|
+
{
|
|
3162
|
+
"aria-label": "Switch workspace",
|
|
3163
|
+
triggerId: triggerId != null ? triggerId : "workspace-switcher-trigger",
|
|
3164
|
+
triggerDataTest: triggerDataTest != null ? triggerDataTest : "workspace-switcher-trigger",
|
|
3165
|
+
className: collapsed ? "w-11 shrink-0" : "w-full min-w-0 max-w-full [&_.ph-dropdown-trigger]:w-full",
|
|
3166
|
+
panelClassName: "w-64 max-w-full",
|
|
3167
|
+
align: "start",
|
|
3168
|
+
open,
|
|
3169
|
+
onOpenChange: setOpen,
|
|
3170
|
+
trigger: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
3171
|
+
"span",
|
|
3172
|
+
{
|
|
3173
|
+
className: cn(
|
|
3174
|
+
"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",
|
|
3175
|
+
collapsed ? "h-10 w-10 justify-center p-0" : "w-full px-3 py-2",
|
|
3176
|
+
open && "border-ph-brand/40"
|
|
3177
|
+
),
|
|
3178
|
+
"data-test": "workspace-switcher-trigger",
|
|
3179
|
+
"aria-expanded": open,
|
|
3180
|
+
children: [
|
|
3181
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_iconoir_react9.Building, { className: "h-4 w-4 shrink-0 text-ph-ink", "aria-hidden": true }),
|
|
3182
|
+
!collapsed ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
|
|
3183
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "min-w-0 flex-1 truncate text-sm font-semibold text-ph-ink", children: name }),
|
|
3184
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
3185
|
+
import_iconoir_react9.NavArrowDown,
|
|
3186
|
+
{
|
|
3187
|
+
className: cn(
|
|
3188
|
+
"h-3.5 w-3.5 shrink-0 text-ph-mutedtext transition-transform",
|
|
3189
|
+
open && "rotate-180"
|
|
3190
|
+
),
|
|
3191
|
+
"aria-hidden": true
|
|
3192
|
+
}
|
|
3193
|
+
)
|
|
3194
|
+
] }) : null
|
|
3195
|
+
]
|
|
3196
|
+
}
|
|
3197
|
+
),
|
|
3198
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
3199
|
+
"div",
|
|
3200
|
+
{
|
|
3201
|
+
id: "workspace-switcher-menu",
|
|
3202
|
+
className: "p-1",
|
|
3203
|
+
"data-test": "workspace-switcher-menu",
|
|
3204
|
+
children: [
|
|
3205
|
+
sections.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "px-3 py-2 text-sm text-ph-mutedtext", children: emptyLabel }) : sections.map((section) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { children: [
|
|
3206
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { className: "px-3 py-2 text-[10px] font-semibold uppercase tracking-[0.14em] text-ph-mutedtext", children: section.label }),
|
|
3207
|
+
section.workspaces.map((workspace) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
3208
|
+
DropdownItem2,
|
|
3209
|
+
{
|
|
3210
|
+
id: `workspace-option-${workspace.id}`,
|
|
3211
|
+
role: "option",
|
|
3212
|
+
"aria-selected": workspace.id === currentId,
|
|
3213
|
+
"data-test": "workspace-option",
|
|
3214
|
+
"data-workspace-id": workspace.id,
|
|
3215
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
3216
|
+
onClick: () => {
|
|
3217
|
+
setOpen(false);
|
|
3218
|
+
onSelect(workspace);
|
|
3219
|
+
},
|
|
3220
|
+
className: appSwitcherMenuItemClass(),
|
|
3221
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { className: "flex min-w-0 w-full items-center gap-3", children: [
|
|
3222
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("span", { className: "min-w-0 flex-1", children: [
|
|
3223
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "block truncate text-sm font-medium text-ph-ink", children: workspace.name }),
|
|
3224
|
+
workspace.description ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "block truncate text-xs text-ph-mutedtext", children: workspace.description }) : null
|
|
3225
|
+
] }),
|
|
3226
|
+
workspace.id === currentId ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
3227
|
+
import_iconoir_react9.Check,
|
|
3228
|
+
{
|
|
3229
|
+
className: "h-4 w-4 shrink-0 text-ph-brand",
|
|
3230
|
+
"aria-hidden": "true"
|
|
3231
|
+
}
|
|
3232
|
+
) : null
|
|
3233
|
+
] })
|
|
3234
|
+
},
|
|
3235
|
+
workspace.id
|
|
3236
|
+
))
|
|
3237
|
+
] }, section.id)),
|
|
3238
|
+
footer ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "mt-1 border-t border-ph-border pt-1", children: footer }) : null
|
|
3239
|
+
]
|
|
3240
|
+
}
|
|
3241
|
+
)
|
|
3242
|
+
}
|
|
3243
|
+
);
|
|
3236
3244
|
}
|
|
3237
3245
|
|
|
3238
3246
|
// src/suite/lib/use-sidebar-width.ts
|
|
3239
|
-
var
|
|
3247
|
+
var import_react13 = require("react");
|
|
3240
3248
|
var SIDEBAR_RAIL_WIDTH = 56;
|
|
3241
3249
|
var SIDEBAR_COLLAPSE_THRESHOLD = 80;
|
|
3242
3250
|
var SIDEBAR_MIN_EXPANDED_WIDTH = 180;
|
|
3243
|
-
var SIDEBAR_MAX_WIDTH =
|
|
3251
|
+
var SIDEBAR_MAX_WIDTH = 640;
|
|
3244
3252
|
var SIDEBAR_DEFAULT_WIDTH = 320;
|
|
3253
|
+
function sidebarColumnWidth(width, collapsed, _chatOpen = false) {
|
|
3254
|
+
if (collapsed) return SIDEBAR_RAIL_WIDTH;
|
|
3255
|
+
return width;
|
|
3256
|
+
}
|
|
3245
3257
|
function clampWidth(width) {
|
|
3246
3258
|
return Math.min(SIDEBAR_MAX_WIDTH, Math.max(SIDEBAR_RAIL_WIDTH, width));
|
|
3247
3259
|
}
|
|
@@ -3252,10 +3264,10 @@ function snapWidth(width) {
|
|
|
3252
3264
|
}
|
|
3253
3265
|
function useSidebarWidth(storageKey, defaultWidth = SIDEBAR_DEFAULT_WIDTH) {
|
|
3254
3266
|
const fallbackWidth = snapWidth(clampWidth(defaultWidth));
|
|
3255
|
-
const [width, setWidth] = (0,
|
|
3256
|
-
const [narrowViewport, setNarrowViewport] = (0,
|
|
3267
|
+
const [width, setWidth] = (0, import_react13.useState)(fallbackWidth);
|
|
3268
|
+
const [narrowViewport, setNarrowViewport] = (0, import_react13.useState)(false);
|
|
3257
3269
|
const collapsed = narrowViewport || width <= SIDEBAR_COLLAPSE_THRESHOLD;
|
|
3258
|
-
(0,
|
|
3270
|
+
(0, import_react13.useEffect)(() => {
|
|
3259
3271
|
let stored = null;
|
|
3260
3272
|
try {
|
|
3261
3273
|
stored = localStorage.getItem(storageKey);
|
|
@@ -3267,14 +3279,14 @@ function useSidebarWidth(storageKey, defaultWidth = SIDEBAR_DEFAULT_WIDTH) {
|
|
|
3267
3279
|
queueMicrotask(() => setWidth(snapWidth(clampWidth(parsed))));
|
|
3268
3280
|
}
|
|
3269
3281
|
}, [storageKey]);
|
|
3270
|
-
(0,
|
|
3282
|
+
(0, import_react13.useEffect)(() => {
|
|
3271
3283
|
const media = window.matchMedia("(max-width: 639px)");
|
|
3272
3284
|
const sync = () => setNarrowViewport(media.matches);
|
|
3273
3285
|
sync();
|
|
3274
3286
|
media.addEventListener("change", sync);
|
|
3275
3287
|
return () => media.removeEventListener("change", sync);
|
|
3276
3288
|
}, []);
|
|
3277
|
-
const persist = (0,
|
|
3289
|
+
const persist = (0, import_react13.useCallback)(
|
|
3278
3290
|
(value) => {
|
|
3279
3291
|
try {
|
|
3280
3292
|
localStorage.setItem(storageKey, String(value));
|
|
@@ -3283,7 +3295,7 @@ function useSidebarWidth(storageKey, defaultWidth = SIDEBAR_DEFAULT_WIDTH) {
|
|
|
3283
3295
|
},
|
|
3284
3296
|
[storageKey]
|
|
3285
3297
|
);
|
|
3286
|
-
const setCollapsed = (0,
|
|
3298
|
+
const setCollapsed = (0, import_react13.useCallback)(
|
|
3287
3299
|
(value) => {
|
|
3288
3300
|
setWidth((current) => {
|
|
3289
3301
|
const next = value ? SIDEBAR_RAIL_WIDTH : current <= SIDEBAR_COLLAPSE_THRESHOLD ? fallbackWidth : snapWidth(current);
|
|
@@ -3293,11 +3305,11 @@ function useSidebarWidth(storageKey, defaultWidth = SIDEBAR_DEFAULT_WIDTH) {
|
|
|
3293
3305
|
},
|
|
3294
3306
|
[fallbackWidth, persist]
|
|
3295
3307
|
);
|
|
3296
|
-
const resetWidth = (0,
|
|
3308
|
+
const resetWidth = (0, import_react13.useCallback)(() => {
|
|
3297
3309
|
setWidth(fallbackWidth);
|
|
3298
3310
|
persist(fallbackWidth);
|
|
3299
3311
|
}, [fallbackWidth, persist]);
|
|
3300
|
-
const startResize = (0,
|
|
3312
|
+
const startResize = (0, import_react13.useCallback)(
|
|
3301
3313
|
(event) => {
|
|
3302
3314
|
event.preventDefault();
|
|
3303
3315
|
const startX = event.clientX;
|
|
@@ -3319,7 +3331,7 @@ function useSidebarWidth(storageKey, defaultWidth = SIDEBAR_DEFAULT_WIDTH) {
|
|
|
3319
3331
|
},
|
|
3320
3332
|
[persist, width]
|
|
3321
3333
|
);
|
|
3322
|
-
const resizeBy = (0,
|
|
3334
|
+
const resizeBy = (0, import_react13.useCallback)(
|
|
3323
3335
|
(delta) => {
|
|
3324
3336
|
setWidth((current) => {
|
|
3325
3337
|
const next = clampWidth(current + delta);
|
|
@@ -3333,10 +3345,10 @@ function useSidebarWidth(storageKey, defaultWidth = SIDEBAR_DEFAULT_WIDTH) {
|
|
|
3333
3345
|
}
|
|
3334
3346
|
|
|
3335
3347
|
// src/suite/lib/motion.tsx
|
|
3336
|
-
var
|
|
3337
|
-
var
|
|
3348
|
+
var import_react14 = require("motion/react");
|
|
3349
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
3338
3350
|
function SuiteMotionProvider({ children }) {
|
|
3339
|
-
return /* @__PURE__ */ (0,
|
|
3351
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react14.LazyMotion, { features: import_react14.domAnimation, strict: true, children });
|
|
3340
3352
|
}
|
|
3341
3353
|
var SUITE_SPRINGS = {
|
|
3342
3354
|
/** Snappy panel/sheet entrances — small overshoot. */
|
|
@@ -3348,24 +3360,24 @@ var SUITE_SPRINGS = {
|
|
|
3348
3360
|
};
|
|
3349
3361
|
|
|
3350
3362
|
// src/suite/components/suite-skeleton.tsx
|
|
3351
|
-
var
|
|
3363
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
3352
3364
|
function SuiteSkeleton({
|
|
3353
3365
|
className,
|
|
3354
3366
|
lines = 1,
|
|
3355
3367
|
circle,
|
|
3356
3368
|
width
|
|
3357
3369
|
}) {
|
|
3358
|
-
return /* @__PURE__ */ (0,
|
|
3370
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
3359
3371
|
"div",
|
|
3360
3372
|
{
|
|
3361
3373
|
className: cn("space-y-2", circle ? "flex flex-col items-center" : ""),
|
|
3362
3374
|
"aria-hidden": true,
|
|
3363
|
-
children: Array.from({ length: lines }).map((_, index) => /* @__PURE__ */ (0,
|
|
3375
|
+
children: Array.from({ length: lines }).map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
3364
3376
|
"div",
|
|
3365
3377
|
{
|
|
3366
3378
|
className: "animate-[skeleton-stagger_0.6s_ease-out_both]",
|
|
3367
3379
|
style: { animationDelay: `${index * 80}ms` },
|
|
3368
|
-
children: /* @__PURE__ */ (0,
|
|
3380
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
3369
3381
|
"div",
|
|
3370
3382
|
{
|
|
3371
3383
|
className: cn(
|
|
@@ -3389,7 +3401,7 @@ function SuiteSkeletonCard({
|
|
|
3389
3401
|
rows = 3,
|
|
3390
3402
|
header = true
|
|
3391
3403
|
}) {
|
|
3392
|
-
return /* @__PURE__ */ (0,
|
|
3404
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
3393
3405
|
"div",
|
|
3394
3406
|
{
|
|
3395
3407
|
className: cn(
|
|
@@ -3398,26 +3410,26 @@ function SuiteSkeletonCard({
|
|
|
3398
3410
|
),
|
|
3399
3411
|
"aria-hidden": true,
|
|
3400
3412
|
children: [
|
|
3401
|
-
header ? /* @__PURE__ */ (0,
|
|
3413
|
+
header ? /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
3402
3414
|
"div",
|
|
3403
3415
|
{
|
|
3404
3416
|
className: "mb-5 flex items-center gap-3 animate-[skeleton-stagger_0.5s_ease-out_both]",
|
|
3405
3417
|
style: { animationDelay: "100ms" },
|
|
3406
3418
|
children: [
|
|
3407
|
-
/* @__PURE__ */ (0,
|
|
3408
|
-
/* @__PURE__ */ (0,
|
|
3409
|
-
/* @__PURE__ */ (0,
|
|
3410
|
-
/* @__PURE__ */ (0,
|
|
3419
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "ph-skeleton h-10 w-10 rounded-xl" }),
|
|
3420
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex-1 space-y-2", children: [
|
|
3421
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "ph-skeleton h-4 w-1/3" }),
|
|
3422
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "ph-skeleton h-3 w-1/2" })
|
|
3411
3423
|
] })
|
|
3412
3424
|
]
|
|
3413
3425
|
}
|
|
3414
3426
|
) : null,
|
|
3415
|
-
/* @__PURE__ */ (0,
|
|
3427
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "space-y-3", children: Array.from({ length: rows }).map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
3416
3428
|
"div",
|
|
3417
3429
|
{
|
|
3418
3430
|
className: "animate-[skeleton-stagger_0.5s_ease-out_both]",
|
|
3419
3431
|
style: { animationDelay: `${200 + index * 80}ms` },
|
|
3420
|
-
children: /* @__PURE__ */ (0,
|
|
3432
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
3421
3433
|
"div",
|
|
3422
3434
|
{
|
|
3423
3435
|
className: "ph-skeleton h-3",
|
|
@@ -3435,16 +3447,16 @@ function SuiteSkeletonList({
|
|
|
3435
3447
|
className,
|
|
3436
3448
|
items = 4
|
|
3437
3449
|
}) {
|
|
3438
|
-
return /* @__PURE__ */ (0,
|
|
3450
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: cn("space-y-3", className), "aria-hidden": true, children: Array.from({ length: items }).map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
3439
3451
|
"div",
|
|
3440
3452
|
{
|
|
3441
3453
|
className: "animate-[skeleton-stagger_0.6s_ease-out_both]",
|
|
3442
3454
|
style: { animationDelay: `${index * 100}ms` },
|
|
3443
|
-
children: /* @__PURE__ */ (0,
|
|
3444
|
-
/* @__PURE__ */ (0,
|
|
3445
|
-
/* @__PURE__ */ (0,
|
|
3446
|
-
/* @__PURE__ */ (0,
|
|
3447
|
-
/* @__PURE__ */ (0,
|
|
3455
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex items-center gap-3 rounded-xl border border-ph-border bg-ph-surface p-4", children: [
|
|
3456
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "ph-skeleton h-10 w-10 rounded-lg" }),
|
|
3457
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "min-w-0 flex-1 space-y-2", children: [
|
|
3458
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "ph-skeleton h-3.5 w-3/4" }),
|
|
3459
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "ph-skeleton h-3 w-1/2" })
|
|
3448
3460
|
] })
|
|
3449
3461
|
] })
|
|
3450
3462
|
},
|
|
@@ -3459,7 +3471,7 @@ function SuiteEmptyState({
|
|
|
3459
3471
|
className,
|
|
3460
3472
|
size = "md"
|
|
3461
3473
|
}) {
|
|
3462
|
-
return /* @__PURE__ */ (0,
|
|
3474
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
3463
3475
|
"div",
|
|
3464
3476
|
{
|
|
3465
3477
|
className: cn(
|
|
@@ -3468,13 +3480,13 @@ function SuiteEmptyState({
|
|
|
3468
3480
|
className
|
|
3469
3481
|
),
|
|
3470
3482
|
children: [
|
|
3471
|
-
/* @__PURE__ */ (0,
|
|
3472
|
-
/* @__PURE__ */ (0,
|
|
3473
|
-
/* @__PURE__ */ (0,
|
|
3483
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "pointer-events-none absolute inset-0 overflow-hidden opacity-60", "aria-hidden": true, children: [
|
|
3484
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "absolute -left-10 -top-10 h-40 w-40 rounded-full bg-ph-brand/10 blur-3xl" }),
|
|
3485
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "absolute -bottom-10 -right-10 h-40 w-40 rounded-full bg-ph-accent/10 blur-3xl" })
|
|
3474
3486
|
] }),
|
|
3475
|
-
/* @__PURE__ */ (0,
|
|
3476
|
-
icon ? /* @__PURE__ */ (0,
|
|
3477
|
-
/* @__PURE__ */ (0,
|
|
3487
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "relative", children: [
|
|
3488
|
+
icon ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("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,
|
|
3489
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
3478
3490
|
"h3",
|
|
3479
3491
|
{
|
|
3480
3492
|
className: cn(
|
|
@@ -3484,8 +3496,8 @@ function SuiteEmptyState({
|
|
|
3484
3496
|
children: title
|
|
3485
3497
|
}
|
|
3486
3498
|
),
|
|
3487
|
-
description ? /* @__PURE__ */ (0,
|
|
3488
|
-
action ? /* @__PURE__ */ (0,
|
|
3499
|
+
description ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("p", { className: "mx-auto mt-2 max-w-sm text-sm leading-relaxed text-ph-subtle", children: description }) : null,
|
|
3500
|
+
action ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "mt-5 flex flex-wrap items-center justify-center gap-2", children: action }) : null
|
|
3489
3501
|
] })
|
|
3490
3502
|
]
|
|
3491
3503
|
}
|
|
@@ -3493,8 +3505,8 @@ function SuiteEmptyState({
|
|
|
3493
3505
|
}
|
|
3494
3506
|
|
|
3495
3507
|
// src/suite/components/suite-settings-mobile-nav.tsx
|
|
3496
|
-
var
|
|
3497
|
-
var
|
|
3508
|
+
var import_react15 = require("react");
|
|
3509
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
3498
3510
|
function SuiteSettingsMobileNav({
|
|
3499
3511
|
items,
|
|
3500
3512
|
activeHref,
|
|
@@ -3503,16 +3515,16 @@ function SuiteSettingsMobileNav({
|
|
|
3503
3515
|
ariaLabel = "Settings sections",
|
|
3504
3516
|
className
|
|
3505
3517
|
}) {
|
|
3506
|
-
return /* @__PURE__ */ (0,
|
|
3518
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
3507
3519
|
"nav",
|
|
3508
3520
|
{
|
|
3509
3521
|
"data-test": dataTest,
|
|
3510
3522
|
"aria-label": ariaLabel,
|
|
3511
3523
|
className: cn("suite-settings-mobile-nav lg:hidden", className),
|
|
3512
|
-
children: /* @__PURE__ */ (0,
|
|
3524
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("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) => {
|
|
3513
3525
|
const Icon = item.icon;
|
|
3514
3526
|
const active = activeHref === item.href || activeHref.startsWith(`${item.href}/`);
|
|
3515
|
-
const iconNode = (0,
|
|
3527
|
+
const iconNode = (0, import_react15.isValidElement)(item.icon) ? item.icon : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
3516
3528
|
Icon,
|
|
3517
3529
|
{
|
|
3518
3530
|
className: cn(
|
|
@@ -3522,7 +3534,7 @@ function SuiteSettingsMobileNav({
|
|
|
3522
3534
|
"aria-hidden": true
|
|
3523
3535
|
}
|
|
3524
3536
|
);
|
|
3525
|
-
return /* @__PURE__ */ (0,
|
|
3537
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
3526
3538
|
"button",
|
|
3527
3539
|
{
|
|
3528
3540
|
type: "button",
|
|
@@ -3537,8 +3549,8 @@ function SuiteSettingsMobileNav({
|
|
|
3537
3549
|
),
|
|
3538
3550
|
children: [
|
|
3539
3551
|
iconNode,
|
|
3540
|
-
/* @__PURE__ */ (0,
|
|
3541
|
-
active ? /* @__PURE__ */ (0,
|
|
3552
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "whitespace-nowrap", children: item.label }),
|
|
3553
|
+
active ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "absolute inset-x-0 -bottom-3 h-0.5 rounded-full bg-ph-ink lg:hidden" }) : null
|
|
3542
3554
|
]
|
|
3543
3555
|
},
|
|
3544
3556
|
item.href
|
|
@@ -3550,144 +3562,9 @@ function SuiteSettingsMobileNav({
|
|
|
3550
3562
|
|
|
3551
3563
|
// src/suite/components/suite-sidebar.tsx
|
|
3552
3564
|
var import_link2 = __toESM(require("next/link"));
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
var
|
|
3556
|
-
var import_react_dom = require("react-dom");
|
|
3557
|
-
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
3558
|
-
var TooltipDelayContext = (0, import_react14.createContext)(0);
|
|
3559
|
-
function tooltipPosition(trigger, side, align, offset) {
|
|
3560
|
-
const horizontal = align === "start" ? trigger.left : align === "end" ? trigger.right : trigger.left + trigger.width / 2;
|
|
3561
|
-
const vertical = align === "start" ? trigger.top : align === "end" ? trigger.bottom : trigger.top + trigger.height / 2;
|
|
3562
|
-
if (side === "top")
|
|
3563
|
-
return {
|
|
3564
|
-
left: horizontal,
|
|
3565
|
-
top: trigger.top - offset,
|
|
3566
|
-
transform: "translate(-50%, -100%)"
|
|
3567
|
-
};
|
|
3568
|
-
if (side === "bottom")
|
|
3569
|
-
return {
|
|
3570
|
-
left: horizontal,
|
|
3571
|
-
top: trigger.bottom + offset,
|
|
3572
|
-
transform: "translate(-50%, 0)"
|
|
3573
|
-
};
|
|
3574
|
-
if (side === "left")
|
|
3575
|
-
return {
|
|
3576
|
-
left: trigger.left - offset,
|
|
3577
|
-
top: vertical,
|
|
3578
|
-
transform: "translate(-100%, -50%)"
|
|
3579
|
-
};
|
|
3580
|
-
return {
|
|
3581
|
-
left: trigger.right + offset,
|
|
3582
|
-
top: vertical,
|
|
3583
|
-
transform: "translate(0, -50%)"
|
|
3584
|
-
};
|
|
3585
|
-
}
|
|
3586
|
-
function Tooltip({
|
|
3587
|
-
content,
|
|
3588
|
-
children,
|
|
3589
|
-
side = "top",
|
|
3590
|
-
align = "center",
|
|
3591
|
-
sideOffset = 7,
|
|
3592
|
-
className,
|
|
3593
|
-
open,
|
|
3594
|
-
defaultOpen = false,
|
|
3595
|
-
onOpenChange,
|
|
3596
|
-
delayDuration
|
|
3597
|
-
}) {
|
|
3598
|
-
const providerDelay = (0, import_react14.useContext)(TooltipDelayContext);
|
|
3599
|
-
const generatedId = (0, import_react14.useId)().replace(/:/g, "");
|
|
3600
|
-
const triggerRef = (0, import_react14.useRef)(null);
|
|
3601
|
-
const timerRef = (0, import_react14.useRef)(null);
|
|
3602
|
-
const [internalOpen, setInternalOpen] = (0, import_react14.useState)(defaultOpen);
|
|
3603
|
-
const [position, setPosition] = (0, import_react14.useState)(null);
|
|
3604
|
-
const isOpen = open != null ? open : internalOpen;
|
|
3605
|
-
const triggerId = children.props.id;
|
|
3606
|
-
const tooltipId = triggerId ? `${triggerId}-tooltip` : `ph-tooltip-${generatedId}`;
|
|
3607
|
-
function setOpen(next) {
|
|
3608
|
-
if (open === void 0) setInternalOpen(next);
|
|
3609
|
-
onOpenChange == null ? void 0 : onOpenChange(next);
|
|
3610
|
-
}
|
|
3611
|
-
function clearTimer() {
|
|
3612
|
-
if (timerRef.current) clearTimeout(timerRef.current);
|
|
3613
|
-
timerRef.current = null;
|
|
3614
|
-
}
|
|
3615
|
-
function updatePosition() {
|
|
3616
|
-
if (!triggerRef.current) return;
|
|
3617
|
-
setPosition(
|
|
3618
|
-
tooltipPosition(
|
|
3619
|
-
triggerRef.current.getBoundingClientRect(),
|
|
3620
|
-
side,
|
|
3621
|
-
align,
|
|
3622
|
-
sideOffset
|
|
3623
|
-
)
|
|
3624
|
-
);
|
|
3625
|
-
}
|
|
3626
|
-
function show(immediate) {
|
|
3627
|
-
clearTimer();
|
|
3628
|
-
updatePosition();
|
|
3629
|
-
const delay = immediate ? 0 : delayDuration != null ? delayDuration : providerDelay;
|
|
3630
|
-
if (!delay) setOpen(true);
|
|
3631
|
-
else timerRef.current = setTimeout(() => setOpen(true), delay);
|
|
3632
|
-
}
|
|
3633
|
-
function hide() {
|
|
3634
|
-
clearTimer();
|
|
3635
|
-
setOpen(false);
|
|
3636
|
-
}
|
|
3637
|
-
(0, import_react14.useEffect)(() => {
|
|
3638
|
-
if (!isOpen) return;
|
|
3639
|
-
const reposition = () => updatePosition();
|
|
3640
|
-
window.addEventListener("resize", reposition);
|
|
3641
|
-
window.addEventListener("scroll", reposition, true);
|
|
3642
|
-
return () => {
|
|
3643
|
-
window.removeEventListener("resize", reposition);
|
|
3644
|
-
window.removeEventListener("scroll", reposition, true);
|
|
3645
|
-
};
|
|
3646
|
-
});
|
|
3647
|
-
(0, import_react14.useEffect)(() => () => clearTimer(), []);
|
|
3648
|
-
const describedBy = [children.props["aria-describedby"], tooltipId].filter(Boolean).join(" ");
|
|
3649
|
-
const trigger = (0, import_react14.cloneElement)(children, { "aria-describedby": describedBy });
|
|
3650
|
-
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
|
|
3651
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
3652
|
-
"span",
|
|
3653
|
-
{
|
|
3654
|
-
ref: triggerRef,
|
|
3655
|
-
className: "inline-flex",
|
|
3656
|
-
onMouseEnter: () => show(false),
|
|
3657
|
-
onMouseLeave: hide,
|
|
3658
|
-
onFocusCapture: () => show(true),
|
|
3659
|
-
onBlurCapture: hide,
|
|
3660
|
-
onKeyDown: (event) => {
|
|
3661
|
-
if (event.key === "Escape") hide();
|
|
3662
|
-
},
|
|
3663
|
-
children: trigger
|
|
3664
|
-
}
|
|
3665
|
-
),
|
|
3666
|
-
isOpen && position && typeof document !== "undefined" ? (0, import_react_dom.createPortal)(
|
|
3667
|
-
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
3668
|
-
"span",
|
|
3669
|
-
{
|
|
3670
|
-
style: __spreadValues({ position: "fixed" }, position),
|
|
3671
|
-
className: "pointer-events-none z-[200]",
|
|
3672
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
3673
|
-
"span",
|
|
3674
|
-
{
|
|
3675
|
-
id: tooltipId,
|
|
3676
|
-
role: "tooltip",
|
|
3677
|
-
"data-side": side,
|
|
3678
|
-
className: cn2("ph-tooltip-content", className),
|
|
3679
|
-
children: content
|
|
3680
|
-
}
|
|
3681
|
-
)
|
|
3682
|
-
}
|
|
3683
|
-
),
|
|
3684
|
-
document.body
|
|
3685
|
-
) : null
|
|
3686
|
-
] });
|
|
3687
|
-
}
|
|
3688
|
-
|
|
3689
|
-
// src/suite/components/suite-sidebar.tsx
|
|
3690
|
-
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
3565
|
+
var import_react16 = require("react");
|
|
3566
|
+
var import_iconoir_react10 = require("iconoir-react");
|
|
3567
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
3691
3568
|
function renderNode(node, collapsed) {
|
|
3692
3569
|
if (typeof node === "function") return node(collapsed);
|
|
3693
3570
|
return node;
|
|
@@ -3702,9 +3579,94 @@ function SuiteSidebar({
|
|
|
3702
3579
|
footerExtras,
|
|
3703
3580
|
collapsed = false,
|
|
3704
3581
|
className,
|
|
3705
|
-
surface = false
|
|
3582
|
+
surface = false,
|
|
3583
|
+
askAiOpen = false,
|
|
3584
|
+
onAskAiOpenChange,
|
|
3585
|
+
askAi,
|
|
3586
|
+
onRequestExpand
|
|
3706
3587
|
}) {
|
|
3707
|
-
|
|
3588
|
+
const showAskAi = Boolean(onAskAiOpenChange && askAi);
|
|
3589
|
+
const chatOpen = showAskAi && askAiOpen && !collapsed;
|
|
3590
|
+
(0, import_react16.useEffect)(() => {
|
|
3591
|
+
if (!onAskAiOpenChange) return;
|
|
3592
|
+
function onOpen() {
|
|
3593
|
+
onRequestExpand == null ? void 0 : onRequestExpand();
|
|
3594
|
+
onAskAiOpenChange == null ? void 0 : onAskAiOpenChange(true);
|
|
3595
|
+
}
|
|
3596
|
+
window.addEventListener(SUITE_OPEN_ASK_AI_EVENT, onOpen);
|
|
3597
|
+
return () => window.removeEventListener(SUITE_OPEN_ASK_AI_EVENT, onOpen);
|
|
3598
|
+
}, [onAskAiOpenChange, onRequestExpand]);
|
|
3599
|
+
(0, import_react16.useEffect)(() => {
|
|
3600
|
+
if (!chatOpen) return;
|
|
3601
|
+
function onKey(event) {
|
|
3602
|
+
if (event.key === "Escape") onAskAiOpenChange == null ? void 0 : onAskAiOpenChange(false);
|
|
3603
|
+
}
|
|
3604
|
+
window.addEventListener("keydown", onKey);
|
|
3605
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
3606
|
+
}, [chatOpen, onAskAiOpenChange]);
|
|
3607
|
+
function toggleAskAi() {
|
|
3608
|
+
if (askAiOpen) {
|
|
3609
|
+
onAskAiOpenChange == null ? void 0 : onAskAiOpenChange(false);
|
|
3610
|
+
return;
|
|
3611
|
+
}
|
|
3612
|
+
if (collapsed) onRequestExpand == null ? void 0 : onRequestExpand();
|
|
3613
|
+
onAskAiOpenChange == null ? void 0 : onAskAiOpenChange(true);
|
|
3614
|
+
}
|
|
3615
|
+
const askAiButton = /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
3616
|
+
"button",
|
|
3617
|
+
{
|
|
3618
|
+
type: "button",
|
|
3619
|
+
"data-test": "suite-ask-ai-toggle",
|
|
3620
|
+
"aria-pressed": askAiOpen,
|
|
3621
|
+
"aria-label": askAiOpen ? "Back to navigation" : "Shelly AI",
|
|
3622
|
+
onClick: toggleAskAi,
|
|
3623
|
+
className: cn(
|
|
3624
|
+
"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",
|
|
3625
|
+
askAiOpen ? "bg-ph-brand/10 text-ph-brand" : "text-ph-mutedtext hover:bg-ph-muted hover:text-ph-ink"
|
|
3626
|
+
),
|
|
3627
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_iconoir_react10.Sparks, { className: "h-4 w-4", "aria-hidden": true })
|
|
3628
|
+
}
|
|
3629
|
+
);
|
|
3630
|
+
if (chatOpen) {
|
|
3631
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
3632
|
+
"div",
|
|
3633
|
+
{
|
|
3634
|
+
"data-suite-chat-open": "",
|
|
3635
|
+
className: cn(
|
|
3636
|
+
"flex h-full w-full min-w-0 flex-col text-ph-ink",
|
|
3637
|
+
surface ? "bg-ph-surface" : "bg-ph-canvas",
|
|
3638
|
+
className
|
|
3639
|
+
),
|
|
3640
|
+
children: [
|
|
3641
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
3642
|
+
"div",
|
|
3643
|
+
{
|
|
3644
|
+
className: cn(
|
|
3645
|
+
"flex h-14 shrink-0 items-center gap-1 border-b border-ph-border px-2",
|
|
3646
|
+
surface ? "bg-ph-surface" : "bg-ph-canvas"
|
|
3647
|
+
),
|
|
3648
|
+
children: [
|
|
3649
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Tooltip, { content: "Back to navigation", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
3650
|
+
"button",
|
|
3651
|
+
{
|
|
3652
|
+
type: "button",
|
|
3653
|
+
"data-test": "suite-ask-ai-back",
|
|
3654
|
+
"aria-label": "Back to navigation",
|
|
3655
|
+
onClick: () => onAskAiOpenChange == null ? void 0 : onAskAiOpenChange(false),
|
|
3656
|
+
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",
|
|
3657
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_iconoir_react10.NavArrowLeft, { className: "h-4 w-4", "aria-hidden": true })
|
|
3658
|
+
}
|
|
3659
|
+
) }),
|
|
3660
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "min-w-0 flex-1 truncate text-sm font-semibold text-ph-ink", children: "Shelly AI" })
|
|
3661
|
+
]
|
|
3662
|
+
}
|
|
3663
|
+
),
|
|
3664
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "min-h-0 flex-1", children: askAi })
|
|
3665
|
+
]
|
|
3666
|
+
}
|
|
3667
|
+
);
|
|
3668
|
+
}
|
|
3669
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
3708
3670
|
"div",
|
|
3709
3671
|
{
|
|
3710
3672
|
className: cn(
|
|
@@ -3713,7 +3675,7 @@ function SuiteSidebar({
|
|
|
3713
3675
|
className
|
|
3714
3676
|
),
|
|
3715
3677
|
children: [
|
|
3716
|
-
/* @__PURE__ */ (0,
|
|
3678
|
+
appSwitcher || notificationBell ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
3717
3679
|
"div",
|
|
3718
3680
|
{
|
|
3719
3681
|
className: cn(
|
|
@@ -3722,27 +3684,46 @@ function SuiteSidebar({
|
|
|
3722
3684
|
collapsed ? "flex-col items-center gap-1 px-1 py-2" : "h-14 items-center justify-between gap-2 px-3"
|
|
3723
3685
|
),
|
|
3724
3686
|
children: [
|
|
3725
|
-
/* @__PURE__ */ (0,
|
|
3726
|
-
collapsed ? null : /* @__PURE__ */ (0,
|
|
3687
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: cn("min-w-0", collapsed ? "shrink-0" : "flex-1"), children: renderNode(appSwitcher, collapsed) }),
|
|
3688
|
+
collapsed ? null : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "shrink-0", children: renderNode(notificationBell, collapsed) })
|
|
3727
3689
|
]
|
|
3728
3690
|
}
|
|
3729
|
-
),
|
|
3730
|
-
/* @__PURE__ */ (0,
|
|
3691
|
+
) : null,
|
|
3692
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
3731
3693
|
"div",
|
|
3732
3694
|
{
|
|
3733
3695
|
className: cn(
|
|
3734
|
-
"flex min-h-0 flex-1 flex-col
|
|
3696
|
+
"flex min-h-0 flex-1 flex-col",
|
|
3735
3697
|
surface ? "bg-ph-surface" : "bg-ph-canvas",
|
|
3698
|
+
chatOpen ? "min-h-0" : "overflow-y-auto",
|
|
3736
3699
|
collapsed ? "px-1.5 py-2" : "p-2"
|
|
3737
3700
|
),
|
|
3738
3701
|
children: [
|
|
3739
|
-
/* @__PURE__ */ (0,
|
|
3740
|
-
|
|
3741
|
-
/* @__PURE__ */ (0,
|
|
3702
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: cn("mb-3 w-full shrink-0", collapsed && "flex justify-center"), children: renderNode(contextSwitcher, collapsed) }),
|
|
3703
|
+
chatOpen ? /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex min-h-0 flex-1 flex-col", children: [
|
|
3704
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "mb-2 flex shrink-0 items-center gap-1", children: [
|
|
3705
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
3706
|
+
"button",
|
|
3707
|
+
{
|
|
3708
|
+
type: "button",
|
|
3709
|
+
"data-test": "suite-ask-ai-back",
|
|
3710
|
+
onClick: () => onAskAiOpenChange == null ? void 0 : onAskAiOpenChange(false),
|
|
3711
|
+
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",
|
|
3712
|
+
children: [
|
|
3713
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_iconoir_react10.NavArrowLeft, { className: "h-4 w-4", "aria-hidden": true }),
|
|
3714
|
+
"Nav"
|
|
3715
|
+
]
|
|
3716
|
+
}
|
|
3717
|
+
),
|
|
3718
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "truncate text-sm font-semibold text-ph-ink", children: "Shelly AI" })
|
|
3719
|
+
] }),
|
|
3720
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "min-h-0 flex-1", children: askAi })
|
|
3721
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
|
|
3722
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("nav", { "aria-label": "Pages", className: "shrink-0 space-y-0.5", children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "space-y-0.5", children: navItems.map((item) => {
|
|
3742
3723
|
var _a;
|
|
3743
3724
|
const Icon = item.icon;
|
|
3744
3725
|
const active = Boolean(item.active);
|
|
3745
|
-
const link = /* @__PURE__ */ (0,
|
|
3726
|
+
const link = /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
3746
3727
|
import_link2.default,
|
|
3747
3728
|
{
|
|
3748
3729
|
href: item.href,
|
|
@@ -3756,7 +3737,7 @@ function SuiteSidebar({
|
|
|
3756
3737
|
collapsed ? "mx-auto size-11 shrink-0 justify-center gap-0 px-0 py-0" : "w-full px-2.5 py-2"
|
|
3757
3738
|
),
|
|
3758
3739
|
children: [
|
|
3759
|
-
/* @__PURE__ */ (0,
|
|
3740
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
3760
3741
|
"span",
|
|
3761
3742
|
{
|
|
3762
3743
|
className: cn(
|
|
@@ -3764,7 +3745,7 @@ function SuiteSidebar({
|
|
|
3764
3745
|
item.iconClassName
|
|
3765
3746
|
),
|
|
3766
3747
|
"aria-hidden": true,
|
|
3767
|
-
children: /* @__PURE__ */ (0,
|
|
3748
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
3768
3749
|
Icon,
|
|
3769
3750
|
{
|
|
3770
3751
|
className: "h-full w-full",
|
|
@@ -3773,7 +3754,7 @@ function SuiteSidebar({
|
|
|
3773
3754
|
)
|
|
3774
3755
|
}
|
|
3775
3756
|
),
|
|
3776
|
-
/* @__PURE__ */ (0,
|
|
3757
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
3777
3758
|
"span",
|
|
3778
3759
|
{
|
|
3779
3760
|
className: cn(
|
|
@@ -3784,26 +3765,26 @@ function SuiteSidebar({
|
|
|
3784
3765
|
children: item.label
|
|
3785
3766
|
}
|
|
3786
3767
|
),
|
|
3787
|
-
!collapsed && item.badge ? /* @__PURE__ */ (0,
|
|
3768
|
+
!collapsed && item.badge ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("span", { className: "relative ml-auto shrink-0", children: item.badge }) : null
|
|
3788
3769
|
]
|
|
3789
3770
|
},
|
|
3790
3771
|
item.label
|
|
3791
3772
|
);
|
|
3792
|
-
return collapsed ? /* @__PURE__ */ (0,
|
|
3793
|
-
}) })
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
)
|
|
3773
|
+
return collapsed ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Tooltip, { content: item.label, side: "right", children: link }, item.label) : link;
|
|
3774
|
+
}) }) }),
|
|
3775
|
+
secondaryNav ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
3776
|
+
"div",
|
|
3777
|
+
{
|
|
3778
|
+
className: "min-h-0 flex-1",
|
|
3779
|
+
"data-test": "suite-sidebar-secondary-nav",
|
|
3780
|
+
children: secondaryNav
|
|
3781
|
+
}
|
|
3782
|
+
) : null
|
|
3783
|
+
] })
|
|
3803
3784
|
]
|
|
3804
3785
|
}
|
|
3805
3786
|
),
|
|
3806
|
-
/* @__PURE__ */ (0,
|
|
3787
|
+
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
3807
3788
|
"div",
|
|
3808
3789
|
{
|
|
3809
3790
|
className: cn(
|
|
@@ -3811,16 +3792,23 @@ function SuiteSidebar({
|
|
|
3811
3792
|
surface ? "bg-ph-surface" : "bg-ph-canvas",
|
|
3812
3793
|
collapsed ? "p-1.5" : "p-3"
|
|
3813
3794
|
),
|
|
3814
|
-
children: /* @__PURE__ */ (0,
|
|
3795
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
|
|
3815
3796
|
"div",
|
|
3816
3797
|
{
|
|
3817
3798
|
className: cn(
|
|
3818
3799
|
"flex items-center gap-2",
|
|
3819
|
-
collapsed ? "flex-col items-center justify-center [
|
|
3800
|
+
collapsed ? "flex-col items-center justify-center [&>div]:w-auto" : "w-full min-w-0"
|
|
3820
3801
|
),
|
|
3821
3802
|
children: [
|
|
3822
3803
|
renderNode(userMenu, collapsed),
|
|
3823
|
-
|
|
3804
|
+
showAskAi ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
3805
|
+
"div",
|
|
3806
|
+
{
|
|
3807
|
+
className: cn("shrink-0", collapsed ? "mt-2" : "ml-auto"),
|
|
3808
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Tooltip, { content: "Shelly AI", side: collapsed ? "right" : "top", children: askAiButton })
|
|
3809
|
+
}
|
|
3810
|
+
) : footerExtras ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: cn("shrink-0", collapsed ? "mt-2" : "ml-auto"), children: renderNode(footerExtras, collapsed) }) : null,
|
|
3811
|
+
showAskAi && footerExtras ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: cn("shrink-0", collapsed && "mt-2"), children: renderNode(footerExtras, collapsed) }) : null
|
|
3824
3812
|
]
|
|
3825
3813
|
}
|
|
3826
3814
|
)
|
|
@@ -3832,7 +3820,7 @@ function SuiteSidebar({
|
|
|
3832
3820
|
}
|
|
3833
3821
|
|
|
3834
3822
|
// src/suite/components/suite-app-layout.tsx
|
|
3835
|
-
var
|
|
3823
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
3836
3824
|
function SuiteAppLayout({
|
|
3837
3825
|
sidebar,
|
|
3838
3826
|
children,
|
|
@@ -3846,7 +3834,7 @@ function SuiteAppLayout({
|
|
|
3846
3834
|
onResetWidth,
|
|
3847
3835
|
className
|
|
3848
3836
|
}) {
|
|
3849
|
-
return /* @__PURE__ */ (0,
|
|
3837
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
3850
3838
|
"div",
|
|
3851
3839
|
{
|
|
3852
3840
|
"data-test": "app-shell",
|
|
@@ -3855,15 +3843,15 @@ function SuiteAppLayout({
|
|
|
3855
3843
|
className
|
|
3856
3844
|
),
|
|
3857
3845
|
children: [
|
|
3858
|
-
/* @__PURE__ */ (0,
|
|
3846
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
|
|
3859
3847
|
"aside",
|
|
3860
3848
|
{
|
|
3861
3849
|
className: "relative hidden shrink-0 flex-col overflow-visible border-r border-ph-border ease-out lg:flex",
|
|
3862
3850
|
style: { width: `${sidebarWidth}px` },
|
|
3863
3851
|
"data-collapsed": collapsed ? "true" : "false",
|
|
3864
3852
|
children: [
|
|
3865
|
-
sidebar,
|
|
3866
|
-
onStartResize ? /* @__PURE__ */ (0,
|
|
3853
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "relative z-0 h-full min-h-0 isolate", children: sidebar }),
|
|
3854
|
+
onStartResize ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3867
3855
|
"div",
|
|
3868
3856
|
{
|
|
3869
3857
|
role: "separator",
|
|
@@ -3885,15 +3873,15 @@ function SuiteAppLayout({
|
|
|
3885
3873
|
onResizeBy == null ? void 0 : onResizeBy(16);
|
|
3886
3874
|
}
|
|
3887
3875
|
},
|
|
3888
|
-
className: "absolute inset-y-0
|
|
3876
|
+
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)]"
|
|
3889
3877
|
}
|
|
3890
3878
|
) : null
|
|
3891
3879
|
]
|
|
3892
3880
|
}
|
|
3893
3881
|
),
|
|
3894
|
-
/* @__PURE__ */ (0,
|
|
3895
|
-
mobileHeader ? /* @__PURE__ */ (0,
|
|
3896
|
-
/* @__PURE__ */ (0,
|
|
3882
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex min-h-0 min-w-0 flex-1 flex-col", children: [
|
|
3883
|
+
mobileHeader ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "shrink-0 lg:hidden", children: mobileHeader }) : null,
|
|
3884
|
+
/* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3897
3885
|
"main",
|
|
3898
3886
|
{
|
|
3899
3887
|
id: "main-content",
|
|
@@ -3907,7 +3895,7 @@ function SuiteAppLayout({
|
|
|
3907
3895
|
children
|
|
3908
3896
|
}
|
|
3909
3897
|
),
|
|
3910
|
-
bottomNav ? /* @__PURE__ */ (0,
|
|
3898
|
+
bottomNav ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "shrink-0 lg:hidden", children: bottomNav }) : null
|
|
3911
3899
|
] })
|
|
3912
3900
|
]
|
|
3913
3901
|
}
|
|
@@ -3961,6 +3949,7 @@ function SuiteAppLayout({
|
|
|
3961
3949
|
SuiteThemeProvider,
|
|
3962
3950
|
SuiteToolbar,
|
|
3963
3951
|
SuiteUserMenu,
|
|
3952
|
+
SuiteWorkspaceSwitcher,
|
|
3964
3953
|
TodayAskAiCard,
|
|
3965
3954
|
TodayCalibrating,
|
|
3966
3955
|
TodayEmptyAction,
|
|
@@ -3976,11 +3965,14 @@ function SuiteAppLayout({
|
|
|
3976
3965
|
appSwitcherMarkClass,
|
|
3977
3966
|
appSwitcherMenuItemClass,
|
|
3978
3967
|
appSwitcherTriggerClass,
|
|
3968
|
+
classifySuiteHref,
|
|
3979
3969
|
cn,
|
|
3970
|
+
consumePendingAskAiPrompt,
|
|
3980
3971
|
getTodayGreeting,
|
|
3981
3972
|
m,
|
|
3982
3973
|
openSuiteAskAi,
|
|
3983
3974
|
resolveSuiteNotificationHref,
|
|
3975
|
+
sidebarColumnWidth,
|
|
3984
3976
|
sourceToSuiteApp,
|
|
3985
3977
|
suiteAppBaseUrl,
|
|
3986
3978
|
suiteAppLabel,
|