@petrarca/sonnet-shell 0.2.0 → 0.4.0
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/README.md +241 -6
- package/dist/index.d.ts +277 -32
- package/dist/index.js +797 -287
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
// src/AppShell.tsx
|
|
2
2
|
import {
|
|
3
|
-
useState,
|
|
3
|
+
useState as useState2,
|
|
4
4
|
useEffect as useEffect3,
|
|
5
5
|
useCallback as useCallback2,
|
|
6
6
|
useRef as useRef2,
|
|
7
|
-
useMemo as
|
|
7
|
+
useMemo as useMemo5
|
|
8
8
|
} from "react";
|
|
9
|
+
import { useResizablePanel as useResizablePanel2 } from "@petrarca/sonnet-core/hooks";
|
|
9
10
|
import { Outlet, useLocation as useLocation2, useNavigate as useNavigate2 } from "react-router-dom";
|
|
10
11
|
import { TooltipProvider } from "@petrarca/sonnet-ui";
|
|
11
12
|
import { ScrollArea as ScrollArea2 } from "@petrarca/sonnet-ui";
|
|
@@ -68,82 +69,71 @@ function TopBar({ children }) {
|
|
|
68
69
|
return /* @__PURE__ */ jsx2("header", { className: "h-12 shrink-0 border-b border-border flex items-center justify-between px-3 bg-background z-20", children });
|
|
69
70
|
}
|
|
70
71
|
|
|
71
|
-
// src/
|
|
72
|
-
import {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
import { Tooltip, TooltipContent, TooltipTrigger } from "@petrarca/sonnet-ui";
|
|
76
|
-
|
|
77
|
-
// src/shellModules.ts
|
|
78
|
-
import { createContext, useContext } from "react";
|
|
79
|
-
var ShellModulesContext = createContext(null);
|
|
80
|
-
function useShellModules() {
|
|
81
|
-
const registry = useContext(ShellModulesContext);
|
|
82
|
-
if (!registry) {
|
|
83
|
-
throw new Error("useShellModules must be used within an AppShell");
|
|
84
|
-
}
|
|
85
|
-
return registry;
|
|
72
|
+
// src/ShellFooter.tsx
|
|
73
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
74
|
+
function ShellFooter({ children }) {
|
|
75
|
+
return /* @__PURE__ */ jsx3("footer", { className: "h-8 shrink-0 border-t border-border flex items-center justify-between px-3 bg-background text-[11px] text-muted-foreground z-20", children });
|
|
86
76
|
}
|
|
87
77
|
|
|
78
|
+
// src/ShellRail.tsx
|
|
79
|
+
import { useMemo as useMemo3 } from "react";
|
|
80
|
+
|
|
88
81
|
// src/IconRail.tsx
|
|
89
|
-
import {
|
|
82
|
+
import { cn } from "@petrarca/sonnet-core";
|
|
83
|
+
import { Button as Button2, Separator } from "@petrarca/sonnet-ui";
|
|
84
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "@petrarca/sonnet-ui";
|
|
85
|
+
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
90
86
|
function IconRail({
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
onServiceSelect
|
|
87
|
+
children,
|
|
88
|
+
className
|
|
94
89
|
}) {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
service.id
|
|
106
|
-
)) }),
|
|
107
|
-
/* @__PURE__ */ jsx3(Separator, { className: "w-6 my-1" }),
|
|
108
|
-
/* @__PURE__ */ jsx3("div", { className: "flex flex-col items-center gap-1", children: bottomModules.map((service) => /* @__PURE__ */ jsx3(
|
|
109
|
-
RailIcon,
|
|
110
|
-
{
|
|
111
|
-
service,
|
|
112
|
-
isActive: isActive(service.id),
|
|
113
|
-
onClick: () => onServiceSelect(service.id)
|
|
114
|
-
},
|
|
115
|
-
service.id
|
|
116
|
-
)) })
|
|
117
|
-
] });
|
|
90
|
+
return /* @__PURE__ */ jsx4(
|
|
91
|
+
"nav",
|
|
92
|
+
{
|
|
93
|
+
className: cn(
|
|
94
|
+
"w-14 shrink-0 border-r bg-muted flex flex-col items-center py-2 gap-1",
|
|
95
|
+
className
|
|
96
|
+
),
|
|
97
|
+
children
|
|
98
|
+
}
|
|
99
|
+
);
|
|
118
100
|
}
|
|
119
|
-
function RailIcon({
|
|
120
|
-
|
|
101
|
+
function RailIcon({
|
|
102
|
+
icon: Icon,
|
|
103
|
+
label,
|
|
104
|
+
active = false,
|
|
105
|
+
onClick,
|
|
106
|
+
disabled = false,
|
|
107
|
+
tooltip
|
|
108
|
+
}) {
|
|
121
109
|
return /* @__PURE__ */ jsxs2(Tooltip, { delayDuration: 0, children: [
|
|
122
|
-
/* @__PURE__ */
|
|
110
|
+
/* @__PURE__ */ jsx4(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs2(
|
|
123
111
|
Button2,
|
|
124
112
|
{
|
|
125
113
|
variant: "ghost",
|
|
126
114
|
size: "compact",
|
|
127
|
-
|
|
115
|
+
"aria-disabled": disabled || void 0,
|
|
116
|
+
onClick: disabled ? void 0 : onClick,
|
|
128
117
|
className: cn(
|
|
129
118
|
"h-10 w-10 rounded-lg transition-colors",
|
|
130
|
-
|
|
119
|
+
disabled ? "text-muted-foreground/40 cursor-default hover:bg-transparent" : active ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground hover:bg-muted-foreground/10"
|
|
131
120
|
),
|
|
132
121
|
children: [
|
|
133
|
-
/* @__PURE__ */
|
|
134
|
-
/* @__PURE__ */
|
|
122
|
+
/* @__PURE__ */ jsx4(Icon, { className: "h-5 w-5" }),
|
|
123
|
+
/* @__PURE__ */ jsx4("span", { className: "sr-only", children: label })
|
|
135
124
|
]
|
|
136
125
|
}
|
|
137
126
|
) }),
|
|
138
|
-
/* @__PURE__ */
|
|
127
|
+
/* @__PURE__ */ jsx4(TooltipContent, { side: "right", sideOffset: 8, children: tooltip ?? label })
|
|
139
128
|
] });
|
|
140
129
|
}
|
|
130
|
+
function RailSeparator() {
|
|
131
|
+
return /* @__PURE__ */ jsx4(Separator, { className: "w-6 my-1" });
|
|
132
|
+
}
|
|
141
133
|
|
|
142
134
|
// src/SubNavPanel.tsx
|
|
143
135
|
import { useMemo as useMemo2 } from "react";
|
|
144
|
-
import { useLocation, Link } from "react-router-dom";
|
|
145
136
|
import { ChevronsLeft, ChevronsRight } from "lucide-react";
|
|
146
|
-
import { cn as cn2 } from "@petrarca/sonnet-core";
|
|
147
137
|
import { ScrollArea } from "@petrarca/sonnet-ui";
|
|
148
138
|
import { Tooltip as Tooltip2, TooltipContent as TooltipContent2, TooltipTrigger as TooltipTrigger2 } from "@petrarca/sonnet-ui";
|
|
149
139
|
|
|
@@ -413,6 +403,17 @@ var events = {
|
|
|
413
403
|
}
|
|
414
404
|
};
|
|
415
405
|
|
|
406
|
+
// src/shellModules.ts
|
|
407
|
+
import { createContext, useContext } from "react";
|
|
408
|
+
var ShellModulesContext = createContext(null);
|
|
409
|
+
function useShellModules() {
|
|
410
|
+
const registry = useContext(ShellModulesContext);
|
|
411
|
+
if (!registry) {
|
|
412
|
+
throw new Error("useShellModules must be used within an AppShell");
|
|
413
|
+
}
|
|
414
|
+
return registry;
|
|
415
|
+
}
|
|
416
|
+
|
|
416
417
|
// src/hooks.ts
|
|
417
418
|
function useExtensionPoint(name) {
|
|
418
419
|
const { getExtensionPoint } = useShellModules();
|
|
@@ -430,8 +431,145 @@ function useShellEvent(key, handler) {
|
|
|
430
431
|
}, [key]);
|
|
431
432
|
}
|
|
432
433
|
|
|
434
|
+
// src/SidebarGroup.tsx
|
|
435
|
+
import { useState } from "react";
|
|
436
|
+
import { ChevronDown } from "lucide-react";
|
|
437
|
+
import { cn as cn2 } from "@petrarca/sonnet-core";
|
|
438
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
439
|
+
function GroupHeading({
|
|
440
|
+
heading,
|
|
441
|
+
canCollapse,
|
|
442
|
+
open,
|
|
443
|
+
onToggle
|
|
444
|
+
}) {
|
|
445
|
+
return /* @__PURE__ */ jsxs3(
|
|
446
|
+
"button",
|
|
447
|
+
{
|
|
448
|
+
type: "button",
|
|
449
|
+
onClick: canCollapse ? onToggle : void 0,
|
|
450
|
+
className: cn2(
|
|
451
|
+
"flex w-full items-center gap-1 px-2 py-1.5",
|
|
452
|
+
"text-[11px] font-semibold uppercase tracking-widest text-muted-foreground/70",
|
|
453
|
+
canCollapse ? "hover:text-foreground cursor-pointer" : "cursor-default"
|
|
454
|
+
),
|
|
455
|
+
children: [
|
|
456
|
+
canCollapse && /* @__PURE__ */ jsx5(
|
|
457
|
+
ChevronDown,
|
|
458
|
+
{
|
|
459
|
+
className: cn2("h-3 w-3 transition-transform", !open && "-rotate-90")
|
|
460
|
+
}
|
|
461
|
+
),
|
|
462
|
+
/* @__PURE__ */ jsx5("span", { children: heading })
|
|
463
|
+
]
|
|
464
|
+
}
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
function SidebarGroup({
|
|
468
|
+
heading,
|
|
469
|
+
collapsible = false,
|
|
470
|
+
defaultOpen = true,
|
|
471
|
+
separator = false,
|
|
472
|
+
children
|
|
473
|
+
}) {
|
|
474
|
+
const [open, setOpen] = useState(defaultOpen);
|
|
475
|
+
const canCollapse = collapsible && !!heading;
|
|
476
|
+
return /* @__PURE__ */ jsxs3("div", { className: cn2(separator && "border-b border-border pb-2"), children: [
|
|
477
|
+
heading && /* @__PURE__ */ jsx5(
|
|
478
|
+
GroupHeading,
|
|
479
|
+
{
|
|
480
|
+
heading,
|
|
481
|
+
canCollapse,
|
|
482
|
+
open,
|
|
483
|
+
onToggle: () => setOpen((v) => !v)
|
|
484
|
+
}
|
|
485
|
+
),
|
|
486
|
+
(!canCollapse || open) && /* @__PURE__ */ jsx5("ul", { className: "space-y-0.5", children })
|
|
487
|
+
] });
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// src/SidebarItem.tsx
|
|
491
|
+
import { Link, useLocation } from "react-router-dom";
|
|
492
|
+
import { ChevronRight } from "lucide-react";
|
|
493
|
+
import { cn as cn3 } from "@petrarca/sonnet-core";
|
|
494
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
495
|
+
function ItemTrailing({
|
|
496
|
+
badge,
|
|
497
|
+
expandable,
|
|
498
|
+
expanded,
|
|
499
|
+
onToggle
|
|
500
|
+
}) {
|
|
501
|
+
if (badge != null) {
|
|
502
|
+
return /* @__PURE__ */ jsx6("span", { className: "inline-flex items-center rounded-full bg-muted px-1.5 h-[18px] text-[10px] tabular-nums text-muted-foreground", children: badge });
|
|
503
|
+
}
|
|
504
|
+
if (expandable) {
|
|
505
|
+
const handleClick = (e) => {
|
|
506
|
+
e.preventDefault();
|
|
507
|
+
e.stopPropagation();
|
|
508
|
+
onToggle?.();
|
|
509
|
+
};
|
|
510
|
+
return /* @__PURE__ */ jsx6(
|
|
511
|
+
"button",
|
|
512
|
+
{
|
|
513
|
+
type: "button",
|
|
514
|
+
onClick: handleClick,
|
|
515
|
+
className: "p-0.5 text-muted-foreground hover:text-foreground",
|
|
516
|
+
children: /* @__PURE__ */ jsx6(
|
|
517
|
+
ChevronRight,
|
|
518
|
+
{
|
|
519
|
+
className: cn3(
|
|
520
|
+
"h-3 w-3 transition-transform",
|
|
521
|
+
expanded && "rotate-90"
|
|
522
|
+
)
|
|
523
|
+
}
|
|
524
|
+
)
|
|
525
|
+
}
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
return null;
|
|
529
|
+
}
|
|
530
|
+
function SidebarItem({
|
|
531
|
+
icon: Icon,
|
|
532
|
+
label,
|
|
533
|
+
path,
|
|
534
|
+
badge,
|
|
535
|
+
indent = 0,
|
|
536
|
+
expandable = false,
|
|
537
|
+
expanded = false,
|
|
538
|
+
onToggle,
|
|
539
|
+
onClick
|
|
540
|
+
}) {
|
|
541
|
+
const { pathname } = useLocation();
|
|
542
|
+
const isActive = pathname === path;
|
|
543
|
+
const style = indent > 0 ? { paddingLeft: `${indent * 16 + 8}px` } : void 0;
|
|
544
|
+
return /* @__PURE__ */ jsx6("li", { children: /* @__PURE__ */ jsxs4(
|
|
545
|
+
Link,
|
|
546
|
+
{
|
|
547
|
+
to: path,
|
|
548
|
+
onClick,
|
|
549
|
+
style,
|
|
550
|
+
className: cn3(
|
|
551
|
+
"flex items-center gap-2 rounded px-2 py-1.5 text-[13px] font-medium transition-colors select-none",
|
|
552
|
+
isActive ? "bg-accent text-accent-foreground" : "text-muted-foreground hover:text-foreground hover:bg-accent/50"
|
|
553
|
+
),
|
|
554
|
+
children: [
|
|
555
|
+
Icon && /* @__PURE__ */ jsx6(Icon, { className: "h-4 w-4 shrink-0" }),
|
|
556
|
+
/* @__PURE__ */ jsx6("span", { className: "min-w-0 flex-1 truncate", children: label }),
|
|
557
|
+
/* @__PURE__ */ jsx6(
|
|
558
|
+
ItemTrailing,
|
|
559
|
+
{
|
|
560
|
+
badge,
|
|
561
|
+
expandable,
|
|
562
|
+
expanded,
|
|
563
|
+
onToggle
|
|
564
|
+
}
|
|
565
|
+
)
|
|
566
|
+
]
|
|
567
|
+
}
|
|
568
|
+
) });
|
|
569
|
+
}
|
|
570
|
+
|
|
433
571
|
// src/SubNavPanel.tsx
|
|
434
|
-
import { jsx as
|
|
572
|
+
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
435
573
|
function useMergedNavigation(service) {
|
|
436
574
|
const contributions = useExtensionPoint(`${service.id}.nav`);
|
|
437
575
|
return useMemo2(() => {
|
|
@@ -452,99 +590,249 @@ function SubNavPanel({
|
|
|
452
590
|
collapsed,
|
|
453
591
|
onToggleCollapse
|
|
454
592
|
}) {
|
|
455
|
-
const { pathname } = useLocation();
|
|
456
593
|
const mergedNavigation = useMergedNavigation(service);
|
|
457
594
|
if (collapsed) {
|
|
458
|
-
return /* @__PURE__ */
|
|
459
|
-
/* @__PURE__ */
|
|
595
|
+
return /* @__PURE__ */ jsx7("aside", { className: "shrink-0 border-r bg-background flex flex-col items-center pt-2.5", children: /* @__PURE__ */ jsxs5(Tooltip2, { children: [
|
|
596
|
+
/* @__PURE__ */ jsx7(TooltipTrigger2, { asChild: true, children: /* @__PURE__ */ jsx7(
|
|
460
597
|
"button",
|
|
461
598
|
{
|
|
599
|
+
type: "button",
|
|
462
600
|
className: "text-muted-foreground/50 hover:text-muted-foreground transition-colors p-1",
|
|
463
601
|
onClick: onToggleCollapse,
|
|
464
|
-
children: /* @__PURE__ */
|
|
602
|
+
children: /* @__PURE__ */ jsx7(ChevronsRight, { className: "h-4 w-4" })
|
|
465
603
|
}
|
|
466
604
|
) }),
|
|
467
|
-
/* @__PURE__ */
|
|
605
|
+
/* @__PURE__ */ jsx7(TooltipContent2, { side: "right", children: "Expand navigation" })
|
|
468
606
|
] }) });
|
|
469
607
|
}
|
|
470
|
-
return /* @__PURE__ */
|
|
471
|
-
/* @__PURE__ */
|
|
472
|
-
/* @__PURE__ */
|
|
473
|
-
/* @__PURE__ */
|
|
474
|
-
/* @__PURE__ */
|
|
608
|
+
return /* @__PURE__ */ jsxs5("aside", { className: "w-52 shrink-0 border-r bg-background flex flex-col", children: [
|
|
609
|
+
/* @__PURE__ */ jsxs5("div", { className: "h-10 shrink-0 flex items-center justify-between px-4", children: [
|
|
610
|
+
/* @__PURE__ */ jsx7("span", { className: "text-sm font-semibold text-foreground", children: service.label }),
|
|
611
|
+
/* @__PURE__ */ jsxs5(Tooltip2, { children: [
|
|
612
|
+
/* @__PURE__ */ jsx7(TooltipTrigger2, { asChild: true, children: /* @__PURE__ */ jsx7(
|
|
475
613
|
"button",
|
|
476
614
|
{
|
|
615
|
+
type: "button",
|
|
477
616
|
className: "text-muted-foreground/40 hover:text-muted-foreground transition-colors p-0.5",
|
|
478
617
|
onClick: onToggleCollapse,
|
|
479
|
-
children: /* @__PURE__ */
|
|
618
|
+
children: /* @__PURE__ */ jsx7(ChevronsLeft, { className: "h-3.5 w-3.5" })
|
|
480
619
|
}
|
|
481
620
|
) }),
|
|
482
|
-
/* @__PURE__ */
|
|
621
|
+
/* @__PURE__ */ jsx7(TooltipContent2, { side: "right", children: "Collapse navigation" })
|
|
483
622
|
] })
|
|
484
623
|
] }),
|
|
485
|
-
/* @__PURE__ */
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
624
|
+
/* @__PURE__ */ jsx7(ScrollArea, { className: "flex-1", children: /* @__PURE__ */ jsx7("nav", { className: "px-1.5 pb-4 space-y-2", children: mergedNavigation.map((group) => /* @__PURE__ */ jsx7(
|
|
625
|
+
SidebarGroup,
|
|
626
|
+
{
|
|
627
|
+
heading: group.heading,
|
|
628
|
+
collapsible: group.collapsible,
|
|
629
|
+
children: group.links.map((link) => /* @__PURE__ */ jsx7(
|
|
630
|
+
SidebarItem,
|
|
491
631
|
{
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
632
|
+
label: link.label,
|
|
633
|
+
path: link.path,
|
|
634
|
+
badge: link.badge
|
|
635
|
+
},
|
|
636
|
+
link.path
|
|
637
|
+
))
|
|
638
|
+
},
|
|
639
|
+
group.id
|
|
640
|
+
)) }) })
|
|
641
|
+
] });
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
// src/shellNavigation.ts
|
|
645
|
+
import { createContext as createContext2, useContext as useContext2 } from "react";
|
|
646
|
+
var ShellNavigationContext = createContext2(null);
|
|
647
|
+
function useShellNavigation() {
|
|
648
|
+
const ctx = useContext2(ShellNavigationContext);
|
|
649
|
+
if (!ctx) {
|
|
650
|
+
throw new Error("useShellNavigation must be used within AppShell");
|
|
651
|
+
}
|
|
652
|
+
return ctx;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
// src/shellConfig.ts
|
|
656
|
+
import { createContext as createContext3, useContext as useContext3 } from "react";
|
|
657
|
+
var ShellConfigContext = createContext3(null);
|
|
658
|
+
function useShellConfig() {
|
|
659
|
+
const config = useContext3(ShellConfigContext);
|
|
660
|
+
if (!config) {
|
|
661
|
+
throw new Error("useShellConfig must be used within a ShellConfigProvider");
|
|
662
|
+
}
|
|
663
|
+
return config;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
// src/capabilities.ts
|
|
667
|
+
import { warnLog as warnLog3 } from "@petrarca/sonnet-core";
|
|
668
|
+
var DEFAULT_CAPABILITY_POLICY = {
|
|
669
|
+
"missing-state": { rail: "disabled", command: "disabled", route: "redirect" },
|
|
670
|
+
"not-authorized": { rail: "hidden", command: "hidden", route: "redirect" },
|
|
671
|
+
"not-authorized-soft": {
|
|
672
|
+
rail: "disabled",
|
|
673
|
+
command: "disabled",
|
|
674
|
+
route: "redirect"
|
|
675
|
+
},
|
|
676
|
+
"feature-off": { rail: "hidden", command: "disabled", route: "redirect" },
|
|
677
|
+
error: { rail: "hidden", command: "hidden", route: "redirect" }
|
|
678
|
+
};
|
|
679
|
+
var EFFECT_RANK = {
|
|
680
|
+
hidden: 3,
|
|
681
|
+
redirect: 2,
|
|
682
|
+
disabled: 1,
|
|
683
|
+
visible: 0
|
|
684
|
+
};
|
|
685
|
+
function resolveCapabilityPolicy(override) {
|
|
686
|
+
if (!override) return DEFAULT_CAPABILITY_POLICY;
|
|
687
|
+
const merged = {};
|
|
688
|
+
for (const kind of Object.keys(DEFAULT_CAPABILITY_POLICY)) {
|
|
689
|
+
merged[kind] = {
|
|
690
|
+
...DEFAULT_CAPABILITY_POLICY[kind],
|
|
691
|
+
...override[kind] ?? {}
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
return merged;
|
|
695
|
+
}
|
|
696
|
+
function foldUnmet(effect, resultReason, acc) {
|
|
697
|
+
const rank = EFFECT_RANK[effect];
|
|
698
|
+
const worstRank = EFFECT_RANK[acc.effect];
|
|
699
|
+
if (rank > worstRank) {
|
|
700
|
+
return { effect, reason: resultReason };
|
|
701
|
+
}
|
|
702
|
+
if (rank === worstRank && !acc.reason && resultReason) {
|
|
703
|
+
return { effect: acc.effect, reason: resultReason };
|
|
704
|
+
}
|
|
705
|
+
return acc;
|
|
706
|
+
}
|
|
707
|
+
function evaluateModule(module, surface, resolve, policy) {
|
|
708
|
+
const capabilities = module.requires;
|
|
709
|
+
if (!capabilities || capabilities.length === 0) return { effect: "visible" };
|
|
710
|
+
if (!resolve) return { effect: "visible" };
|
|
711
|
+
let acc = { effect: "visible" };
|
|
712
|
+
for (const capability of capabilities) {
|
|
713
|
+
const result = resolve(capability);
|
|
714
|
+
if (result.met) continue;
|
|
715
|
+
const kind = result.kind ?? "error";
|
|
716
|
+
if (kind === "error") {
|
|
717
|
+
warnLog3(
|
|
718
|
+
`[capabilities] unmet capability "${capability}" resolved to kind "error" (fail-closed)`
|
|
719
|
+
);
|
|
720
|
+
}
|
|
721
|
+
acc = foldUnmet(policy[kind][surface], result.reason, acc);
|
|
722
|
+
}
|
|
723
|
+
return acc;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
// src/ShellRail.tsx
|
|
727
|
+
import { Fragment, jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
728
|
+
function ShellRail() {
|
|
729
|
+
const { mainModules, bottomModules } = useShellModules();
|
|
730
|
+
const { resolveCapability, capabilityPolicy } = useShellConfig();
|
|
731
|
+
const {
|
|
732
|
+
activeService,
|
|
733
|
+
sidePaneModuleId,
|
|
734
|
+
subNavCollapsed,
|
|
735
|
+
onToggleSubNav,
|
|
736
|
+
onServiceSelect
|
|
737
|
+
} = useShellNavigation();
|
|
738
|
+
const isActive = (id) => activeService?.id === id || sidePaneModuleId === id;
|
|
739
|
+
const policy = useMemo3(
|
|
740
|
+
() => resolveCapabilityPolicy(capabilityPolicy),
|
|
741
|
+
[capabilityPolicy]
|
|
742
|
+
);
|
|
743
|
+
const renderModule = (service) => {
|
|
744
|
+
const { effect, reason } = evaluateModule(
|
|
745
|
+
service,
|
|
746
|
+
"rail",
|
|
747
|
+
resolveCapability,
|
|
748
|
+
policy
|
|
749
|
+
);
|
|
750
|
+
if (effect === "hidden" || effect === "redirect") return null;
|
|
751
|
+
const disabled = effect === "disabled";
|
|
752
|
+
return /* @__PURE__ */ jsx8(
|
|
753
|
+
RailIcon,
|
|
754
|
+
{
|
|
755
|
+
icon: service.icon,
|
|
756
|
+
label: service.label,
|
|
757
|
+
active: isActive(service.id),
|
|
758
|
+
onClick: () => onServiceSelect(service.id),
|
|
759
|
+
disabled,
|
|
760
|
+
tooltip: disabled && reason ? `${service.label} \u2014 ${reason}` : void 0
|
|
761
|
+
},
|
|
762
|
+
service.id
|
|
763
|
+
);
|
|
764
|
+
};
|
|
765
|
+
return /* @__PURE__ */ jsxs6(Fragment, { children: [
|
|
766
|
+
/* @__PURE__ */ jsxs6(IconRail, { children: [
|
|
767
|
+
/* @__PURE__ */ jsx8("div", { className: "flex-1 flex flex-col items-center gap-1 overflow-y-auto", children: mainModules.map(renderModule) }),
|
|
768
|
+
/* @__PURE__ */ jsx8(RailSeparator, {}),
|
|
769
|
+
/* @__PURE__ */ jsx8("div", { className: "flex flex-col items-center gap-1", children: bottomModules.map(renderModule) })
|
|
770
|
+
] }),
|
|
771
|
+
activeService && activeService.navigation.length > 0 && /* @__PURE__ */ jsx8(
|
|
772
|
+
SubNavPanel,
|
|
773
|
+
{
|
|
774
|
+
service: activeService,
|
|
775
|
+
collapsed: subNavCollapsed,
|
|
776
|
+
onToggleCollapse: onToggleSubNav
|
|
777
|
+
}
|
|
778
|
+
)
|
|
502
779
|
] });
|
|
503
780
|
}
|
|
504
781
|
|
|
505
782
|
// src/SidePane.tsx
|
|
506
783
|
import { X } from "lucide-react";
|
|
507
|
-
import { cn as
|
|
784
|
+
import { cn as cn5 } from "@petrarca/sonnet-core";
|
|
508
785
|
import { useResizablePanel } from "@petrarca/sonnet-core/hooks";
|
|
509
786
|
|
|
510
787
|
// src/sidePaneState.ts
|
|
511
|
-
import { createContext as
|
|
512
|
-
var SidePaneContext =
|
|
788
|
+
import { createContext as createContext4, useContext as useContext4 } from "react";
|
|
789
|
+
var SidePaneContext = createContext4(null);
|
|
513
790
|
function useSidePaneState() {
|
|
514
|
-
const ctx =
|
|
791
|
+
const ctx = useContext4(SidePaneContext);
|
|
515
792
|
if (!ctx) {
|
|
516
793
|
throw new Error("useSidePaneState must be used within an AppShell");
|
|
517
794
|
}
|
|
518
795
|
return ctx;
|
|
519
796
|
}
|
|
520
797
|
|
|
521
|
-
// src/
|
|
522
|
-
import {
|
|
798
|
+
// src/DragHandle.tsx
|
|
799
|
+
import { cn as cn4 } from "@petrarca/sonnet-core";
|
|
800
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
523
801
|
function DragHandle({
|
|
802
|
+
edge,
|
|
524
803
|
separatorProps,
|
|
525
804
|
onPointerDown,
|
|
526
805
|
onDoubleClick
|
|
527
806
|
}) {
|
|
528
|
-
return /* @__PURE__ */
|
|
807
|
+
return /* @__PURE__ */ jsx9(
|
|
529
808
|
"div",
|
|
530
809
|
{
|
|
531
810
|
...separatorProps,
|
|
532
811
|
onPointerDown,
|
|
533
812
|
onDoubleClick,
|
|
534
|
-
className:
|
|
535
|
-
|
|
536
|
-
"
|
|
813
|
+
className: cn4(
|
|
814
|
+
// 8px invisible hit area; visual feedback only via the before pseudo-element.
|
|
815
|
+
"absolute top-0 h-full w-2 cursor-col-resize",
|
|
816
|
+
edge === "right" ? "right-0" : "left-0",
|
|
817
|
+
// Centered line: invisible at rest, 2px on hover, 4px while dragging.
|
|
818
|
+
"before:absolute before:inset-y-0 before:left-1/2 before:-translate-x-1/2",
|
|
819
|
+
"before:w-0 before:transition-all before:duration-150",
|
|
820
|
+
"hover:before:w-0.5 hover:before:bg-primary/60",
|
|
821
|
+
"active:before:w-1 active:before:bg-primary/80"
|
|
537
822
|
)
|
|
538
823
|
}
|
|
539
824
|
);
|
|
540
825
|
}
|
|
826
|
+
|
|
827
|
+
// src/SidePane.tsx
|
|
828
|
+
import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
541
829
|
var DEFAULT_WIDTH = 320;
|
|
542
830
|
var DEFAULT_MIN = 240;
|
|
543
831
|
var DEFAULT_MAX = 800;
|
|
544
832
|
function SidePane() {
|
|
545
833
|
const { pane, close } = useSidePaneState();
|
|
546
834
|
if (!pane) return null;
|
|
547
|
-
return /* @__PURE__ */
|
|
835
|
+
return /* @__PURE__ */ jsx10(SidePaneOpen, { pane, onClose: close });
|
|
548
836
|
}
|
|
549
837
|
function SidePaneOpen({
|
|
550
838
|
pane,
|
|
@@ -557,32 +845,33 @@ function SidePaneOpen({
|
|
|
557
845
|
direction: "right-edge"
|
|
558
846
|
});
|
|
559
847
|
const isFullWidth = pane.fullWidth === true;
|
|
560
|
-
return /* @__PURE__ */
|
|
848
|
+
return /* @__PURE__ */ jsxs7(
|
|
561
849
|
"div",
|
|
562
850
|
{
|
|
563
|
-
className:
|
|
851
|
+
className: cn5(
|
|
564
852
|
"relative flex flex-col border-r bg-background",
|
|
565
853
|
isFullWidth ? "flex-1" : "shrink-0"
|
|
566
854
|
),
|
|
567
855
|
style: isFullWidth ? void 0 : { width: panelWidth },
|
|
568
856
|
children: [
|
|
569
|
-
/* @__PURE__ */
|
|
857
|
+
/* @__PURE__ */ jsx10("div", { className: "flex h-10 shrink-0 items-center justify-end border-b px-2", children: /* @__PURE__ */ jsx10(
|
|
570
858
|
"button",
|
|
571
859
|
{
|
|
572
860
|
onClick: onClose,
|
|
573
|
-
className:
|
|
861
|
+
className: cn5(
|
|
574
862
|
"flex h-6 w-6 items-center justify-center rounded text-muted-foreground",
|
|
575
863
|
"hover:bg-accent hover:text-foreground transition-colors",
|
|
576
864
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
577
865
|
),
|
|
578
866
|
"aria-label": "Close side pane",
|
|
579
|
-
children: /* @__PURE__ */
|
|
867
|
+
children: /* @__PURE__ */ jsx10(X, { className: "h-3.5 w-3.5" })
|
|
580
868
|
}
|
|
581
869
|
) }),
|
|
582
|
-
/* @__PURE__ */
|
|
583
|
-
!isFullWidth && /* @__PURE__ */
|
|
870
|
+
/* @__PURE__ */ jsx10("div", { className: "flex-1 overflow-auto", children: pane.content }),
|
|
871
|
+
!isFullWidth && /* @__PURE__ */ jsx10(
|
|
584
872
|
DragHandle,
|
|
585
873
|
{
|
|
874
|
+
edge: "right",
|
|
586
875
|
separatorProps,
|
|
587
876
|
onPointerDown: handlePointerDown,
|
|
588
877
|
onDoubleClick: handleDoubleClick
|
|
@@ -594,7 +883,7 @@ function SidePaneOpen({
|
|
|
594
883
|
}
|
|
595
884
|
|
|
596
885
|
// src/CommandMenu.tsx
|
|
597
|
-
import { useEffect as useEffect2, useCallback } from "react";
|
|
886
|
+
import { useEffect as useEffect2, useCallback, useMemo as useMemo4 } from "react";
|
|
598
887
|
import { useNavigate } from "react-router-dom";
|
|
599
888
|
import {
|
|
600
889
|
CommandDialog,
|
|
@@ -605,10 +894,11 @@ import {
|
|
|
605
894
|
CommandList,
|
|
606
895
|
CommandSeparator
|
|
607
896
|
} from "@petrarca/sonnet-ui";
|
|
608
|
-
import { Fragment, jsx as
|
|
897
|
+
import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
609
898
|
function CommandMenu({ open, onOpenChange }) {
|
|
610
899
|
const navigate = useNavigate();
|
|
611
900
|
const { mainModules, bottomModules } = useShellModules();
|
|
901
|
+
const { resolveCapability, capabilityPolicy } = useShellConfig();
|
|
612
902
|
useEffect2(() => {
|
|
613
903
|
const handleKeyDown = (e) => {
|
|
614
904
|
if (e.key === "k" && (e.metaKey || e.ctrlKey)) {
|
|
@@ -619,6 +909,11 @@ function CommandMenu({ open, onOpenChange }) {
|
|
|
619
909
|
document.addEventListener("keydown", handleKeyDown);
|
|
620
910
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
621
911
|
}, [open, onOpenChange]);
|
|
912
|
+
const policy = useMemo4(
|
|
913
|
+
() => resolveCapabilityPolicy(capabilityPolicy),
|
|
914
|
+
[capabilityPolicy]
|
|
915
|
+
);
|
|
916
|
+
const moduleEffect = (service) => evaluateModule(service, "command", resolveCapability, policy);
|
|
622
917
|
const handleSelect = useCallback(
|
|
623
918
|
(path) => {
|
|
624
919
|
navigate(path);
|
|
@@ -628,17 +923,21 @@ function CommandMenu({ open, onOpenChange }) {
|
|
|
628
923
|
);
|
|
629
924
|
const renderNavGroup = (service) => {
|
|
630
925
|
if (service.navigation.length === 0) return null;
|
|
926
|
+
const { effect, reason } = moduleEffect(service);
|
|
927
|
+
if (effect === "hidden" || effect === "redirect") return null;
|
|
928
|
+
const disabled = effect === "disabled";
|
|
631
929
|
const Icon = service.icon;
|
|
632
|
-
return /* @__PURE__ */
|
|
633
|
-
(group) => group.links.map((link) => /* @__PURE__ */
|
|
930
|
+
return /* @__PURE__ */ jsx11(CommandGroup, { heading: service.label, children: service.navigation.flatMap(
|
|
931
|
+
(group) => group.links.map((link) => /* @__PURE__ */ jsxs8(
|
|
634
932
|
CommandItem,
|
|
635
933
|
{
|
|
636
934
|
value: `${service.label} ${group.heading ?? ""} ${link.label}`,
|
|
637
|
-
|
|
935
|
+
disabled,
|
|
936
|
+
onSelect: disabled ? void 0 : () => handleSelect(link.path),
|
|
638
937
|
children: [
|
|
639
|
-
/* @__PURE__ */
|
|
640
|
-
/* @__PURE__ */
|
|
641
|
-
group.heading && /* @__PURE__ */
|
|
938
|
+
/* @__PURE__ */ jsx11(Icon, { className: "mr-2 h-4 w-4 text-muted-foreground" }),
|
|
939
|
+
/* @__PURE__ */ jsx11("span", { children: link.label }),
|
|
940
|
+
disabled && reason ? /* @__PURE__ */ jsx11("span", { className: "ml-auto text-xs text-muted-foreground", children: reason }) : group.heading && /* @__PURE__ */ jsx11("span", { className: "ml-auto text-xs text-muted-foreground", children: group.heading })
|
|
642
941
|
]
|
|
643
942
|
},
|
|
644
943
|
link.path
|
|
@@ -647,24 +946,29 @@ function CommandMenu({ open, onOpenChange }) {
|
|
|
647
946
|
};
|
|
648
947
|
const renderCommandGroup = (service) => {
|
|
649
948
|
if (!service.commands?.length) return null;
|
|
949
|
+
const { effect, reason } = moduleEffect(service);
|
|
950
|
+
if (effect === "hidden" || effect === "redirect") return null;
|
|
951
|
+
const disabled = effect === "disabled";
|
|
650
952
|
const Icon = service.icon;
|
|
651
|
-
return /* @__PURE__ */
|
|
953
|
+
return /* @__PURE__ */ jsx11(
|
|
652
954
|
CommandGroup,
|
|
653
955
|
{
|
|
654
956
|
heading: service.commands[0].group ?? service.label,
|
|
655
957
|
children: service.commands.map((cmd) => {
|
|
656
958
|
const CmdIcon = cmd.icon ?? Icon;
|
|
657
|
-
return /* @__PURE__ */
|
|
959
|
+
return /* @__PURE__ */ jsxs8(
|
|
658
960
|
CommandItem,
|
|
659
961
|
{
|
|
660
962
|
value: `${service.label} ${cmd.label}`,
|
|
661
|
-
|
|
963
|
+
disabled,
|
|
964
|
+
onSelect: disabled ? void 0 : () => {
|
|
662
965
|
cmd.action();
|
|
663
966
|
onOpenChange(false);
|
|
664
967
|
},
|
|
665
968
|
children: [
|
|
666
|
-
/* @__PURE__ */
|
|
667
|
-
/* @__PURE__ */
|
|
969
|
+
/* @__PURE__ */ jsx11(CmdIcon, { className: "mr-2 h-4 w-4 text-muted-foreground" }),
|
|
970
|
+
/* @__PURE__ */ jsx11("span", { children: cmd.label }),
|
|
971
|
+
disabled && reason && /* @__PURE__ */ jsx11("span", { className: "ml-auto text-xs text-muted-foreground", children: reason })
|
|
668
972
|
]
|
|
669
973
|
},
|
|
670
974
|
cmd.id
|
|
@@ -675,45 +979,69 @@ function CommandMenu({ open, onOpenChange }) {
|
|
|
675
979
|
);
|
|
676
980
|
};
|
|
677
981
|
const allModules = [...mainModules, ...bottomModules];
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
982
|
+
const hasVisibleNav = (modules) => modules.some(
|
|
983
|
+
(m) => m.navigation.length > 0 && !["hidden", "redirect"].includes(moduleEffect(m).effect)
|
|
984
|
+
);
|
|
985
|
+
const hasVisibleCmds = allModules.some(
|
|
986
|
+
(m) => (m.commands?.length ?? 0) > 0 && !["hidden", "redirect"].includes(moduleEffect(m).effect)
|
|
987
|
+
);
|
|
988
|
+
return /* @__PURE__ */ jsxs8(CommandDialog, { open, onOpenChange, children: [
|
|
989
|
+
/* @__PURE__ */ jsx11(CommandInput, { placeholder: "Search pages, services, actions..." }),
|
|
990
|
+
/* @__PURE__ */ jsxs8(CommandList, { children: [
|
|
991
|
+
/* @__PURE__ */ jsx11(CommandEmpty, { children: "No results found." }),
|
|
682
992
|
mainModules.map(renderNavGroup),
|
|
683
|
-
/* @__PURE__ */
|
|
993
|
+
hasVisibleNav(mainModules) && hasVisibleNav(bottomModules) && /* @__PURE__ */ jsx11(CommandSeparator, {}),
|
|
684
994
|
bottomModules.map(renderNavGroup),
|
|
685
|
-
|
|
686
|
-
/* @__PURE__ */
|
|
995
|
+
hasVisibleCmds && /* @__PURE__ */ jsxs8(Fragment2, { children: [
|
|
996
|
+
/* @__PURE__ */ jsx11(CommandSeparator, {}),
|
|
687
997
|
allModules.map(renderCommandGroup)
|
|
688
998
|
] })
|
|
689
999
|
] })
|
|
690
1000
|
] });
|
|
691
1001
|
}
|
|
692
1002
|
|
|
693
|
-
// src/
|
|
694
|
-
import
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
1003
|
+
// src/ModuleEffects.tsx
|
|
1004
|
+
import React3 from "react";
|
|
1005
|
+
import { warnLog as warnLog4 } from "@petrarca/sonnet-core";
|
|
1006
|
+
import { Fragment as Fragment3, jsx as jsx12 } from "react/jsx-runtime";
|
|
1007
|
+
var ModuleEffectBoundary = class extends React3.Component {
|
|
1008
|
+
state = { caught: false };
|
|
1009
|
+
static getDerivedStateFromError() {
|
|
1010
|
+
return { caught: true };
|
|
700
1011
|
}
|
|
701
|
-
|
|
1012
|
+
componentDidCatch(error) {
|
|
1013
|
+
warnLog4(
|
|
1014
|
+
"[ModuleEffects] module '{}' useEffects threw \u2014 effects disabled for this module: {}",
|
|
1015
|
+
this.props.moduleId,
|
|
1016
|
+
error
|
|
1017
|
+
);
|
|
1018
|
+
}
|
|
1019
|
+
render() {
|
|
1020
|
+
return this.state.caught ? null : this.props.children;
|
|
1021
|
+
}
|
|
1022
|
+
};
|
|
1023
|
+
function ModuleEffectHost({ module }) {
|
|
1024
|
+
module.useEffects();
|
|
1025
|
+
return null;
|
|
1026
|
+
}
|
|
1027
|
+
function ModuleEffects({ modules }) {
|
|
1028
|
+
return /* @__PURE__ */ jsx12(Fragment3, { children: modules.filter((m) => typeof m.useEffects === "function").map((m) => /* @__PURE__ */ jsx12(ModuleEffectBoundary, { moduleId: m.id, children: /* @__PURE__ */ jsx12(ModuleEffectHost, { module: m }) }, m.id)) });
|
|
702
1029
|
}
|
|
703
1030
|
|
|
704
1031
|
// src/AppShell.tsx
|
|
705
|
-
import { Fragment as
|
|
706
|
-
var
|
|
707
|
-
narrow: "w-[480px]",
|
|
708
|
-
default: "w-[640px]",
|
|
709
|
-
wide: "w-[800px]",
|
|
710
|
-
half: "w-[50vw]",
|
|
711
|
-
full: "w-screen",
|
|
1032
|
+
import { Fragment as Fragment4, jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1033
|
+
var PANEL_WIDTHS = {
|
|
1034
|
+
narrow: { css: "w-[480px]", px: 480 },
|
|
1035
|
+
default: { css: "w-[640px]", px: 640 },
|
|
1036
|
+
wide: { css: "w-[800px]", px: 800 },
|
|
1037
|
+
half: { css: "w-[50vw]", px: 640 },
|
|
1038
|
+
full: { css: "w-screen", px: 640 },
|
|
712
1039
|
// legacy aliases
|
|
713
|
-
lg: "w-[640px]",
|
|
714
|
-
"1/3": "w-[33vw]",
|
|
715
|
-
"1/2": "w-[50vw]"
|
|
1040
|
+
lg: { css: "w-[640px]", px: 640 },
|
|
1041
|
+
"1/3": { css: "w-[33vw]", px: 640 },
|
|
1042
|
+
"1/2": { css: "w-[50vw]", px: 640 }
|
|
716
1043
|
};
|
|
1044
|
+
var DEFAULT_PANEL = PANEL_WIDTHS.default;
|
|
717
1045
|
function isSidePaneModule(service) {
|
|
718
1046
|
return !!service.sidePane && service.navigation.length === 0;
|
|
719
1047
|
}
|
|
@@ -761,7 +1089,7 @@ function useShellApiInit(deps) {
|
|
|
761
1089
|
}
|
|
762
1090
|
function useActiveService(modules) {
|
|
763
1091
|
const location = useLocation2();
|
|
764
|
-
const serviceByBasePath =
|
|
1092
|
+
const serviceByBasePath = useMemo5(
|
|
765
1093
|
() => new Map(
|
|
766
1094
|
modules.filter((m) => !m.hidden && m.basePath !== "/").map((m) => [m.basePath, m.id])
|
|
767
1095
|
),
|
|
@@ -776,7 +1104,7 @@ function useActiveService(modules) {
|
|
|
776
1104
|
},
|
|
777
1105
|
[serviceByBasePath]
|
|
778
1106
|
);
|
|
779
|
-
const [selectedServiceId, setSelectedServiceId] =
|
|
1107
|
+
const [selectedServiceId, setSelectedServiceId] = useState2(
|
|
780
1108
|
() => resolveServiceFromPath(location.pathname)
|
|
781
1109
|
);
|
|
782
1110
|
useEffect3(
|
|
@@ -787,7 +1115,7 @@ function useActiveService(modules) {
|
|
|
787
1115
|
return { activeService, selectedServiceId, setSelectedServiceId };
|
|
788
1116
|
}
|
|
789
1117
|
function useSidePaneState2() {
|
|
790
|
-
const [sidePaneState, setSidePaneState] =
|
|
1118
|
+
const [sidePaneState, setSidePaneState] = useState2(
|
|
791
1119
|
null
|
|
792
1120
|
);
|
|
793
1121
|
const handleOpen = useCallback2(
|
|
@@ -816,8 +1144,27 @@ function useSidePaneState2() {
|
|
|
816
1144
|
handleSetFullWidth
|
|
817
1145
|
};
|
|
818
1146
|
}
|
|
1147
|
+
var DEFAULT_RESIZE_MIN = 240;
|
|
1148
|
+
var DEFAULT_RESIZE_MAX = 1200;
|
|
1149
|
+
function resizeOptionsFromPanel(state, widthEntry) {
|
|
1150
|
+
if (!state?.resizable) {
|
|
1151
|
+
return {
|
|
1152
|
+
enabled: false,
|
|
1153
|
+
defaultWidth: widthEntry.px,
|
|
1154
|
+
minWidth: DEFAULT_RESIZE_MIN,
|
|
1155
|
+
maxWidth: DEFAULT_RESIZE_MAX
|
|
1156
|
+
};
|
|
1157
|
+
}
|
|
1158
|
+
const viewportMax = typeof window !== "undefined" ? Math.round(window.innerWidth * 0.9) : DEFAULT_RESIZE_MAX;
|
|
1159
|
+
return {
|
|
1160
|
+
enabled: true,
|
|
1161
|
+
defaultWidth: widthEntry.px,
|
|
1162
|
+
minWidth: state.minWidth ?? DEFAULT_RESIZE_MIN,
|
|
1163
|
+
maxWidth: state.maxWidth ?? viewportMax
|
|
1164
|
+
};
|
|
1165
|
+
}
|
|
819
1166
|
function usePanelState() {
|
|
820
|
-
const [panelState, setPanelState] =
|
|
1167
|
+
const [panelState, setPanelState] = useState2(null);
|
|
821
1168
|
const panelOnCloseRef = useRef2(void 0);
|
|
822
1169
|
const handleOpen = useCallback2(
|
|
823
1170
|
(opts) => setPanelState(opts),
|
|
@@ -827,7 +1174,8 @@ function usePanelState() {
|
|
|
827
1174
|
panelOnCloseRef.current = panelState?.onClose;
|
|
828
1175
|
setPanelState(null);
|
|
829
1176
|
}, [panelState]);
|
|
830
|
-
const
|
|
1177
|
+
const widthEntry = PANEL_WIDTHS[panelState?.width ?? "default"] ?? DEFAULT_PANEL;
|
|
1178
|
+
const panelWidth = widthEntry.css;
|
|
831
1179
|
const panelOffsetTop = panelState?.coverage === "full" ? "0px" : "3rem";
|
|
832
1180
|
return {
|
|
833
1181
|
panelState,
|
|
@@ -835,11 +1183,12 @@ function usePanelState() {
|
|
|
835
1183
|
handleOpen,
|
|
836
1184
|
handleClose,
|
|
837
1185
|
panelWidth,
|
|
838
|
-
panelOffsetTop
|
|
1186
|
+
panelOffsetTop,
|
|
1187
|
+
resize: resizeOptionsFromPanel(panelState, widthEntry)
|
|
839
1188
|
};
|
|
840
1189
|
}
|
|
841
1190
|
function useDialogState() {
|
|
842
|
-
const [dialogState, setDialogState] =
|
|
1191
|
+
const [dialogState, setDialogState] = useState2(null);
|
|
843
1192
|
const handleConfirm = useCallback2(() => {
|
|
844
1193
|
dialogState?.resolve(true);
|
|
845
1194
|
setDialogState(null);
|
|
@@ -851,7 +1200,7 @@ function useDialogState() {
|
|
|
851
1200
|
return { dialogState, setDialogState, handleConfirm, handleCancel };
|
|
852
1201
|
}
|
|
853
1202
|
function useFeatureLookup(modules) {
|
|
854
|
-
return
|
|
1203
|
+
return useMemo5(() => {
|
|
855
1204
|
const map = /* @__PURE__ */ new Map();
|
|
856
1205
|
for (const m of modules) {
|
|
857
1206
|
for (const group of m.navigation) {
|
|
@@ -863,15 +1212,15 @@ function useFeatureLookup(modules) {
|
|
|
863
1212
|
return (featureId) => map.get(featureId) ?? null;
|
|
864
1213
|
}, [modules]);
|
|
865
1214
|
}
|
|
866
|
-
function AppShell({ registry }) {
|
|
1215
|
+
function AppShell({ registry, sidebar }) {
|
|
867
1216
|
const navigate = useNavigate2();
|
|
868
1217
|
const config = useShellConfig();
|
|
869
1218
|
const { modules } = registry;
|
|
870
1219
|
const { activeService, setSelectedServiceId } = useActiveService(modules);
|
|
871
|
-
const [subNavCollapsed, setSubNavCollapsed] =
|
|
872
|
-
const [commandMenuOpen, setCommandMenuOpen] =
|
|
1220
|
+
const [subNavCollapsed, setSubNavCollapsed] = useState2(false);
|
|
1221
|
+
const [commandMenuOpen, setCommandMenuOpen] = useState2(false);
|
|
873
1222
|
const openCommandMenu = useCallback2(() => setCommandMenuOpen(true), []);
|
|
874
|
-
const [fullscreenState, setFullscreenState] =
|
|
1223
|
+
const [fullscreenState, setFullscreenState] = useState2(null);
|
|
875
1224
|
const handleFullscreenEnter = useCallback2(
|
|
876
1225
|
(opts) => setFullscreenState(opts),
|
|
877
1226
|
[]
|
|
@@ -930,7 +1279,7 @@ function AppShell({ registry }) {
|
|
|
930
1279
|
setSubNavCollapsed
|
|
931
1280
|
]
|
|
932
1281
|
);
|
|
933
|
-
const sidePaneContextValue =
|
|
1282
|
+
const sidePaneContextValue = useMemo5(
|
|
934
1283
|
() => ({
|
|
935
1284
|
pane: sidePane2.sidePaneState,
|
|
936
1285
|
open: sidePane2.handleOpen,
|
|
@@ -946,50 +1295,59 @@ function AppShell({ registry }) {
|
|
|
946
1295
|
}),
|
|
947
1296
|
[sidePane2]
|
|
948
1297
|
);
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
),
|
|
958
|
-
/* @__PURE__ */
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
1298
|
+
const navigationValue = {
|
|
1299
|
+
activeService,
|
|
1300
|
+
sidePaneModuleId: sidePane2.sidePaneState?.moduleId ?? null,
|
|
1301
|
+
subNavCollapsed,
|
|
1302
|
+
onToggleSubNav: () => setSubNavCollapsed((c) => !c),
|
|
1303
|
+
onServiceSelect: handleServiceSelect
|
|
1304
|
+
};
|
|
1305
|
+
return /* @__PURE__ */ jsx13(ShellModulesContext.Provider, { value: registry, children: /* @__PURE__ */ jsx13(SidePaneContext.Provider, { value: sidePaneContextValue, children: /* @__PURE__ */ jsx13(ShellNavigationContext.Provider, { value: navigationValue, children: /* @__PURE__ */ jsxs9(TooltipProvider, { children: [
|
|
1306
|
+
/* @__PURE__ */ jsx13(ModuleEffects, { modules }),
|
|
1307
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex h-screen w-screen flex-col overflow-hidden", children: [
|
|
1308
|
+
/* @__PURE__ */ jsx13(TopBar, { children: config.topBar }),
|
|
1309
|
+
/* @__PURE__ */ jsx13(
|
|
1310
|
+
CommandMenu,
|
|
1311
|
+
{
|
|
1312
|
+
open: commandMenuOpen,
|
|
1313
|
+
onOpenChange: setCommandMenuOpen
|
|
1314
|
+
}
|
|
1315
|
+
),
|
|
1316
|
+
/* @__PURE__ */ jsx13(
|
|
1317
|
+
ShellBody,
|
|
1318
|
+
{
|
|
1319
|
+
activeService,
|
|
1320
|
+
sidePaneFullWidth: sidePane2.sidePaneState?.fullWidth,
|
|
1321
|
+
sidebar
|
|
1322
|
+
}
|
|
1323
|
+
),
|
|
1324
|
+
config.footer && /* @__PURE__ */ jsx13(ShellFooter, { children: config.footer }),
|
|
1325
|
+
dialog2.dialogState && /* @__PURE__ */ jsx13(
|
|
1326
|
+
ConfirmDialog,
|
|
1327
|
+
{
|
|
1328
|
+
open: true,
|
|
1329
|
+
title: dialog2.dialogState.opts.title,
|
|
1330
|
+
description: dialog2.dialogState.opts.description,
|
|
1331
|
+
confirmLabel: dialog2.dialogState.opts.confirmLabel,
|
|
1332
|
+
cancelLabel: dialog2.dialogState.opts.cancelLabel,
|
|
1333
|
+
variant: dialog2.dialogState.opts.variant,
|
|
1334
|
+
onConfirm: dialog2.handleConfirm,
|
|
1335
|
+
onCancel: dialog2.handleCancel
|
|
1336
|
+
}
|
|
1337
|
+
),
|
|
1338
|
+
fullscreenState && /* @__PURE__ */ jsx13("div", { className: "fixed inset-0 z-50 bg-background overflow-auto", children: fullscreenState.content }),
|
|
1339
|
+
/* @__PURE__ */ jsx13(
|
|
1340
|
+
SlideOverPanel,
|
|
1341
|
+
{
|
|
1342
|
+
panelState: panel2.panelState,
|
|
1343
|
+
panelWidth: panel2.panelWidth,
|
|
1344
|
+
panelOffsetTop: panel2.panelOffsetTop,
|
|
1345
|
+
panelOnCloseRef: panel2.panelOnCloseRef,
|
|
1346
|
+
onClose: panel2.handleClose,
|
|
1347
|
+
resize: panel2.resize
|
|
1348
|
+
}
|
|
1349
|
+
)
|
|
1350
|
+
] })
|
|
993
1351
|
] }) }) }) });
|
|
994
1352
|
}
|
|
995
1353
|
function SlideOverPanel({
|
|
@@ -997,78 +1355,92 @@ function SlideOverPanel({
|
|
|
997
1355
|
panelWidth,
|
|
998
1356
|
panelOffsetTop,
|
|
999
1357
|
panelOnCloseRef,
|
|
1000
|
-
onClose
|
|
1358
|
+
onClose,
|
|
1359
|
+
resize
|
|
1001
1360
|
}) {
|
|
1002
|
-
|
|
1361
|
+
const sheetProps = {
|
|
1362
|
+
side: "right",
|
|
1363
|
+
offsetTop: panelOffsetTop,
|
|
1364
|
+
onCloseAutoFocus: (e) => {
|
|
1365
|
+
if (panelOnCloseRef.current) {
|
|
1366
|
+
e.preventDefault();
|
|
1367
|
+
panelOnCloseRef.current();
|
|
1368
|
+
}
|
|
1369
|
+
},
|
|
1370
|
+
...!panelState?.description && { "aria-describedby": void 0 }
|
|
1371
|
+
};
|
|
1372
|
+
return /* @__PURE__ */ jsx13(
|
|
1003
1373
|
Sheet,
|
|
1004
1374
|
{
|
|
1005
1375
|
open: panelState !== null,
|
|
1006
1376
|
onOpenChange: (open) => {
|
|
1007
1377
|
if (!open) onClose();
|
|
1008
1378
|
},
|
|
1009
|
-
children: /* @__PURE__ */
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1379
|
+
children: resize.enabled ? /* @__PURE__ */ jsx13(ResizableSheetContent, { ...sheetProps, resize, children: panelState && /* @__PURE__ */ jsx13(PanelContent, { state: panelState }) }) : /* @__PURE__ */ jsx13(SheetContent, { ...sheetProps, className: `${panelWidth} max-w-[90vw]`, children: panelState && /* @__PURE__ */ jsx13(PanelContent, { state: panelState }) })
|
|
1380
|
+
}
|
|
1381
|
+
);
|
|
1382
|
+
}
|
|
1383
|
+
function ResizableSheetContent({
|
|
1384
|
+
resize,
|
|
1385
|
+
children,
|
|
1386
|
+
...sheetProps
|
|
1387
|
+
}) {
|
|
1388
|
+
const {
|
|
1389
|
+
panelWidth: dynWidth,
|
|
1390
|
+
handlePointerDown,
|
|
1391
|
+
handleDoubleClick,
|
|
1392
|
+
separatorProps
|
|
1393
|
+
} = useResizablePanel2({
|
|
1394
|
+
defaultWidth: resize.defaultWidth,
|
|
1395
|
+
minWidth: resize.minWidth,
|
|
1396
|
+
maxWidth: resize.maxWidth,
|
|
1397
|
+
direction: "left-edge"
|
|
1398
|
+
});
|
|
1399
|
+
return /* @__PURE__ */ jsxs9(
|
|
1400
|
+
SheetContent,
|
|
1401
|
+
{
|
|
1402
|
+
...sheetProps,
|
|
1403
|
+
className: "max-w-[90vw]",
|
|
1404
|
+
style: { width: dynWidth },
|
|
1405
|
+
children: [
|
|
1406
|
+
/* @__PURE__ */ jsx13(
|
|
1407
|
+
DragHandle,
|
|
1408
|
+
{
|
|
1409
|
+
edge: "left",
|
|
1410
|
+
separatorProps,
|
|
1411
|
+
onPointerDown: handlePointerDown,
|
|
1412
|
+
onDoubleClick: handleDoubleClick
|
|
1413
|
+
}
|
|
1414
|
+
),
|
|
1415
|
+
children
|
|
1416
|
+
]
|
|
1027
1417
|
}
|
|
1028
1418
|
);
|
|
1029
1419
|
}
|
|
1030
1420
|
function ShellBody({
|
|
1031
1421
|
activeService,
|
|
1032
1422
|
sidePaneFullWidth,
|
|
1033
|
-
|
|
1034
|
-
subNavCollapsed,
|
|
1035
|
-
onToggleSubNav,
|
|
1036
|
-
onServiceSelect
|
|
1423
|
+
sidebar
|
|
1037
1424
|
}) {
|
|
1038
|
-
return /* @__PURE__ */
|
|
1039
|
-
/* @__PURE__ */
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
activeServiceId: activeService?.id ?? null,
|
|
1043
|
-
activeSidePaneModuleId: sidePaneModuleId,
|
|
1044
|
-
onServiceSelect
|
|
1045
|
-
}
|
|
1046
|
-
),
|
|
1047
|
-
activeService && activeService.navigation.length > 0 && /* @__PURE__ */ jsx7(
|
|
1048
|
-
SubNavPanel,
|
|
1049
|
-
{
|
|
1050
|
-
service: activeService,
|
|
1051
|
-
collapsed: subNavCollapsed,
|
|
1052
|
-
onToggleCollapse: onToggleSubNav
|
|
1053
|
-
}
|
|
1054
|
-
),
|
|
1055
|
-
/* @__PURE__ */ jsx7(SidePane, {}),
|
|
1056
|
-
sidePaneFullWidth !== true && /* @__PURE__ */ jsx7("div", { className: "flex-1 min-w-0 h-full overflow-hidden", children: /* @__PURE__ */ jsx7(ContentArea, { layout: activeService?.layout }) })
|
|
1425
|
+
return /* @__PURE__ */ jsxs9("div", { className: "flex flex-1 overflow-hidden", children: [
|
|
1426
|
+
sidebar ?? /* @__PURE__ */ jsx13(ShellRail, {}),
|
|
1427
|
+
/* @__PURE__ */ jsx13(SidePane, {}),
|
|
1428
|
+
sidePaneFullWidth !== true && /* @__PURE__ */ jsx13("div", { className: "flex-1 min-w-0 h-full overflow-hidden", children: /* @__PURE__ */ jsx13(ContentArea, { layout: activeService?.layout }) })
|
|
1057
1429
|
] });
|
|
1058
1430
|
}
|
|
1059
1431
|
function ContentArea({ layout }) {
|
|
1060
1432
|
if (layout === "full") {
|
|
1061
|
-
return /* @__PURE__ */
|
|
1433
|
+
return /* @__PURE__ */ jsx13("div", { className: "h-full w-full overflow-hidden", children: /* @__PURE__ */ jsx13(Outlet, {}) });
|
|
1062
1434
|
}
|
|
1063
|
-
return /* @__PURE__ */
|
|
1435
|
+
return /* @__PURE__ */ jsx13(ScrollArea2, { className: "h-full", children: /* @__PURE__ */ jsx13("main", { className: "p-6", children: /* @__PURE__ */ jsx13(Outlet, {}) }) });
|
|
1064
1436
|
}
|
|
1065
1437
|
function PanelContent({ state }) {
|
|
1066
|
-
return /* @__PURE__ */
|
|
1067
|
-
state.title ? /* @__PURE__ */
|
|
1068
|
-
/* @__PURE__ */
|
|
1069
|
-
state.description && /* @__PURE__ */
|
|
1070
|
-
] }) : /* @__PURE__ */
|
|
1071
|
-
/* @__PURE__ */
|
|
1438
|
+
return /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
1439
|
+
state.title ? /* @__PURE__ */ jsxs9(SheetHeader, { children: [
|
|
1440
|
+
/* @__PURE__ */ jsx13(SheetTitle, { children: state.title }),
|
|
1441
|
+
state.description && /* @__PURE__ */ jsx13(SheetDescription, { children: state.description })
|
|
1442
|
+
] }) : /* @__PURE__ */ jsx13(SheetTitle, { className: "sr-only", children: "Panel" }),
|
|
1443
|
+
/* @__PURE__ */ jsx13(SheetBody, { children: state.content })
|
|
1072
1444
|
] });
|
|
1073
1445
|
}
|
|
1074
1446
|
|
|
@@ -1076,32 +1448,36 @@ function PanelContent({ state }) {
|
|
|
1076
1448
|
import { Toaster } from "sonner";
|
|
1077
1449
|
|
|
1078
1450
|
// src/ShellConfigProvider.tsx
|
|
1079
|
-
import { jsx as
|
|
1451
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
1080
1452
|
function ShellConfigProvider({
|
|
1081
1453
|
config,
|
|
1082
1454
|
children
|
|
1083
1455
|
}) {
|
|
1084
|
-
return /* @__PURE__ */
|
|
1456
|
+
return /* @__PURE__ */ jsx14(ShellConfigContext.Provider, { value: config, children });
|
|
1085
1457
|
}
|
|
1086
1458
|
|
|
1087
1459
|
// src/RootLayout.tsx
|
|
1088
|
-
import { jsx as
|
|
1089
|
-
function RootLayout({
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1460
|
+
import { jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1461
|
+
function RootLayout({
|
|
1462
|
+
config,
|
|
1463
|
+
registry,
|
|
1464
|
+
sidebar
|
|
1465
|
+
}) {
|
|
1466
|
+
return /* @__PURE__ */ jsxs10(ShellConfigProvider, { config, children: [
|
|
1467
|
+
/* @__PURE__ */ jsx15(Toaster, { position: "top-right", richColors: true, closeButton: true }),
|
|
1468
|
+
/* @__PURE__ */ jsx15(AppShell, { registry, sidebar })
|
|
1093
1469
|
] });
|
|
1094
1470
|
}
|
|
1095
1471
|
|
|
1096
1472
|
// src/PlaceholderPage.tsx
|
|
1097
1473
|
import { useLocation as useLocation3 } from "react-router-dom";
|
|
1098
|
-
import { jsx as
|
|
1474
|
+
import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1099
1475
|
function PlaceholderPage() {
|
|
1100
1476
|
const { pathname } = useLocation3();
|
|
1101
|
-
return /* @__PURE__ */
|
|
1102
|
-
/* @__PURE__ */
|
|
1103
|
-
/* @__PURE__ */
|
|
1104
|
-
/* @__PURE__ */
|
|
1477
|
+
return /* @__PURE__ */ jsxs11("div", { children: [
|
|
1478
|
+
/* @__PURE__ */ jsx16("h1", { className: "mb-1", children: pathToTitle(pathname) }),
|
|
1479
|
+
/* @__PURE__ */ jsx16("p", { className: "text-sm text-muted-foreground mb-6", children: pathname }),
|
|
1480
|
+
/* @__PURE__ */ jsx16("div", { className: "rounded-lg border-2 border-dashed border-border p-12 flex items-center justify-center", children: /* @__PURE__ */ jsx16("span", { className: "text-sm text-muted-foreground", children: "Content area \u2014 not yet implemented" }) })
|
|
1105
1481
|
] });
|
|
1106
1482
|
}
|
|
1107
1483
|
function pathToTitle(path) {
|
|
@@ -1110,12 +1486,131 @@ function pathToTitle(path) {
|
|
|
1110
1486
|
return last.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
1111
1487
|
}
|
|
1112
1488
|
|
|
1489
|
+
// src/Sidebar.tsx
|
|
1490
|
+
import { cn as cn6 } from "@petrarca/sonnet-core";
|
|
1491
|
+
import { ScrollArea as ScrollArea3 } from "@petrarca/sonnet-ui";
|
|
1492
|
+
import { jsx as jsx17, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1493
|
+
function Sidebar({
|
|
1494
|
+
children,
|
|
1495
|
+
header,
|
|
1496
|
+
width = 260,
|
|
1497
|
+
className
|
|
1498
|
+
}) {
|
|
1499
|
+
return /* @__PURE__ */ jsxs12(
|
|
1500
|
+
"aside",
|
|
1501
|
+
{
|
|
1502
|
+
style: { width },
|
|
1503
|
+
className: cn6(
|
|
1504
|
+
"shrink-0 border-r bg-muted/30 flex flex-col h-full",
|
|
1505
|
+
className
|
|
1506
|
+
),
|
|
1507
|
+
children: [
|
|
1508
|
+
header,
|
|
1509
|
+
/* @__PURE__ */ jsx17(ScrollArea3, { className: "flex-1", children: /* @__PURE__ */ jsx17("nav", { className: "px-1.5 py-2 space-y-3", children }) })
|
|
1510
|
+
]
|
|
1511
|
+
}
|
|
1512
|
+
);
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
// src/ShellSidebar.tsx
|
|
1516
|
+
import { jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1517
|
+
function ShellSidebar({
|
|
1518
|
+
bottomGroupLabel = "Tools",
|
|
1519
|
+
...sidebarProps
|
|
1520
|
+
}) {
|
|
1521
|
+
const { mainModules, bottomModules } = useShellModules();
|
|
1522
|
+
const topNavItems = mainModules.flatMap(
|
|
1523
|
+
(mod) => (mod.topNav ?? []).map((link) => ({ link, icon: mod.icon }))
|
|
1524
|
+
);
|
|
1525
|
+
return /* @__PURE__ */ jsxs13(Sidebar, { ...sidebarProps, children: [
|
|
1526
|
+
topNavItems.length > 0 && /* @__PURE__ */ jsx18(SidebarGroup, { separator: true, children: topNavItems.map(({ link, icon }) => /* @__PURE__ */ jsx18(
|
|
1527
|
+
SidebarItem,
|
|
1528
|
+
{
|
|
1529
|
+
icon,
|
|
1530
|
+
label: link.label,
|
|
1531
|
+
path: link.path,
|
|
1532
|
+
badge: link.badge
|
|
1533
|
+
},
|
|
1534
|
+
link.path
|
|
1535
|
+
)) }),
|
|
1536
|
+
mainModules.map((mod) => {
|
|
1537
|
+
if (mod.navigation.length === 0) {
|
|
1538
|
+
return /* @__PURE__ */ jsx18(
|
|
1539
|
+
SidebarItem,
|
|
1540
|
+
{
|
|
1541
|
+
icon: mod.icon,
|
|
1542
|
+
label: mod.label,
|
|
1543
|
+
path: mod.basePath
|
|
1544
|
+
},
|
|
1545
|
+
mod.id
|
|
1546
|
+
);
|
|
1547
|
+
}
|
|
1548
|
+
return /* @__PURE__ */ jsx18(SidebarGroup, { heading: mod.label, collapsible: true, children: mod.navigation.flatMap((group) => [
|
|
1549
|
+
// Render NavGroup heading if it has one
|
|
1550
|
+
...group.heading ? [
|
|
1551
|
+
/* @__PURE__ */ jsx18(
|
|
1552
|
+
SidebarGroup,
|
|
1553
|
+
{
|
|
1554
|
+
heading: group.heading,
|
|
1555
|
+
collapsible: group.collapsible,
|
|
1556
|
+
children: group.links.map((link) => /* @__PURE__ */ jsx18(
|
|
1557
|
+
SidebarItem,
|
|
1558
|
+
{
|
|
1559
|
+
icon: mod.icon,
|
|
1560
|
+
label: link.label,
|
|
1561
|
+
path: link.path,
|
|
1562
|
+
badge: link.badge
|
|
1563
|
+
},
|
|
1564
|
+
link.path
|
|
1565
|
+
))
|
|
1566
|
+
},
|
|
1567
|
+
group.id
|
|
1568
|
+
)
|
|
1569
|
+
] : group.links.map((link) => /* @__PURE__ */ jsx18(
|
|
1570
|
+
SidebarItem,
|
|
1571
|
+
{
|
|
1572
|
+
icon: mod.icon,
|
|
1573
|
+
label: link.label,
|
|
1574
|
+
path: link.path,
|
|
1575
|
+
badge: link.badge
|
|
1576
|
+
},
|
|
1577
|
+
link.path
|
|
1578
|
+
))
|
|
1579
|
+
]) }, mod.id);
|
|
1580
|
+
}),
|
|
1581
|
+
bottomModules.length > 0 && /* @__PURE__ */ jsx18(SidebarGroup, { heading: bottomGroupLabel, collapsible: true, children: bottomModules.map((mod) => /* @__PURE__ */ jsx18(
|
|
1582
|
+
SidebarItem,
|
|
1583
|
+
{
|
|
1584
|
+
icon: mod.icon,
|
|
1585
|
+
label: mod.label,
|
|
1586
|
+
path: mod.basePath
|
|
1587
|
+
},
|
|
1588
|
+
mod.id
|
|
1589
|
+
)) })
|
|
1590
|
+
] });
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
// src/ShellVersion.tsx
|
|
1594
|
+
import { jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1595
|
+
function ShellVersion({
|
|
1596
|
+
name,
|
|
1597
|
+
version
|
|
1598
|
+
}) {
|
|
1599
|
+
return /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-2", children: [
|
|
1600
|
+
/* @__PURE__ */ jsx19("span", { children: name }),
|
|
1601
|
+
version && /* @__PURE__ */ jsxs14("span", { className: "text-muted-foreground/50", children: [
|
|
1602
|
+
"v",
|
|
1603
|
+
version
|
|
1604
|
+
] })
|
|
1605
|
+
] });
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1113
1608
|
// src/SearchTrigger.tsx
|
|
1114
1609
|
import { Search } from "lucide-react";
|
|
1115
1610
|
import { Button as Button3 } from "@petrarca/sonnet-ui";
|
|
1116
|
-
import { jsx as
|
|
1611
|
+
import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1117
1612
|
function SearchTrigger() {
|
|
1118
|
-
return /* @__PURE__ */
|
|
1613
|
+
return /* @__PURE__ */ jsxs15(
|
|
1119
1614
|
Button3,
|
|
1120
1615
|
{
|
|
1121
1616
|
variant: "outline",
|
|
@@ -1123,10 +1618,10 @@ function SearchTrigger() {
|
|
|
1123
1618
|
className: "h-8 gap-2 text-sm text-muted-foreground w-56 justify-start",
|
|
1124
1619
|
onClick: () => navigation.openCommandMenu(),
|
|
1125
1620
|
children: [
|
|
1126
|
-
/* @__PURE__ */
|
|
1127
|
-
/* @__PURE__ */
|
|
1128
|
-
/* @__PURE__ */
|
|
1129
|
-
/* @__PURE__ */
|
|
1621
|
+
/* @__PURE__ */ jsx20(Search, { className: "h-4 w-4" }),
|
|
1622
|
+
/* @__PURE__ */ jsx20("span", { children: "Search..." }),
|
|
1623
|
+
/* @__PURE__ */ jsxs15("kbd", { className: "ml-auto pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground", children: [
|
|
1624
|
+
/* @__PURE__ */ jsx20("span", { className: "text-xs", children: "\u2318" }),
|
|
1130
1625
|
"K"
|
|
1131
1626
|
] })
|
|
1132
1627
|
]
|
|
@@ -1146,23 +1641,23 @@ import {
|
|
|
1146
1641
|
DropdownMenuSeparator,
|
|
1147
1642
|
DropdownMenuTrigger
|
|
1148
1643
|
} from "@petrarca/sonnet-ui";
|
|
1149
|
-
import { jsx as
|
|
1644
|
+
import { jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1150
1645
|
function UserMenu({ user, onSignOut }) {
|
|
1151
|
-
return /* @__PURE__ */
|
|
1152
|
-
/* @__PURE__ */
|
|
1153
|
-
/* @__PURE__ */
|
|
1154
|
-
/* @__PURE__ */
|
|
1155
|
-
/* @__PURE__ */
|
|
1156
|
-
/* @__PURE__ */
|
|
1646
|
+
return /* @__PURE__ */ jsxs16(DropdownMenu, { children: [
|
|
1647
|
+
/* @__PURE__ */ jsx21(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx21(Button4, { variant: "ghost", size: "compact", className: "rounded-full", children: /* @__PURE__ */ jsx21(Avatar, { className: "h-7 w-7", children: /* @__PURE__ */ jsx21(AvatarFallback, { className: "text-xs", children: user.initials }) }) }) }),
|
|
1648
|
+
/* @__PURE__ */ jsxs16(DropdownMenuContent, { align: "end", className: "w-48", children: [
|
|
1649
|
+
/* @__PURE__ */ jsx21(DropdownMenuLabel, { className: "font-normal", children: /* @__PURE__ */ jsxs16("div", { className: "flex flex-col gap-1", children: [
|
|
1650
|
+
/* @__PURE__ */ jsx21("p", { className: "text-sm font-medium", children: user.name }),
|
|
1651
|
+
/* @__PURE__ */ jsx21("p", { className: "text-xs text-muted-foreground", children: user.email })
|
|
1157
1652
|
] }) }),
|
|
1158
|
-
/* @__PURE__ */
|
|
1159
|
-
/* @__PURE__ */
|
|
1160
|
-
/* @__PURE__ */
|
|
1653
|
+
/* @__PURE__ */ jsx21(DropdownMenuSeparator, {}),
|
|
1654
|
+
/* @__PURE__ */ jsxs16(DropdownMenuItem, { children: [
|
|
1655
|
+
/* @__PURE__ */ jsx21(User, { className: "mr-2 h-4 w-4" }),
|
|
1161
1656
|
"Profile"
|
|
1162
1657
|
] }),
|
|
1163
|
-
/* @__PURE__ */
|
|
1164
|
-
/* @__PURE__ */
|
|
1165
|
-
/* @__PURE__ */
|
|
1658
|
+
/* @__PURE__ */ jsx21(DropdownMenuSeparator, {}),
|
|
1659
|
+
/* @__PURE__ */ jsxs16(DropdownMenuItem, { onSelect: onSignOut, children: [
|
|
1660
|
+
/* @__PURE__ */ jsx21(LogOut, { className: "mr-2 h-4 w-4" }),
|
|
1166
1661
|
"Sign out"
|
|
1167
1662
|
] })
|
|
1168
1663
|
] })
|
|
@@ -1193,13 +1688,13 @@ function createModuleRegistry(modules) {
|
|
|
1193
1688
|
}
|
|
1194
1689
|
|
|
1195
1690
|
// src/OverviewCard.tsx
|
|
1196
|
-
import { cn as
|
|
1197
|
-
import { jsx as
|
|
1691
|
+
import { cn as cn7 } from "@petrarca/sonnet-core";
|
|
1692
|
+
import { jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1198
1693
|
function FeatureLink({
|
|
1199
1694
|
feature,
|
|
1200
1695
|
children
|
|
1201
1696
|
}) {
|
|
1202
|
-
return /* @__PURE__ */
|
|
1697
|
+
return /* @__PURE__ */ jsx22(
|
|
1203
1698
|
"span",
|
|
1204
1699
|
{
|
|
1205
1700
|
role: "link",
|
|
@@ -1227,22 +1722,22 @@ function OverviewCard({
|
|
|
1227
1722
|
feature,
|
|
1228
1723
|
className
|
|
1229
1724
|
}) {
|
|
1230
|
-
return /* @__PURE__ */
|
|
1725
|
+
return /* @__PURE__ */ jsxs17(
|
|
1231
1726
|
"button",
|
|
1232
1727
|
{
|
|
1233
1728
|
onClick: feature ? () => navigation.goToFeature(feature) : void 0,
|
|
1234
1729
|
disabled: !feature,
|
|
1235
|
-
className:
|
|
1730
|
+
className: cn7(
|
|
1236
1731
|
"rounded-lg border bg-card p-5 text-left flex flex-col gap-3",
|
|
1237
1732
|
"disabled:cursor-default",
|
|
1238
1733
|
feature && "hover:bg-accent/50 transition-colors",
|
|
1239
1734
|
className
|
|
1240
1735
|
),
|
|
1241
1736
|
children: [
|
|
1242
|
-
/* @__PURE__ */
|
|
1243
|
-
/* @__PURE__ */
|
|
1244
|
-
/* @__PURE__ */
|
|
1245
|
-
/* @__PURE__ */
|
|
1737
|
+
/* @__PURE__ */ jsx22("div", { className: "h-9 w-9 rounded-md bg-blue-50 flex items-center justify-center shrink-0", children: /* @__PURE__ */ jsx22(Icon, { className: "h-5 w-5 text-blue-600" }) }),
|
|
1738
|
+
/* @__PURE__ */ jsxs17("div", { children: [
|
|
1739
|
+
/* @__PURE__ */ jsx22("p", { className: "text-sm font-medium mb-1", children: title }),
|
|
1740
|
+
/* @__PURE__ */ jsx22("p", { className: "text-xs text-muted-foreground leading-relaxed", children: description })
|
|
1246
1741
|
] })
|
|
1247
1742
|
]
|
|
1248
1743
|
}
|
|
@@ -1252,35 +1747,50 @@ export {
|
|
|
1252
1747
|
AppShell,
|
|
1253
1748
|
CommandMenu,
|
|
1254
1749
|
ConfirmDialog,
|
|
1750
|
+
DEFAULT_CAPABILITY_POLICY,
|
|
1255
1751
|
FeatureLink,
|
|
1256
1752
|
IconRail,
|
|
1257
1753
|
OverviewCard,
|
|
1258
1754
|
PlaceholderPage,
|
|
1755
|
+
RailIcon,
|
|
1756
|
+
RailSeparator,
|
|
1259
1757
|
RootLayout,
|
|
1260
1758
|
SearchTrigger,
|
|
1261
1759
|
ShellConfigProvider,
|
|
1760
|
+
ShellFooter,
|
|
1761
|
+
ShellRail,
|
|
1762
|
+
ShellSidebar,
|
|
1763
|
+
ShellVersion,
|
|
1262
1764
|
SidePane,
|
|
1263
1765
|
SidePaneContext,
|
|
1766
|
+
Sidebar,
|
|
1767
|
+
SidebarGroup,
|
|
1768
|
+
SidebarItem,
|
|
1264
1769
|
SubNavPanel,
|
|
1265
1770
|
TopBar,
|
|
1266
1771
|
UserMenu,
|
|
1267
1772
|
createModuleRegistry,
|
|
1268
1773
|
dialog,
|
|
1774
|
+
evaluateModule,
|
|
1269
1775
|
events,
|
|
1270
1776
|
fullscreen,
|
|
1271
1777
|
initDialog,
|
|
1778
|
+
initFeatureNav,
|
|
1779
|
+
initFullscreen,
|
|
1272
1780
|
initNavigation,
|
|
1273
1781
|
initPanel,
|
|
1274
1782
|
initSidePane,
|
|
1275
1783
|
navigation,
|
|
1276
1784
|
notification,
|
|
1277
1785
|
panel,
|
|
1786
|
+
resolveCapabilityPolicy,
|
|
1278
1787
|
sidePane,
|
|
1279
1788
|
useExtensionPoint,
|
|
1280
1789
|
useMainModules,
|
|
1281
1790
|
useShellConfig,
|
|
1282
1791
|
useShellEvent,
|
|
1283
1792
|
useShellModules,
|
|
1793
|
+
useShellNavigation,
|
|
1284
1794
|
useSidePaneState
|
|
1285
1795
|
};
|
|
1286
1796
|
//# sourceMappingURL=index.js.map
|