@xeonr/console-shell 0.1.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.
Files changed (53) hide show
  1. package/dist/AccountMenu.d.ts +5 -0
  2. package/dist/AccountMenu.d.ts.map +1 -0
  3. package/dist/AccountMenu.js +71 -0
  4. package/dist/AccountMenu.js.map +1 -0
  5. package/dist/CommandPalette.d.ts +8 -0
  6. package/dist/CommandPalette.d.ts.map +1 -0
  7. package/dist/CommandPalette.js +160 -0
  8. package/dist/CommandPalette.js.map +1 -0
  9. package/dist/ConsoleProvider.d.ts +36 -0
  10. package/dist/ConsoleProvider.d.ts.map +1 -0
  11. package/dist/ConsoleProvider.js +110 -0
  12. package/dist/ConsoleProvider.js.map +1 -0
  13. package/dist/ConsoleShell.d.ts +20 -0
  14. package/dist/ConsoleShell.d.ts.map +1 -0
  15. package/dist/ConsoleShell.js +81 -0
  16. package/dist/ConsoleShell.js.map +1 -0
  17. package/dist/Launcher.d.ts +7 -0
  18. package/dist/Launcher.d.ts.map +1 -0
  19. package/dist/Launcher.js +119 -0
  20. package/dist/Launcher.js.map +1 -0
  21. package/dist/ScopeRail.d.ts +11 -0
  22. package/dist/ScopeRail.d.ts.map +1 -0
  23. package/dist/ScopeRail.js +74 -0
  24. package/dist/ScopeRail.js.map +1 -0
  25. package/dist/SectionSidebar.d.ts +11 -0
  26. package/dist/SectionSidebar.d.ts.map +1 -0
  27. package/dist/SectionSidebar.js +67 -0
  28. package/dist/SectionSidebar.js.map +1 -0
  29. package/dist/TeamCard.d.ts +5 -0
  30. package/dist/TeamCard.d.ts.map +1 -0
  31. package/dist/TeamCard.js +109 -0
  32. package/dist/TeamCard.js.map +1 -0
  33. package/dist/TopBar.d.ts +13 -0
  34. package/dist/TopBar.d.ts.map +1 -0
  35. package/dist/TopBar.js +50 -0
  36. package/dist/TopBar.js.map +1 -0
  37. package/dist/client.d.ts +11 -0
  38. package/dist/client.d.ts.map +1 -0
  39. package/dist/client.js +71 -0
  40. package/dist/client.js.map +1 -0
  41. package/dist/index.d.ts +7 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +6 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/nav.d.ts +18 -0
  46. package/dist/nav.d.ts.map +1 -0
  47. package/dist/nav.js +8 -0
  48. package/dist/nav.js.map +1 -0
  49. package/dist/types.d.ts +76 -0
  50. package/dist/types.d.ts.map +1 -0
  51. package/dist/types.js +6 -0
  52. package/dist/types.js.map +1 -0
  53. package/package.json +38 -0
