@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.
- package/dist/AccountMenu.d.ts +5 -0
- package/dist/AccountMenu.d.ts.map +1 -0
- package/dist/AccountMenu.js +71 -0
- package/dist/AccountMenu.js.map +1 -0
- package/dist/CommandPalette.d.ts +8 -0
- package/dist/CommandPalette.d.ts.map +1 -0
- package/dist/CommandPalette.js +160 -0
- package/dist/CommandPalette.js.map +1 -0
- package/dist/ConsoleProvider.d.ts +36 -0
- package/dist/ConsoleProvider.d.ts.map +1 -0
- package/dist/ConsoleProvider.js +110 -0
- package/dist/ConsoleProvider.js.map +1 -0
- package/dist/ConsoleShell.d.ts +20 -0
- package/dist/ConsoleShell.d.ts.map +1 -0
- package/dist/ConsoleShell.js +81 -0
- package/dist/ConsoleShell.js.map +1 -0
- package/dist/Launcher.d.ts +7 -0
- package/dist/Launcher.d.ts.map +1 -0
- package/dist/Launcher.js +119 -0
- package/dist/Launcher.js.map +1 -0
- package/dist/ScopeRail.d.ts +11 -0
- package/dist/ScopeRail.d.ts.map +1 -0
- package/dist/ScopeRail.js +74 -0
- package/dist/ScopeRail.js.map +1 -0
- package/dist/SectionSidebar.d.ts +11 -0
- package/dist/SectionSidebar.d.ts.map +1 -0
- package/dist/SectionSidebar.js +67 -0
- package/dist/SectionSidebar.js.map +1 -0
- package/dist/TeamCard.d.ts +5 -0
- package/dist/TeamCard.d.ts.map +1 -0
- package/dist/TeamCard.js +109 -0
- package/dist/TeamCard.js.map +1 -0
- package/dist/TopBar.d.ts +13 -0
- package/dist/TopBar.d.ts.map +1 -0
- package/dist/TopBar.js +50 -0
- package/dist/TopBar.js.map +1 -0
- package/dist/client.d.ts +11 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +71 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/nav.d.ts +18 -0
- package/dist/nav.d.ts.map +1 -0
- package/dist/nav.js +8 -0
- package/dist/nav.js.map +1 -0
- package/dist/types.d.ts +76 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +38 -0
package/dist/Launcher.js
ADDED
|
@@ -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":"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"}
|
|
@@ -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 @@
|
|
|
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"}
|
package/dist/TeamCard.js
ADDED
|
@@ -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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"}
|
package/dist/TopBar.d.ts
ADDED
|
@@ -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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"}
|
package/dist/client.d.ts
ADDED
|
@@ -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
|