@@ -0,0 +1,119 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useMemo, useState } from "react";
3
+ import styled from "styled-components";
4
+ import { AppButton, Icon, IconButton, StatusPill, v } from "@xeonr/platform-ui";
5
+ import { MAX_PINNED, useConsole } from "./ConsoleProvider.js";
6
+ // "All products": every registered product grouped by category, with host,
7
+ // blurb, enabled / enable / coming-soon state and a pin toggle for the rail.
8
+ // Registry-driven, so a new product needs no shell change to appear here.
9
+ const ORDER = ["Compute", "Data", "Developer tools", "Networking", "Observability", "Identity & access"];
10
+ const Scrim = styled.div `
11
+ position: fixed; inset: 0;
12
+ z-index: ${v.zScrim};
13
+ background: ${v.scrim};
14
+ display: flex; justify-content: center; align-items: flex-start;
15
+ padding: 64px 16px 16px;
16
+ `;
17
+ const Dialog = styled.div `
18
+ width: min(760px, 100%);
19
+ max-height: calc(100vh - 80px);
20
+ background: ${v.surface};
21
+ border: 1px solid ${v.line2};
22
+ border-radius: ${v.rModal};
23
+ box-shadow: ${v.elev};
24
+ overflow: hidden;
25
+ display: flex; flex-direction: column;
26
+ `;
27
+ const Stripe = styled.div `height: 2px; background: ${v.grad90}; flex: none;`;
28
+ const Head = styled.div `
29
+ display: flex; align-items: center; gap: 12px;
30
+ padding: 16px 20px;
31
+ border-bottom: 1px solid ${v.line};
32
+ flex: none;
33
+ h2 { margin: 0; font-size: 16px; font-weight: 600; }
34
+ p { margin: 0; font-size: 12px; color: ${v.muted}; }
35
+ `;
36
+ const Filter = styled.input `
37
+ height: 32px; width: 200px;
38
+ padding: 0 10px;
39
+ border-radius: ${v.rCtl};
40
+ background: ${v.field};
41
+ border: 1px solid ${v.fieldLine};
42
+ color: ${v.text};
43
+ font-size: 12.5px;
44
+ &::placeholder { color: ${v.faint}; }
45
+ @media (max-width: 600px) { width: 120px; }
46
+ `;
47
+ const Body = styled.div `
48
+ display: grid;
49
+ grid-template-columns: repeat(2, minmax(0, 1fr));
50
+ gap: 18px;
51
+ padding: 18px 20px;
52
+ overflow-y: auto;
53
+ @media (max-width: 700px) { grid-template-columns: minmax(0, 1fr); }
54
+ `;
55
+ const Col = styled.div `display: flex; flex-direction: column; gap: 18px;`;
56
+ const Group = styled.div `display: flex; flex-direction: column; gap: 8px;`;
57
+ const GroupLabel = styled.div `
58
+ font-size: 10.5px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase;
59
+ color: ${v.faint}; padding: 0 2px;
60
+ `;
61
+ const Row = styled.div `
62
+ display: flex; align-items: center; gap: 12px;
63
+ padding: 10px 12px;
64
+ border-radius: 10px;
65
+ border: 1px solid ${v.line};
66
+ background: ${v.surface2};
67
+ opacity: ${(p) => (p.$dim ? 0.7 : 1)};
68
+ `;
69
+ const Tile = styled.a `
70
+ width: 34px; height: 34px; flex: none;
71
+ border-radius: 9px;
72
+ display: grid; place-items: center;
73
+ color: ${(p) => p.$c};
74
+ background: ${v.hover};
75
+ text-decoration: none;
76
+ `;
77
+ const Text = styled.div `
78
+ display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto;
79
+ b { font-size: 13px; font-weight: 600; }
80
+ code { font-family: ${v.mono}; font-weight: 400; font-size: 11px; color: ${v.faint}; margin-left: 6px; }
81
+ span { font-size: 12px; color: ${v.muted}; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
82
+ a { color: inherit; text-decoration: none; }
83
+ `;
84
+ const Foot = styled.div `
85
+ display: flex; align-items: center; gap: 12px;
86
+ padding: 12px 20px;
87
+ border-top: 1px solid ${v.line};
88
+ font-size: 12px; color: ${v.faint};
89
+ flex: none;
90
+ a { margin-left: auto; color: ${v.muted}; text-decoration: none; display: inline-flex; align-items: center; gap: 6px; }
91
+ `;
92
+ function hostOf(origin) {
93
+ try {
94
+ return new URL(origin).host;
95
+ }
96
+ catch {
97
+ return origin;
98
+ }
99
+ }
100
+ export function Launcher({ onClose, authOrigin, onEnable }) {
101
+ const c = useConsole();
102
+ const [q, setQ] = useState("");
103
+ const groups = useMemo(() => {
104
+ const needle = q.trim().toLowerCase();
105
+ const list = c.products
106
+ .filter((p) => p.key !== "home")
107
+ .filter((p) => !needle || `${p.name} ${p.blurb} ${p.origin}`.toLowerCase().includes(needle));
108
+ return ORDER.map((cat) => ({ cat, items: list.filter((p) => p.category === cat) })).filter((g) => g.items.length > 0);
109
+ }, [c.products, q]);
110
+ const half = Math.ceil(groups.length / 2);
111
+ const row = (p) => {
112
+ const pinned = c.pinned.includes(p.key);
113
+ const full = !pinned && c.pinned.length >= MAX_PINNED;
114
+ const href = c.productHref(p);
115
+ return (_jsxs(Row, { "$dim": p.status === "coming_soon", children: [_jsx(Tile, { href: p.status === "live" && p.enabled ? href : undefined, "$c": p.colour, "aria-label": p.name, children: _jsx(Icon, { name: p.icon }) }), _jsxs(Text, { children: [_jsxs("b", { children: [p.status === "live" && p.enabled ? _jsx("a", { href: href, children: p.name }) : p.name, _jsx("code", { children: hostOf(p.origin) })] }), _jsx("span", { children: p.blurb })] }), p.status === "coming_soon" ? (_jsx(StatusPill, { "$tone": "info", children: "Coming soon" })) : p.enabled ? (_jsx(StatusPill, { "$tone": "ok", children: "Enabled" })) : p.canEnable ? (_jsx(AppButton, { size: "xs", onClick: () => onEnable?.(p), children: "Enable" })) : (_jsx(StatusPill, { "$tone": "mut", children: "Not enabled" })), _jsx(IconButton, { type: "button", "aria-label": pinned ? `Unpin ${p.name} from the rail` : `Pin ${p.name} to the rail`, "aria-pressed": pinned, title: full ? `Rail is full (${MAX_PINNED}). Unpin something first.` : undefined, disabled: full || p.status !== "live", onClick: () => c.togglePin(p.key), style: { color: pinned ? v.brand : v.faint }, children: _jsx(Icon, { name: pinned ? "check" : "pin" }) })] }, p.key));
116
+ };
117
+ return (_jsx(Scrim, { onMouseDown: (e) => e.target === e.currentTarget && onClose(), children: _jsxs(Dialog, { role: "dialog", "aria-modal": "true", "aria-label": "All products", children: [_jsx(Stripe, {}), _jsxs(Head, { children: [_jsxs("div", { children: [_jsx("h2", { children: "All products" }), _jsxs("p", { children: ["What ", _jsx("b", { children: c.activeTeam?.name ?? c.activeTeam?.slug ?? "this team" }), " can use. Pin up to ", MAX_PINNED, " to the rail; the rest live here and in \u2318K."] })] }), _jsxs("div", { style: { marginLeft: "auto", display: "flex", gap: 8, alignItems: "center" }, children: [_jsx(Filter, { value: q, onChange: (e) => setQ(e.target.value), placeholder: "Filter products", "aria-label": "Filter products", autoFocus: true }), _jsx(IconButton, { type: "button", "aria-label": "Close", onClick: onClose, children: _jsx(Icon, { name: "close" }) })] })] }), _jsxs(Body, { children: [_jsx(Col, { children: groups.slice(0, half).map((g) => _jsxs(Group, { children: [_jsx(GroupLabel, { children: g.cat }), g.items.map(row)] }, g.cat)) }), _jsx(Col, { children: groups.slice(half).map((g) => _jsxs(Group, { children: [_jsx(GroupLabel, { children: g.cat }), g.items.map(row)] }, g.cat)) })] }), _jsxs(Foot, { children: [_jsx("span", { children: "New products appear here automatically once registered in Auth as a console product and bound to a team." }), c.me.isOrgAdmin ? (_jsxs("a", { href: `${authOrigin}/applications`, children: ["Manage the catalogue ", _jsx(Icon, { name: "external" })] })) : null] })] }) }));
118
+ }
119
+ //# sourceMappingURL=Launcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Launcher.js","sourceRoot":"","sources":["../src/Launcher.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,MAAM,MAAM,mBAAmB,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,oBAAoB,CAAC;AAChF,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,sBAAuB,CAAC;AAG/D,2EAA2E;AAC3E,6EAA6E;AAC7E,0EAA0E;AAE1E,MAAM,KAAK,GAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,iBAAiB,EAAE,YAAY,EAAE,eAAe,EAAE,mBAAmB,CAAC,CAAC;AAE5H,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAA;;aAEX,CAAC,CAAC,MAAM;gBACL,CAAC,CAAC,KAAK;;;CAGtB,CAAC;AAEF,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAA;;;gBAGT,CAAC,CAAC,OAAO;sBACH,CAAC,CAAC,KAAK;mBACV,CAAC,CAAC,MAAM;gBACX,CAAC,CAAC,IAAI;;;CAGrB,CAAC;AAEF,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAA,4BAA4B,CAAC,CAAC,MAAM,eAAe,CAAC;AAE7E,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAA;;;6BAGM,CAAC,CAAC,IAAI;;;2CAGQ,CAAC,CAAC,KAAK;CACjD,CAAC;AAEF,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAA;;;mBAGR,CAAC,CAAC,IAAI;gBACT,CAAC,CAAC,KAAK;sBACD,CAAC,CAAC,SAAS;WACtB,CAAC,CAAC,IAAI;;4BAEW,CAAC,CAAC,KAAK;;CAElC,CAAC;AAEF,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;CAOtB,CAAC;AAEF,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAA,mDAAmD,CAAC;AAC1E,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAA,kDAAkD,CAAC;AAC3E,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAA;;WAElB,CAAC,CAAC,KAAK;CACjB,CAAC;AAEF,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAgC;;;;sBAIhC,CAAC,CAAC,IAAI;gBACZ,CAAC,CAAC,QAAQ;aACb,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;CACrC,CAAC;AAEF,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAgB;;;;WAI1B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE;gBACN,CAAC,CAAC,KAAK;;CAEtB,CAAC;AAEF,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAA;;;wBAGC,CAAC,CAAC,IAAI,+CAA+C,CAAC,CAAC,KAAK;mCACjD,CAAC,CAAC,KAAK;;CAEzC,CAAC;AAEF,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAA;;;0BAGG,CAAC,CAAC,IAAI;4BACJ,CAAC,CAAC,KAAK;;kCAED,CAAC,CAAC,KAAK;CACxC,CAAC;AAEF,SAAS,MAAM,CAAC,MAAc;IAC5B,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC;IAChB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAA8F;IACpJ,MAAM,CAAC,GAAG,UAAU,EAAE,CAAC;IACvB,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE;QAC1B,MAAM,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ;aACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,MAAM,CAAC;aAC/B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QAC/F,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACxH,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC;IACpB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAE1C,MAAM,GAAG,GAAG,CAAC,CAAU,EAAE,EAAE;QACzB,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,IAAI,UAAU,CAAC;QACtD,MAAM,IAAI,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QAC9B,OAAO,CACL,MAAC,GAAG,YAAmB,CAAC,CAAC,MAAM,KAAK,aAAa,aAC/C,KAAC,IAAI,IAAC,IAAI,EAAE,CAAC,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,QAAM,CAAC,CAAC,MAAM,gBAAc,CAAC,CAAC,IAAI,YAC/F,KAAC,IAAI,IAAC,IAAI,EAAE,CAAC,CAAC,IAAI,GAAI,GACjB,EACP,MAAC,IAAI,eACH,wBACG,CAAC,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAG,IAAI,EAAE,IAAI,YAAG,CAAC,CAAC,IAAI,GAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EACxE,yBAAO,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,GAAQ,IAC7B,EACJ,yBAAO,CAAC,CAAC,KAAK,GAAQ,IACjB,EACN,CAAC,CAAC,MAAM,KAAK,aAAa,CAAC,CAAC,CAAC,CAC5B,KAAC,UAAU,aAAO,MAAM,4BAAyB,CAClD,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CACd,KAAC,UAAU,aAAO,IAAI,wBAAqB,CAC5C,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAChB,KAAC,SAAS,IAAC,IAAI,EAAC,IAAI,EAAC,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,uBAAoB,CACtE,CAAC,CAAC,CAAC,CACF,KAAC,UAAU,aAAO,KAAK,4BAAyB,CACjD,EACD,KAAC,UAAU,IACT,IAAI,EAAC,QAAQ,gBACD,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,cAAc,kBACpE,MAAM,EACpB,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,iBAAiB,UAAU,2BAA2B,CAAC,CAAC,CAAC,SAAS,EAChF,QAAQ,EAAE,IAAI,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,EACrC,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,EACjC,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,YAE5C,KAAC,IAAI,IAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,GAAI,GAC7B,KA9BL,CAAC,CAAC,GAAG,CA+BT,CACP,CAAC;IACJ,CAAC,CAAC;IAEF,OAAO,CACL,KAAC,KAAK,IAAC,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,aAAa,IAAI,OAAO,EAAE,YAClE,MAAC,MAAM,IAAC,IAAI,EAAC,QAAQ,gBAAY,MAAM,gBAAY,cAAc,aAC/D,KAAC,MAAM,KAAG,EACV,MAAC,IAAI,eACH,0BACE,wCAAqB,EACrB,iCACO,sBAAI,CAAC,CAAC,UAAU,EAAE,IAAI,IAAI,CAAC,CAAC,UAAU,EAAE,IAAI,IAAI,WAAW,GAAK,0BAAqB,UAAU,wDAClG,IACA,EACN,eAAK,KAAK,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,aAC/E,KAAC,MAAM,IAAC,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,WAAW,EAAC,iBAAiB,gBAAY,iBAAiB,EAAC,SAAS,SAAG,EAChI,KAAC,UAAU,IAAC,IAAI,EAAC,QAAQ,gBAAY,OAAO,EAAC,OAAO,EAAE,OAAO,YAAE,KAAC,IAAI,IAAC,IAAI,EAAC,OAAO,GAAG,GAAa,IAC7F,IACD,EACP,MAAC,IAAI,eACH,KAAC,GAAG,cAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAC,KAAK,eAAa,KAAC,UAAU,cAAE,CAAC,CAAC,GAAG,GAAc,EAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAxD,CAAC,CAAC,GAAG,CAA4D,CAAC,GAAO,EAC5H,KAAC,GAAG,cAAE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAC,KAAK,eAAa,KAAC,UAAU,cAAE,CAAC,CAAC,GAAG,GAAc,EAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAxD,CAAC,CAAC,GAAG,CAA4D,CAAC,GAAO,IACpH,EACP,MAAC,IAAI,eACH,sIAAqH,EACpH,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CACjB,aAAG,IAAI,EAAE,GAAG,UAAU,eAAe,sCAAuB,KAAC,IAAI,IAAC,IAAI,EAAC,UAAU,GAAG,IAAI,CACzF,CAAC,CAAC,CAAC,IAAI,IACH,IACA,GACH,CACT,CAAC;AACJ,CAAC"}
@@ -0,0 +1,11 @@
1
+ export declare const RailButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Merged<Omit<import("react").DetailedHTMLProps<import("react").AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>, "style"> & {
2
+ style?: import("react").CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
3
+ }, {
4
+ $on?: boolean | undefined;
5
+ $accent?: string | undefined;
6
+ }>> & string;
7
+ export declare function ScopeRail({ onOpenLauncher, onOpenAccount }: {
8
+ onOpenLauncher: () => void;
9
+ onOpenAccount: () => void;
10
+ }): import("react").JSX.Element;
11
+ //# sourceMappingURL=ScopeRail.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ScopeRail.d.ts","sourceRoot":"","sources":["../src/ScopeRail.tsx"],"names":[],"mappings":"AAqCA,eAAO,MAAM,UAAU;;;UAAoB,OAAO,GAAG,SAAS;cAAY,MAAM,GAAG,SAAS;YAa3F,CAAC;AAyBF,wBAAgB,SAAS,CAAC,EAAE,cAAc,EAAE,aAAa,EAAE,EAAE;IAAE,cAAc,EAAE,MAAM,IAAI,CAAC;IAAC,aAAa,EAAE,MAAM,IAAI,CAAA;CAAE,+BAwCrH"}
@@ -0,0 +1,74 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import styled from "styled-components";
3
+ import { Icon, v, useTheme } from "@xeonr/platform-ui";
4
+ import { useConsole } from "./ConsoleProvider.js";
5
+ // The far-left product rail: Home, the pinned products for this team as
6
+ // coloured tiles, the All-products launcher, then theme and account.
7
+ // Cross-product tiles are plain <a> to another origin, carrying the team slug.
8
+ const Rail = styled.nav `
9
+ width: 56px;
10
+ flex: none;
11
+ display: flex;
12
+ flex-direction: column;
13
+ align-items: center;
14
+ gap: 6px;
15
+ padding: 12px 0;
16
+ background: ${v.sidebar};
17
+ border-right: 1px solid ${v.line};
18
+ `;
19
+ const Logo = styled.a `
20
+ width: 40px; height: 40px;
21
+ border-radius: 12px;
22
+ background: ${v.grad};
23
+ color: ${v.onBrand};
24
+ display: grid; place-items: center;
25
+ font-weight: 700; font-size: 17px;
26
+ margin-bottom: 6px;
27
+ text-decoration: none;
28
+ `;
29
+ const Divider = styled.div `
30
+ width: 24px; height: 1px;
31
+ background: ${v.line2};
32
+ margin: 4px 0;
33
+ `;
34
+ export const RailButton = styled.a `
35
+ width: 40px; height: 40px;
36
+ border-radius: 10px;
37
+ display: grid; place-items: center;
38
+ color: ${(p) => p.$accent ?? v.muted};
39
+ background: ${(p) => (p.$on ? v.brand16 : "transparent")};
40
+ box-shadow: ${(p) => (p.$on ? `inset 0 0 0 1px ${v.brand55}` : "none")};
41
+ border: 0;
42
+ cursor: pointer;
43
+ text-decoration: none;
44
+ font-size: 18px;
45
+ transition: background 0.14s ease, color 0.14s ease;
46
+ &:hover { background: ${(p) => (p.$on ? v.brand16 : v.hover)}; color: ${(p) => p.$accent ?? v.text}; }
47
+ `;
48
+ const Avatar = styled.span `
49
+ width: 30px; height: 30px;
50
+ border-radius: 999px;
51
+ background: ${v.grad};
52
+ color: ${v.onBrand};
53
+ display: grid; place-items: center;
54
+ font-size: 12px; font-weight: 700;
55
+ position: relative;
56
+ `;
57
+ const Dot = styled.span `
58
+ position: absolute; top: -2px; right: -2px;
59
+ width: 9px; height: 9px; border-radius: 999px;
60
+ background: ${v.danger};
61
+ box-shadow: 0 0 0 2px ${v.sidebar};
62
+ `;
63
+ const Spacer = styled.div `flex: 1 1 auto;`;
64
+ function initials(name) {
65
+ return name.split(/\s+/).map((s) => s[0] ?? "").join("").slice(0, 2).toUpperCase();
66
+ }
67
+ export function ScopeRail({ onOpenLauncher, onOpenAccount }) {
68
+ const c = useConsole();
69
+ const theme = useTheme();
70
+ const home = c.products.find((p) => p.key === "home");
71
+ const tiles = c.products.filter((p) => c.pinned.includes(p.key) || p.key === c.product).filter((p) => p.key !== "home");
72
+ return (_jsxs(Rail, { "aria-label": "Products", children: [_jsx(Logo, { href: home ? c.productHref(home) : "/", "aria-label": "Xeonr Cloud Console", children: "X" }), _jsx(RailButton, { href: home ? c.productHref(home) : "/", "$on": c.product === "home", "aria-label": "Home", title: "Home", children: _jsx(Icon, { name: "home" }) }), _jsx(Divider, {}), tiles.map((p) => (_jsx(RailButton, { href: c.productHref(p), "$on": p.key === c.product, "$accent": p.colour, "aria-label": p.name, title: p.name, children: _jsx(Icon, { name: p.icon }) }, p.key))), _jsx(RailButton, { as: "button", type: "button", onClick: onOpenLauncher, "aria-label": "All products", title: "All products", children: _jsx(Icon, { name: "launcher" }) }), _jsx(Spacer, {}), _jsx(RailButton, { as: "button", type: "button", onClick: theme.cycle, "aria-label": `Theme: ${theme.pref}`, title: `Theme: ${theme.pref}`, children: _jsx(Icon, { name: theme.pref === "system" ? "system" : theme.resolved === "dark" ? "moon" : "sun" }) }), _jsx(RailButton, { as: "button", type: "button", onClick: onOpenAccount, "aria-label": "Account menu", title: c.me.displayName, children: _jsxs(Avatar, { children: [initials(c.me.displayName), c.invitations.length > 0 ? _jsx(Dot, { "aria-label": `${c.invitations.length} pending invitations` }) : null] }) })] }));
73
+ }
74
+ //# sourceMappingURL=ScopeRail.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ScopeRail.js","sourceRoot":"","sources":["../src/ScopeRail.tsx"],"names":[],"mappings":";AAAA,OAAO,MAAM,MAAM,mBAAmB,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAuB,CAAC;AAEnD,wEAAwE;AACxE,qEAAqE;AACrE,+EAA+E;AAE/E,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;gBAQP,CAAC,CAAC,OAAO;4BACG,CAAC,CAAC,IAAI;CACjC,CAAC;AAEF,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAA;;;gBAGL,CAAC,CAAC,IAAI;WACX,CAAC,CAAC,OAAO;;;;;CAKnB,CAAC;AAEF,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAA;;gBAEV,CAAC,CAAC,KAAK;;CAEtB,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAA6D;;;;WAIpF,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,KAAK;gBACtB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC;gBAC1C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;;;;;;0BAM9C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,IAAI;CACnG,CAAC;AAEF,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAA;;;gBAGV,CAAC,CAAC,IAAI;WACX,CAAC,CAAC,OAAO;;;;CAInB,CAAC;AAEF,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAA;;;gBAGP,CAAC,CAAC,MAAM;0BACE,CAAC,CAAC,OAAO;CAClC,CAAC;AAEF,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAA,iBAAiB,CAAC;AAE3C,SAAS,QAAQ,CAAC,IAAY;IAC5B,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;AACrF,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,EAAE,cAAc,EAAE,aAAa,EAA6D;IACpH,MAAM,CAAC,GAAG,UAAU,EAAE,CAAC;IACvB,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IACzB,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC;IACtD,MAAM,KAAK,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC;IAExH,OAAO,CACL,MAAC,IAAI,kBAAY,UAAU,aACzB,KAAC,IAAI,IAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,gBAAa,qBAAqB,kBAAS,EACvF,KAAC,UAAU,IAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,SAAO,CAAC,CAAC,OAAO,KAAK,MAAM,gBAAa,MAAM,EAAC,KAAK,EAAC,MAAM,YAC3G,KAAC,IAAI,IAAC,IAAI,EAAC,MAAM,GAAG,GACT,EACb,KAAC,OAAO,KAAG,EACV,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAChB,KAAC,UAAU,IAET,IAAI,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SACjB,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,OAAO,aACf,CAAC,CAAC,MAAM,gBACL,CAAC,CAAC,IAAI,EAClB,KAAK,EAAE,CAAC,CAAC,IAAI,YAEb,KAAC,IAAI,IAAC,IAAI,EAAE,CAAC,CAAC,IAAI,GAAI,IAPjB,CAAC,CAAC,GAAG,CAQC,CACd,CAAC,EACF,KAAC,UAAU,IAAC,EAAE,EAAC,QAAQ,EAAC,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAE,cAAc,gBAAa,cAAc,EAAC,KAAK,EAAC,cAAc,YAC3G,KAAC,IAAI,IAAC,IAAI,EAAC,UAAU,GAAG,GACb,EACb,KAAC,MAAM,KAAG,EACV,KAAC,UAAU,IAAC,EAAE,EAAC,QAAQ,EAAC,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAE,KAAK,CAAC,KAAK,gBAAc,UAAU,KAAK,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,UAAU,KAAK,CAAC,IAAI,EAAE,YAC3H,KAAC,IAAI,IAAC,IAAI,EAAE,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,GAAI,GACpF,EACb,KAAC,UAAU,IAAC,EAAE,EAAC,QAAQ,EAAC,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAE,aAAa,gBAAa,cAAc,EAAC,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,WAAW,YAC7G,MAAC,MAAM,eACJ,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,EAC1B,CAAC,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAC,GAAG,kBAAa,GAAG,CAAC,CAAC,WAAW,CAAC,MAAM,sBAAsB,GAAI,CAAC,CAAC,CAAC,IAAI,IAC9F,GACE,IACR,CACR,CAAC;AACJ,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { NavGroup } from "./nav.ts";
2
+ export declare function SectionSidebar({ open, base, groups, productLabel, authOrigin, docsHref, onNavigate, }: {
3
+ open: boolean;
4
+ base: string;
5
+ groups: NavGroup[];
6
+ productLabel: string;
7
+ authOrigin: string;
8
+ docsHref?: string | undefined;
9
+ onNavigate?: (() => void) | undefined;
10
+ }): import("react").JSX.Element;
11
+ //# sourceMappingURL=SectionSidebar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SectionSidebar.d.ts","sourceRoot":"","sources":["../src/SectionSidebar.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAoEzC,wBAAgB,cAAc,CAAC,EAC7B,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,UAAU,GACX,EAAE;IACD,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,UAAU,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;CACvC,+BAuCA"}
@@ -0,0 +1,67 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import styled from "styled-components";
3
+ import { NavLink } from "react-router-dom";
4
+ import { Icon, v } from "@xeonr/platform-ui";
5
+ import { TeamCard } from "./TeamCard.js";
6
+ // 224px section sidebar: the shell's TeamCard on top, then the product's own
7
+ // registry. In-product links are router NavLinks relative to `base` (the
8
+ // product's team root, e.g. "/platform-core"); items with `href` open on
9
+ // another host and get the external mark.
10
+ const Aside = styled.aside `
11
+ width: 224px;
12
+ flex: none;
13
+ display: flex;
14
+ flex-direction: column;
15
+ background: ${v.sidebar};
16
+ border-right: 1px solid ${v.line};
17
+ padding: 12px 10px;
18
+ overflow-y: auto;
19
+ @media (max-width: 900px) {
20
+ position: fixed;
21
+ inset: 2px auto 0 56px;
22
+ z-index: ${v.zNav};
23
+ transform: translateX(${(p) => (p.$open ? "0" : "-110%")});
24
+ transition: transform 0.18s cubic-bezier(0.2, 0.7, 0.3, 1);
25
+ box-shadow: ${v.elev};
26
+ }
27
+ `;
28
+ const List = styled.div `display: flex; flex-direction: column; gap: 2px; margin-top: 6px;`;
29
+ const GroupLabel = styled.div `
30
+ font-size: 10.5px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase;
31
+ color: ${v.faint}; padding: 14px 10px 6px;
32
+ `;
33
+ const itemCss = `
34
+ display: flex; align-items: center; gap: 10px;
35
+ height: 34px; padding: 0 10px;
36
+ border-radius: 8px;
37
+ color: ${v.muted};
38
+ font-size: 13px; font-weight: 500;
39
+ text-decoration: none;
40
+ transition: background 0.14s ease, color 0.14s ease;
41
+ &:hover { background: ${v.hover}; color: ${v.text}; }
42
+ svg { font-size: 14px; width: 16px; }
43
+ `;
44
+ const Item = styled(NavLink) `
45
+ ${itemCss}
46
+ &.active { background: ${v.brand12}; color: ${v.text}; }
47
+ `;
48
+ const ExtItem = styled.a `
49
+ ${itemCss}
50
+ .ext { margin-left: auto; color: ${v.faint}; font-size: 11px; }
51
+ `;
52
+ const Pill = styled.span `
53
+ margin-left: auto;
54
+ font-size: 11px; line-height: 18px;
55
+ color: ${v.faint};
56
+ background: ${v.field};
57
+ border: 1px solid ${v.fieldLine};
58
+ border-radius: 999px;
59
+ padding: 0 7px;
60
+ `;
61
+ const Spacer = styled.div `flex: 1 1 auto;`;
62
+ export function SectionSidebar({ open, base, groups, productLabel, authOrigin, docsHref, onNavigate, }) {
63
+ return (_jsxs(Aside, { "$open": open, children: [_jsx(TeamCard, { productLabel: productLabel, authOrigin: authOrigin }), _jsx(List, { children: groups.map((g, gi) => (_jsxs("div", { children: [g.label ? _jsx(GroupLabel, { children: g.label }) : null, g.items
64
+ .filter((i) => !i.hidden)
65
+ .map((i) => i.href ? (_jsxs(ExtItem, { href: i.href, children: [_jsx(Icon, { name: i.icon }), _jsx("span", { children: i.label }), i.count !== undefined ? _jsx(Pill, { children: i.count }) : null, _jsx(Icon, { className: "ext", name: "external" })] }, i.key)) : (_jsxs(Item, { to: i.path ? `${base}/${i.path}` : base, end: i.path === "", onClick: onNavigate, children: [_jsx(Icon, { name: i.icon }), _jsx("span", { children: i.label }), i.count !== undefined ? _jsx(Pill, { children: i.count }) : null] }, i.key)))] }, g.label ?? gi))) }), _jsx(Spacer, {}), docsHref ? (_jsxs(ExtItem, { href: docsHref, children: [_jsx(Icon, { name: "docs" }), _jsx("span", { children: "API docs" }), _jsx(Icon, { className: "ext", name: "external" })] })) : null] }));
66
+ }
67
+ //# sourceMappingURL=SectionSidebar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SectionSidebar.js","sourceRoot":"","sources":["../src/SectionSidebar.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare function TeamCard({ productLabel, authOrigin }: {
2
+ productLabel: string;
3
+ authOrigin: string;
4
+ }): import("react").JSX.Element;
5
+ //# sourceMappingURL=TeamCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TeamCard.d.ts","sourceRoot":"","sources":["../src/TeamCard.tsx"],"names":[],"mappings":"AA2FA,wBAAgB,QAAQ,CAAC,EAAE,YAAY,EAAE,UAAU,EAAE,EAAE;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,+BAgElG"}
@@ -0,0 +1,109 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from "react";
3
+ import styled from "styled-components";
4
+ import { Icon, v } from "@xeonr/platform-ui";
5
+ import { useConsole } from "./ConsoleProvider.js";
6
+ // The team switcher card at the top of the section sidebar. It belongs to the
7
+ // shell; the sections under it belong to the product. Team management itself
8
+ // lives in the auth portal (CP and Functions each built and deleted their
9
+ // own), so the menu links out for that and only *switches* here.
10
+ const Card = styled.button `
11
+ width: 100%;
12
+ text-align: left;
13
+ display: flex;
14
+ align-items: center;
15
+ gap: 10px;
16
+ padding: 10px;
17
+ border-radius: ${v.rCard};
18
+ background: ${v.surface};
19
+ border: 1px solid ${v.line2};
20
+ box-shadow: ${v.elev};
21
+ color: ${v.text};
22
+ cursor: pointer;
23
+ transition: border-color 0.14s ease;
24
+ &:hover { border-color: ${v.brand55}; }
25
+ `;
26
+ const Tile = styled.span `
27
+ width: 34px; height: 34px; flex: none;
28
+ border-radius: 9px;
29
+ background: ${(p) => (p.$src ? `url(${p.$src}) center/cover` : v.grad)};
30
+ color: ${v.onBrand};
31
+ display: grid; place-items: center;
32
+ font-weight: 700; font-size: 13px;
33
+ `;
34
+ const Text = styled.span `
35
+ display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto;
36
+ b { font-size: 13px; font-weight: 600; line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
37
+ span { font-size: 11px; color: ${v.faint}; line-height: 1.3; text-transform: capitalize; }
38
+ `;
39
+ const Chev = styled.span `color: ${v.faint}; flex: none; display: grid;`;
40
+ const Menu = styled.div `
41
+ position: absolute;
42
+ left: 10px; right: 10px; top: 66px;
43
+ z-index: ${v.zPop};
44
+ background: ${v.surface};
45
+ border: 1px solid ${v.line2};
46
+ border-radius: ${v.rCard};
47
+ box-shadow: ${v.elev};
48
+ padding: 6px;
49
+ display: flex; flex-direction: column; gap: 2px;
50
+ `;
51
+ const MenuLabel = styled.div `
52
+ font-size: 10.5px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase;
53
+ color: ${v.faint}; padding: 8px 8px 4px;
54
+ `;
55
+ const Item = styled.button `
56
+ display: flex; align-items: center; gap: 10px;
57
+ width: 100%; text-align: left;
58
+ padding: 7px 8px;
59
+ border-radius: ${v.rCtl};
60
+ font-size: 13px;
61
+ color: ${v.text};
62
+ background: ${(p) => (p.$on ? v.brand12 : "transparent")};
63
+ cursor: pointer;
64
+ &:hover { background: ${(p) => (p.$on ? v.brand12 : v.hover)}; }
65
+ small { margin-left: auto; color: ${v.faint}; font-size: 11px; text-transform: capitalize; }
66
+ `;
67
+ const ItemLink = styled.a `
68
+ display: flex; align-items: center; gap: 10px;
69
+ padding: 7px 8px;
70
+ border-radius: ${v.rCtl};
71
+ font-size: 13px;
72
+ color: ${v.muted};
73
+ text-decoration: none;
74
+ &:hover { background: ${v.hover}; color: ${v.text}; }
75
+ svg { margin-left: auto; font-size: 11px; }
76
+ `;
77
+ const Hair = styled.div `height: 1px; background: ${v.line}; margin: 4px 0;`;
78
+ function initials(name) {
79
+ return name.split(/[\s-]+/).map((s) => s[0] ?? "").join("").slice(0, 2).toUpperCase();
80
+ }
81
+ export function TeamCard({ productLabel, authOrigin }) {
82
+ const c = useConsole();
83
+ const [open, setOpen] = useState(false);
84
+ const ref = useRef(null);
85
+ useEffect(() => {
86
+ if (!open)
87
+ return;
88
+ const onDoc = (e) => {
89
+ if (ref.current && !ref.current.contains(e.target))
90
+ setOpen(false);
91
+ };
92
+ const onKey = (e) => {
93
+ if (e.key === "Escape")
94
+ setOpen(false);
95
+ };
96
+ document.addEventListener("mousedown", onDoc);
97
+ document.addEventListener("keydown", onKey);
98
+ return () => {
99
+ document.removeEventListener("mousedown", onDoc);
100
+ document.removeEventListener("keydown", onKey);
101
+ };
102
+ }, [open]);
103
+ const t = c.activeTeam;
104
+ return (_jsxs("div", { ref: ref, style: { position: "relative" }, children: [_jsxs(Card, { type: "button", "aria-haspopup": "menu", "aria-expanded": open, onClick: () => setOpen((o) => !o), children: [_jsx(Tile, { "$src": t?.avatarUrl, children: t ? initials(t.name || t.slug) : "?" }), _jsxs(Text, { children: [_jsx("b", { children: t ? t.name || t.slug : "Choose a team" }), _jsx("span", { children: t ? `${t.role} · ${productLabel}` : productLabel })] }), _jsx(Chev, { children: _jsx(Icon, { name: "chevron-down", size: 14 }) })] }), open ? (_jsxs(Menu, { role: "menu", children: [_jsx(MenuLabel, { children: "Your teams" }), c.teams.map((team) => (_jsxs(Item, { role: "menuitemradio", "aria-checked": team.id === t?.id, "$on": team.id === t?.id, onClick: () => {
105
+ setOpen(false);
106
+ c.setTeam(team.id);
107
+ }, children: [_jsx(Tile, { "$src": team.avatarUrl, style: { width: 24, height: 24, fontSize: 10, borderRadius: 7 }, children: initials(team.name || team.slug) }), team.name || team.slug, _jsx("small", { children: team.role })] }, team.id))), _jsx(Hair, {}), t ? (_jsxs(ItemLink, { href: `${authOrigin}/teams/${encodeURIComponent(t.slug)}`, children: [_jsx(Icon, { name: "members" }), " Members & roles ", _jsx(Icon, { name: "external" })] })) : null, _jsxs(ItemLink, { href: `${authOrigin}/teams?new=1`, children: [_jsx(Icon, { name: "add" }), " New team ", _jsx(Icon, { name: "external" })] })] })) : null] }));
108
+ }
109
+ //# sourceMappingURL=TeamCard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TeamCard.js","sourceRoot":"","sources":["../src/TeamCard.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export interface Crumb {
2
+ label: string;
3
+ href?: string | undefined;
4
+ }
5
+ export declare function TopBar({ crumbs, searchPlaceholder, onBurger, onSearch, notifications, onNotifications, }: {
6
+ crumbs: Crumb[];
7
+ searchPlaceholder: string;
8
+ onBurger: () => void;
9
+ onSearch: () => void;
10
+ notifications?: number | undefined;
11
+ onNotifications?: (() => void) | undefined;
12
+ }): import("react").JSX.Element;
13
+ //# sourceMappingURL=TopBar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TopBar.d.ts","sourceRoot":"","sources":["../src/TopBar.tsx"],"names":[],"mappings":"AAqDA,MAAM,WAAW,KAAK;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B;AAED,wBAAgB,MAAM,CAAC,EACrB,MAAM,EACN,iBAAiB,EACjB,QAAQ,EACR,QAAQ,EACR,aAAiB,EACjB,eAAe,GAChB,EAAE;IACD,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,eAAe,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;CAC5C,+BA8BA"}
package/dist/TopBar.js ADDED
@@ -0,0 +1,50 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import styled from "styled-components";
3
+ import { Icon, IconButton, v } from "@xeonr/platform-ui";
4
+ // Breadcrumb whose first crumb is always the team, then the product, then
5
+ // whatever the screen adds; ⌘K trigger; notifications.
6
+ const Bar = styled.header `
7
+ height: 52px;
8
+ flex: none;
9
+ display: flex;
10
+ align-items: center;
11
+ gap: 8px;
12
+ padding: 0 20px;
13
+ border-bottom: 1px solid ${v.line};
14
+ background: ${v.bg};
15
+ position: sticky; top: 0;
16
+ z-index: calc(${v.zNav} - 2);
17
+ `;
18
+ const Crumb = styled.span `
19
+ font-size: 13px;
20
+ color: ${(p) => (p.$last ? v.text : v.muted)};
21
+ font-weight: ${(p) => (p.$last ? 600 : 500)};
22
+ white-space: nowrap;
23
+ overflow: hidden; text-overflow: ellipsis;
24
+ max-width: 260px;
25
+ `;
26
+ const Sep = styled.span `color: ${v.faint}; display: grid; svg { font-size: 11px; }`;
27
+ const Search = styled.button `
28
+ height: 34px;
29
+ width: min(320px, 32vw);
30
+ display: flex; align-items: center; gap: 10px;
31
+ padding: 0 12px;
32
+ border-radius: ${v.rCtl};
33
+ background: ${v.field};
34
+ border: 1px solid ${v.fieldLine};
35
+ color: ${v.faint};
36
+ font-size: 13px;
37
+ cursor: text;
38
+ span { flex: 1 1 auto; text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
39
+ kbd { font: inherit; font-size: 11px; border: 1px solid ${v.line2}; border-radius: 5px; padding: 1px 6px; }
40
+ &:hover { border-color: ${v.brand55}; }
41
+ @media (max-width: 700px) { width: 34px; padding: 0; justify-content: center; span, kbd { display: none; } }
42
+ `;
43
+ const Spacer = styled.div `flex: 1 1 auto;`;
44
+ const Burger = styled(IconButton) `
45
+ @media (min-width: 901px) { display: none; }
46
+ `;
47
+ export function TopBar({ crumbs, searchPlaceholder, onBurger, onSearch, notifications = 0, onNotifications, }) {
48
+ return (_jsxs(Bar, { children: [_jsx(Burger, { type: "button", "aria-label": "Menu", onClick: onBurger, children: _jsx(Icon, { name: "menu" }) }), crumbs.map((c, i) => (_jsxs("span", { style: { display: "contents" }, children: [i > 0 ? _jsx(Sep, { children: _jsx(Icon, { name: "chevron-right" }) }) : null, c.href && i < crumbs.length - 1 ? (_jsx(Crumb, { as: "a", href: c.href, style: { textDecoration: "none" }, children: c.label })) : (_jsx(Crumb, { "$last": i === crumbs.length - 1, children: c.label }))] }, `${c.label}-${i}`))), _jsx(Spacer, {}), _jsxs(Search, { type: "button", onClick: onSearch, "aria-label": "Search and commands", children: [_jsx(Icon, { name: "search" }), _jsx("span", { children: searchPlaceholder }), _jsx("kbd", { children: "\u2318K" })] }), onNotifications ? (_jsxs(IconButton, { type: "button", "$size": 34, "aria-label": notifications ? `${notifications} notifications` : "Notifications", onClick: onNotifications, style: { position: "relative" }, children: [_jsx(Icon, { name: "bell" }), notifications > 0 ? (_jsx("span", { style: { position: "absolute", top: 6, right: 7, width: 8, height: 8, borderRadius: 999, background: v.danger } })) : null] })) : null] }));
49
+ }
50
+ //# sourceMappingURL=TopBar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TopBar.js","sourceRoot":"","sources":["../src/TopBar.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { ConsoleClient, ConsoleContext, Invitation, Me, Product, SearchResult } from "./types.ts";
2
+ export declare function httpConsoleClient(base?: string): ConsoleClient;
3
+ export interface MockFixtures {
4
+ me: Me;
5
+ products: Product[];
6
+ context?: Partial<ConsoleContext> | undefined;
7
+ invitations?: Invitation[] | undefined;
8
+ search?: ((query: string) => SearchResult[]) | undefined;
9
+ }
10
+ export declare function mockConsoleClient(fx: MockFixtures, delayMs?: number): ConsoleClient;
11
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAMvG,wBAAgB,iBAAiB,CAAC,IAAI,SAAa,GAAG,aAAa,CAyBlE;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,EAAE,CAAC;IACP,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAC9C,WAAW,CAAC,EAAE,UAAU,EAAE,GAAG,SAAS,CAAC;IACvC,MAAM,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,YAAY,EAAE,CAAC,GAAG,SAAS,CAAC;CAC1D;AAKD,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,YAAY,EAAE,OAAO,SAAM,GAAG,aAAa,CAkChF"}
package/dist/client.js ADDED
@@ -0,0 +1,71 @@
1
+ // httpConsoleClient talks to the *product's own* origin. The xeonr/bff module
2
+ // serves these paths and proxies to auth with the server-held access token, so
3
+ // there is no CORS and no browser-held credential — which is what makes the
4
+ // shell work on a console hosted on any domain.
5
+ export function httpConsoleClient(base = "/console") {
6
+ async function call(path, init) {
7
+ const res = await fetch(`${base}${path}`, {
8
+ credentials: "same-origin",
9
+ headers: { "content-type": "application/json", ...(init?.headers ?? {}) },
10
+ ...init,
11
+ });
12
+ if (res.status === 401) {
13
+ // The BFF answers 401 only when there is no session at all; it has
14
+ // already tried a silent prompt=none entry, so this is a real sign-in.
15
+ window.location.assign(`/auth/login?next=${encodeURIComponent(window.location.pathname + window.location.search)}`);
16
+ return new Promise(() => { });
17
+ }
18
+ if (!res.ok)
19
+ throw new Error(`${path}: ${res.status}`);
20
+ return (await res.json());
21
+ }
22
+ return {
23
+ me: () => call("/me"),
24
+ listProducts: (team) => call(`/products${team ? `?team=${encodeURIComponent(team)}` : ""}`),
25
+ getContext: () => call("/context"),
26
+ setContext: (patch) => call("/context", { method: "PATCH", body: JSON.stringify(patch) }),
27
+ listMyInvitations: () => call("/invitations"),
28
+ search: (query, team) => call(`/search?q=${encodeURIComponent(query)}${team ? `&team=${encodeURIComponent(team)}` : ""}`),
29
+ };
30
+ }
31
+ // mockConsoleClient drives the shell with no server at all — the same idea as
32
+ // container-platform's `pnpm dev:mock`. Context writes persist to localStorage
33
+ // so pinning and team switching feel real across reloads.
34
+ export function mockConsoleClient(fx, delayMs = 120) {
35
+ const KEY = "xnr.console.mock.ctx";
36
+ const wait = (x) => new Promise((r) => setTimeout(() => r(x), delayMs));
37
+ function readCtx() {
38
+ let stored = {};
39
+ try {
40
+ stored = JSON.parse(localStorage.getItem(KEY) ?? "{}");
41
+ }
42
+ catch {
43
+ stored = {};
44
+ }
45
+ return {
46
+ activeTeam: fx.me.teams[0]?.id ?? null,
47
+ pinnedProducts: fx.products.filter((p) => p.pinnedByDefault).map((p) => p.key),
48
+ theme: "system",
49
+ ...fx.context,
50
+ ...stored,
51
+ };
52
+ }
53
+ return {
54
+ me: () => wait(fx.me),
55
+ listProducts: () => wait(fx.products),
56
+ getContext: () => wait(readCtx()),
57
+ setContext: (patch) => {
58
+ const next = { ...readCtx(), ...patch };
59
+ try {
60
+ localStorage.setItem(KEY, JSON.stringify(next));
61
+ }
62
+ catch {
63
+ /* storage may be unavailable; the in-memory value still returns */
64
+ }
65
+ return wait(next);
66
+ },
67
+ listMyInvitations: () => wait(fx.invitations ?? []),
68
+ search: (q) => wait(fx.search ? fx.search(q) : []),
69
+ };
70
+ }
71
+ //# sourceMappingURL=client.js.map