@platned/ui 0.1.3 → 0.3.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 +2 -19
- package/dist/index.cjs +3286 -534
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1522 -104
- package/dist/index.d.ts +1522 -104
- package/dist/index.js +3189 -517
- package/dist/index.js.map +1 -1
- package/dist/sidebar.cjs +73 -147
- package/dist/sidebar.cjs.map +1 -1
- package/dist/sidebar.d.cts +20 -1
- package/dist/sidebar.d.ts +20 -1
- package/dist/sidebar.js +99 -158
- package/dist/sidebar.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +8 -5
- package/tailwind-preset.cjs +240 -0
- package/tailwind-preset.js +0 -77
package/dist/sidebar.cjs
CHANGED
|
@@ -30,17 +30,16 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/sidebar/index.tsx
|
|
31
31
|
var sidebar_exports = {};
|
|
32
32
|
__export(sidebar_exports, {
|
|
33
|
-
AppSidebar: () => AppSidebar
|
|
33
|
+
AppSidebar: () => AppSidebar,
|
|
34
|
+
NavTabs: () => NavTabs
|
|
34
35
|
});
|
|
35
36
|
module.exports = __toCommonJS(sidebar_exports);
|
|
36
37
|
var import_react = require("react");
|
|
37
|
-
var
|
|
38
|
+
var import_react_router_dom2 = require("react-router-dom");
|
|
38
39
|
var import_clsx4 = __toESM(require("clsx"), 1);
|
|
40
|
+
var import_lu = require("react-icons/lu");
|
|
39
41
|
|
|
40
|
-
// src/
|
|
41
|
-
var import_clsx3 = __toESM(require("clsx"), 1);
|
|
42
|
-
|
|
43
|
-
// src/components/avatar.tsx
|
|
42
|
+
// src/components/avatar/avatar.tsx
|
|
44
43
|
var import_clsx = __toESM(require("clsx"), 1);
|
|
45
44
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
46
45
|
var sizeStyles = {
|
|
@@ -53,16 +52,16 @@ var initialTextStyles = {
|
|
|
53
52
|
md: "text-body-xs font-semibold",
|
|
54
53
|
sm: "text-body-tiny font-semibold"
|
|
55
54
|
};
|
|
56
|
-
|
|
57
|
-
circle
|
|
58
|
-
|
|
59
|
-
}
|
|
55
|
+
function getShapeClass(shape, size) {
|
|
56
|
+
if (shape === "circle") return "rounded-full";
|
|
57
|
+
return size === "sm" ? "rounded" : "rounded-lg";
|
|
58
|
+
}
|
|
60
59
|
function Avatar(props) {
|
|
61
60
|
const { size = "lg", shape = "circle", className } = props;
|
|
62
61
|
const base = (0, import_clsx.default)(
|
|
63
62
|
"shrink-0 overflow-hidden",
|
|
64
63
|
sizeStyles[size],
|
|
65
|
-
|
|
64
|
+
getShapeClass(shape, size),
|
|
66
65
|
className
|
|
67
66
|
);
|
|
68
67
|
if (props.type === "image") {
|
|
@@ -86,7 +85,7 @@ function Avatar(props) {
|
|
|
86
85
|
"span",
|
|
87
86
|
{
|
|
88
87
|
className: (0, import_clsx.default)(
|
|
89
|
-
"select-none leading-none text-
|
|
88
|
+
"select-none leading-none text-brand-on-brand",
|
|
90
89
|
initialTextStyles[size]
|
|
91
90
|
),
|
|
92
91
|
children: props.initial.charAt(0).toUpperCase()
|
|
@@ -96,142 +95,68 @@ function Avatar(props) {
|
|
|
96
95
|
);
|
|
97
96
|
}
|
|
98
97
|
|
|
99
|
-
// src/components/nav-item.tsx
|
|
98
|
+
// src/components/chrome/nav-item.tsx
|
|
100
99
|
var import_clsx2 = __toESM(require("clsx"), 1);
|
|
101
100
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
101
|
+
var SIZE = {
|
|
102
|
+
sm: { box: "h-9 gap-2 rounded-lg px-2.5 py-1.5", label: "text-body-xs" },
|
|
103
|
+
md: { box: "h-11 gap-3 rounded-xl px-3.5 py-2.5", label: "text-body-sm" }
|
|
104
|
+
};
|
|
102
105
|
function NavItem({
|
|
103
106
|
icon,
|
|
104
107
|
label,
|
|
105
108
|
isActive = false,
|
|
106
109
|
indicator = false,
|
|
107
110
|
collapsed = false,
|
|
111
|
+
size = "md",
|
|
108
112
|
className
|
|
109
113
|
}) {
|
|
114
|
+
const s = SIZE[size];
|
|
110
115
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
111
116
|
"span",
|
|
112
117
|
{
|
|
113
118
|
className: (0, import_clsx2.default)(
|
|
114
|
-
"relative flex
|
|
119
|
+
"relative flex w-full items-center transition-colors",
|
|
120
|
+
s.box,
|
|
115
121
|
collapsed && "justify-center",
|
|
116
|
-
isActive ? "bg-
|
|
117
|
-
"border border-
|
|
118
|
-
"hover:bg-
|
|
122
|
+
isActive ? "bg-brand text-brand-on-brand" : [
|
|
123
|
+
"border border-default bg-default text-default-secondary",
|
|
124
|
+
"hover:bg-brand-tertiary-hover hover:border-brand-tertiary hover:text-brand"
|
|
119
125
|
],
|
|
120
126
|
className
|
|
121
127
|
),
|
|
122
128
|
children: [
|
|
123
129
|
icon !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "shrink-0 [&_svg]:size-4", children: icon }),
|
|
124
|
-
!collapsed && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "
|
|
125
|
-
indicator && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "absolute -right-px -top-px size-2 rounded-full bg-
|
|
130
|
+
!collapsed && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: (0, import_clsx2.default)("min-w-0 flex-1 truncate font-regular leading-snug", s.label), children: label }),
|
|
131
|
+
indicator && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "absolute -right-px -top-px size-2 rounded-full bg-danger" })
|
|
126
132
|
]
|
|
127
133
|
}
|
|
128
134
|
);
|
|
129
135
|
}
|
|
130
136
|
|
|
131
|
-
// src/
|
|
137
|
+
// src/sidebar/nav-tabs.tsx
|
|
138
|
+
var import_react_router_dom = require("react-router-dom");
|
|
139
|
+
var import_clsx3 = __toESM(require("clsx"), 1);
|
|
132
140
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
141
|
+
function NavTabs({ items, className }) {
|
|
142
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: (0, import_clsx3.default)("flex gap-6 overflow-x-auto border-b border-default", className), children: items.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
143
|
+
import_react_router_dom.NavLink,
|
|
144
|
+
{
|
|
145
|
+
to: tab.to,
|
|
146
|
+
end: tab.end,
|
|
147
|
+
className: ({ isActive }) => (0, import_clsx3.default)(
|
|
148
|
+
"shrink-0 whitespace-nowrap border-b-2 pb-3 text-body-sm transition-colors",
|
|
149
|
+
isActive ? "border-brand-emphasis font-semibold text-brand-emphasis" : "border-transparent font-medium text-default-secondary hover:text-default"
|
|
150
|
+
),
|
|
151
|
+
children: tab.label
|
|
152
|
+
},
|
|
153
|
+
tab.to
|
|
154
|
+
)) });
|
|
155
|
+
}
|
|
133
156
|
|
|
134
157
|
// src/sidebar/index.tsx
|
|
135
158
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
136
|
-
|
|
137
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
138
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "3", y: "3", width: "7", height: "7", rx: "1" }),
|
|
139
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "14", y: "3", width: "7", height: "7", rx: "1" }),
|
|
140
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "14", y: "14", width: "7", height: "7", rx: "1" }),
|
|
141
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "3", y: "14", width: "7", height: "7", rx: "1" })
|
|
142
|
-
] });
|
|
143
|
-
}
|
|
144
|
-
function LayersIcon() {
|
|
145
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
146
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("polygon", { points: "12 2 2 7 12 12 22 7 12 2" }),
|
|
147
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("polyline", { points: "2 17 12 22 22 17" }),
|
|
148
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("polyline", { points: "2 12 12 17 22 12" })
|
|
149
|
-
] });
|
|
150
|
-
}
|
|
151
|
-
function BuildingIcon() {
|
|
152
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
153
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "2", y: "7", width: "20", height: "14", rx: "2" }),
|
|
154
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16" })
|
|
155
|
-
] });
|
|
156
|
-
}
|
|
157
|
-
function UsersIcon() {
|
|
158
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
159
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" }),
|
|
160
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "9", cy: "7", r: "4" }),
|
|
161
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M23 21v-2a4 4 0 0 0-3-3.87" }),
|
|
162
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M16 3.13a4 4 0 0 1 0 7.75" })
|
|
163
|
-
] });
|
|
164
|
-
}
|
|
165
|
-
function RssIcon() {
|
|
166
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
167
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M4 11a9 9 0 0 1 9 9" }),
|
|
168
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M4 4a16 16 0 0 1 16 16" }),
|
|
169
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "5", cy: "19", r: "1", fill: "currentColor" })
|
|
170
|
-
] });
|
|
171
|
-
}
|
|
172
|
-
function FileTextIcon() {
|
|
173
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
174
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
|
|
175
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("polyline", { points: "14 2 14 8 20 8" }),
|
|
176
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "16", y1: "13", x2: "8", y2: "13" }),
|
|
177
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "16", y1: "17", x2: "8", y2: "17" })
|
|
178
|
-
] });
|
|
179
|
-
}
|
|
180
|
-
function BellIcon() {
|
|
181
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
182
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9" }),
|
|
183
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M13.73 21a2 2 0 0 1-3.46 0" })
|
|
184
|
-
] });
|
|
185
|
-
}
|
|
186
|
-
function ServerIcon() {
|
|
187
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
188
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "2", y: "2", width: "20", height: "8", rx: "2" }),
|
|
189
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "2", y: "14", width: "20", height: "8", rx: "2" }),
|
|
190
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "6", y1: "6", x2: "6.01", y2: "6" }),
|
|
191
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "6", y1: "18", x2: "6.01", y2: "18" })
|
|
192
|
-
] });
|
|
193
|
-
}
|
|
194
|
-
function SettingsIcon() {
|
|
195
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
196
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "12", cy: "12", r: "3" }),
|
|
197
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" })
|
|
198
|
-
] });
|
|
199
|
-
}
|
|
200
|
-
function ClipboardListIcon() {
|
|
201
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
202
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2" }),
|
|
203
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "9", y: "3", width: "6", height: "4", rx: "1" }),
|
|
204
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "9", y1: "12", x2: "15", y2: "12" }),
|
|
205
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "9", y1: "16", x2: "13", y2: "16" })
|
|
206
|
-
] });
|
|
207
|
-
}
|
|
208
|
-
function GlobeIcon() {
|
|
209
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
210
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
|
|
211
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "2", y1: "12", x2: "22", y2: "12" }),
|
|
212
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" })
|
|
213
|
-
] });
|
|
214
|
-
}
|
|
215
|
-
function ChevronLeftIcon() {
|
|
216
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("polyline", { points: "15 18 9 12 15 6" }) });
|
|
217
|
-
}
|
|
218
|
-
function ChevronRightIcon() {
|
|
219
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("polyline", { points: "9 18 15 12 9 6" }) });
|
|
220
|
-
}
|
|
221
|
-
function MoreVerticalIcon() {
|
|
222
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
223
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "12", cy: "5", r: "1", fill: "currentColor" }),
|
|
224
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "12", cy: "12", r: "1", fill: "currentColor" }),
|
|
225
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "12", cy: "19", r: "1", fill: "currentColor" })
|
|
226
|
-
] });
|
|
227
|
-
}
|
|
228
|
-
function LogOutIcon() {
|
|
229
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
230
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" }),
|
|
231
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("polyline", { points: "16 17 21 12 16 7" }),
|
|
232
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("line", { x1: "21", y1: "12", x2: "9", y2: "12" })
|
|
233
|
-
] });
|
|
234
|
-
}
|
|
159
|
+
var NAV_ICON = "size-4";
|
|
235
160
|
function SidebarLogo({ collapsed }) {
|
|
236
161
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
237
162
|
"div",
|
|
@@ -241,19 +166,19 @@ function SidebarLogo({ collapsed }) {
|
|
|
241
166
|
collapsed ? "justify-center" : "gap-2.5"
|
|
242
167
|
),
|
|
243
168
|
children: [
|
|
244
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex shrink-0 size-10 items-center justify-center rounded-xl bg-
|
|
169
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex shrink-0 size-10 items-center justify-center rounded-xl bg-brand-hover overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "grid grid-cols-2 gap-[3px]", children: [
|
|
245
170
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "size-2 rounded-[2px] bg-white" }),
|
|
246
171
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "size-2 rounded-[2px] bg-white/50" }),
|
|
247
172
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "size-2 rounded-[2px] bg-white/50" }),
|
|
248
173
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "size-2 rounded-[2px] bg-white" })
|
|
249
174
|
] }) }),
|
|
250
|
-
!collapsed && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-heading font-semibold text-
|
|
175
|
+
!collapsed && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-heading font-semibold text-default tracking-tight whitespace-nowrap", children: "SCIC" })
|
|
251
176
|
]
|
|
252
177
|
}
|
|
253
178
|
);
|
|
254
179
|
}
|
|
255
180
|
function NavLinkItem({ to, icon, label, indicator, collapsed, end }) {
|
|
256
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
181
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_router_dom2.NavLink, { to, end, className: "block w-full no-underline", children: ({ isActive }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
257
182
|
NavItem,
|
|
258
183
|
{
|
|
259
184
|
icon,
|
|
@@ -286,9 +211,9 @@ function UserCard({ collapsed, name, role, onLogout }) {
|
|
|
286
211
|
setMenuOpen(false);
|
|
287
212
|
onLogout();
|
|
288
213
|
},
|
|
289
|
-
className: "flex w-full items-center gap-2 px-3 py-2 text-body-sm text-
|
|
214
|
+
className: "flex w-full items-center gap-2 px-3 py-2 text-body-sm text-default hover:bg-default-hover transition-colors",
|
|
290
215
|
children: [
|
|
291
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
216
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lu.LuLogOut, { className: "size-3.5", "aria-hidden": true }),
|
|
292
217
|
"Sign out"
|
|
293
218
|
]
|
|
294
219
|
}
|
|
@@ -313,12 +238,12 @@ function UserCard({ collapsed, name, role, onLogout }) {
|
|
|
313
238
|
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Avatar, { initial, size: "md", shape: "circle" })
|
|
314
239
|
}
|
|
315
240
|
),
|
|
316
|
-
menuOpen && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "absolute bottom-0 left-full ml-2 w-36 rounded-lg border border-
|
|
241
|
+
menuOpen && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "absolute bottom-0 left-full ml-2 w-36 rounded-lg border border-default bg-default shadow-md py-1 z-20", children: menuItems })
|
|
317
242
|
] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
318
243
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Avatar, { initial, size: "md", shape: "circle" }),
|
|
319
244
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex flex-1 min-w-0 flex-col gap-0.5", children: [
|
|
320
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "truncate text-body-sm font-semibold text-
|
|
321
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "truncate text-body-tiny font-regular text-
|
|
245
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "truncate text-body-sm font-semibold text-default leading-snug", children: name }),
|
|
246
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "truncate text-body-tiny font-regular text-default-secondary leading-none", children: role })
|
|
322
247
|
] }),
|
|
323
248
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "relative shrink-0", ref: menuRef, children: [
|
|
324
249
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
@@ -329,11 +254,11 @@ function UserCard({ collapsed, name, role, onLogout }) {
|
|
|
329
254
|
"aria-haspopup": "menu",
|
|
330
255
|
"aria-expanded": menuOpen,
|
|
331
256
|
onClick: () => setMenuOpen((v) => !v),
|
|
332
|
-
className: "flex size-6 items-center justify-center rounded-md text-
|
|
333
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
257
|
+
className: "flex size-6 items-center justify-center rounded-md text-default-secondary hover:bg-default-hover hover:text-default transition-colors",
|
|
258
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lu.LuEllipsisVertical, { className: "size-4", "aria-hidden": true })
|
|
334
259
|
}
|
|
335
260
|
),
|
|
336
|
-
menuOpen && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "absolute bottom-full right-0 mb-1 w-36 rounded-lg border border-
|
|
261
|
+
menuOpen && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "absolute bottom-full right-0 mb-1 w-36 rounded-lg border border-default bg-default shadow-md py-1 z-20", children: menuItems })
|
|
337
262
|
] })
|
|
338
263
|
] })
|
|
339
264
|
}
|
|
@@ -345,7 +270,7 @@ function AppSidebar({ collapsed, onToggle, isAdmin = false, userName, userRole,
|
|
|
345
270
|
{
|
|
346
271
|
className: (0, import_clsx4.default)(
|
|
347
272
|
"relative flex flex-col shrink-0 transition-all duration-200",
|
|
348
|
-
"bg-
|
|
273
|
+
"bg-default-secondary border-r border-default rounded-xl",
|
|
349
274
|
"h-full",
|
|
350
275
|
collapsed ? "w-20" : "w-80"
|
|
351
276
|
),
|
|
@@ -358,25 +283,25 @@ function AppSidebar({ collapsed, onToggle, isAdmin = false, userName, userRole,
|
|
|
358
283
|
onClick: onToggle,
|
|
359
284
|
className: (0, import_clsx4.default)(
|
|
360
285
|
"absolute -right-3 top-5 z-10 flex size-6 items-center justify-center rounded-full",
|
|
361
|
-
"bg-
|
|
362
|
-
"hover:bg-
|
|
286
|
+
"bg-default border border-default text-default-secondary",
|
|
287
|
+
"hover:bg-default-hover shadow-sm transition-colors"
|
|
363
288
|
),
|
|
364
|
-
children: collapsed ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
289
|
+
children: collapsed ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lu.LuChevronRight, { className: "size-3", strokeWidth: 2.5, "aria-hidden": true }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lu.LuChevronLeft, { className: "size-3", strokeWidth: 2.5, "aria-hidden": true })
|
|
365
290
|
}
|
|
366
291
|
),
|
|
367
292
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex flex-1 min-h-0 flex-col gap-1", children: [
|
|
368
293
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(SidebarLogo, { collapsed }),
|
|
369
294
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("nav", { className: "flex flex-col gap-3 overflow-y-auto px-4 pt-2 pb-3", children: [
|
|
370
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLinkItem, { to: "/dashboard", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
371
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLinkItem, { to: "/entities", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
372
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLinkItem, { to: "/suppliers", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
373
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLinkItem, { to: "/customers", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
374
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLinkItem, { to: "/sources", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
375
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLinkItem, { to: "/articles", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
376
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLinkItem, { to: "/alerts", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
377
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLinkItem, { to: "/website-scraper", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
378
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLinkItem, { to: "/review", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
379
|
-
isAdmin && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLinkItem, { to: "/queues", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
295
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLinkItem, { to: "/dashboard", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lu.LuLayoutGrid, { className: NAV_ICON, "aria-hidden": true }), label: "Dashboard", collapsed, end: true }),
|
|
296
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLinkItem, { to: "/entities", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lu.LuLayers, { className: NAV_ICON, "aria-hidden": true }), label: "Entities", collapsed, indicator: true }),
|
|
297
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLinkItem, { to: "/suppliers", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lu.LuBuilding, { className: NAV_ICON, "aria-hidden": true }), label: "Suppliers", collapsed }),
|
|
298
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLinkItem, { to: "/customers", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lu.LuUsers, { className: NAV_ICON, "aria-hidden": true }), label: "Customers", collapsed }),
|
|
299
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLinkItem, { to: "/sources", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lu.LuFileText, { className: NAV_ICON, "aria-hidden": true }), label: "Sources", collapsed }),
|
|
300
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLinkItem, { to: "/articles", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lu.LuRss, { className: NAV_ICON, "aria-hidden": true }), label: "Intelligence", collapsed }),
|
|
301
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLinkItem, { to: "/alerts", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lu.LuBell, { className: NAV_ICON, "aria-hidden": true }), label: "Alerts", collapsed }),
|
|
302
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLinkItem, { to: "/website-scraper", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lu.LuGlobe, { className: NAV_ICON, "aria-hidden": true }), label: "Website Intel", collapsed }),
|
|
303
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLinkItem, { to: "/review", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lu.LuClipboardList, { className: NAV_ICON, "aria-hidden": true }), label: "Review queue", collapsed }),
|
|
304
|
+
isAdmin && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLinkItem, { to: "/queues", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lu.LuServer, { className: NAV_ICON, "aria-hidden": true }), label: "Queues", collapsed })
|
|
380
305
|
] })
|
|
381
306
|
] }),
|
|
382
307
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex flex-col", children: [
|
|
@@ -384,12 +309,12 @@ function AppSidebar({ collapsed, onToggle, isAdmin = false, userName, userRole,
|
|
|
384
309
|
NavLinkItem,
|
|
385
310
|
{
|
|
386
311
|
to: "/settings",
|
|
387
|
-
icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
312
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lu.LuSettings, { className: NAV_ICON, "aria-hidden": true }),
|
|
388
313
|
label: "Settings",
|
|
389
314
|
collapsed
|
|
390
315
|
}
|
|
391
316
|
) }),
|
|
392
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "border-t border-
|
|
317
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "border-t border-default", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(UserCard, { collapsed, name: userName, role: userRole, onLogout }) })
|
|
393
318
|
] })
|
|
394
319
|
]
|
|
395
320
|
}
|
|
@@ -397,6 +322,7 @@ function AppSidebar({ collapsed, onToggle, isAdmin = false, userName, userRole,
|
|
|
397
322
|
}
|
|
398
323
|
// Annotate the CommonJS export names for ESM import in node:
|
|
399
324
|
0 && (module.exports = {
|
|
400
|
-
AppSidebar
|
|
325
|
+
AppSidebar,
|
|
326
|
+
NavTabs
|
|
401
327
|
});
|
|
402
328
|
//# sourceMappingURL=sidebar.cjs.map
|
package/dist/sidebar.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/sidebar/index.tsx","../src/index.tsx","../src/components/avatar.tsx","../src/components/nav-item.tsx"],"sourcesContent":["import { type ReactNode, useEffect, useRef, useState } from 'react';\nimport { NavLink } from 'react-router-dom';\nimport clsx from 'clsx';\n\nimport { Avatar, NavItem } from '../index';\n\n// ── Inline SVG icons (Lucide-compatible, 24×24 viewBox rendered at 16×16) ──\n\nfunction GridIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <rect x=\"3\" y=\"3\" width=\"7\" height=\"7\" rx=\"1\" />\n <rect x=\"14\" y=\"3\" width=\"7\" height=\"7\" rx=\"1\" />\n <rect x=\"14\" y=\"14\" width=\"7\" height=\"7\" rx=\"1\" />\n <rect x=\"3\" y=\"14\" width=\"7\" height=\"7\" rx=\"1\" />\n </svg>\n );\n}\n\nfunction LayersIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <polygon points=\"12 2 2 7 12 12 22 7 12 2\" />\n <polyline points=\"2 17 12 22 22 17\" />\n <polyline points=\"2 12 12 17 22 12\" />\n </svg>\n );\n}\n\nfunction BuildingIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <rect x=\"2\" y=\"7\" width=\"20\" height=\"14\" rx=\"2\" />\n <path d=\"M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16\" />\n </svg>\n );\n}\n\nfunction UsersIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2\" />\n <circle cx=\"9\" cy=\"7\" r=\"4\" />\n <path d=\"M23 21v-2a4 4 0 0 0-3-3.87\" />\n <path d=\"M16 3.13a4 4 0 0 1 0 7.75\" />\n </svg>\n );\n}\n\nfunction RssIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M4 11a9 9 0 0 1 9 9\" />\n <path d=\"M4 4a16 16 0 0 1 16 16\" />\n <circle cx=\"5\" cy=\"19\" r=\"1\" fill=\"currentColor\" />\n </svg>\n );\n}\n\nfunction FileTextIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n <line x1=\"16\" y1=\"13\" x2=\"8\" y2=\"13\" />\n <line x1=\"16\" y1=\"17\" x2=\"8\" y2=\"17\" />\n </svg>\n );\n}\n\nfunction BellIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\" />\n <path d=\"M13.73 21a2 2 0 0 1-3.46 0\" />\n </svg>\n );\n}\n\nfunction ServerIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <rect x=\"2\" y=\"2\" width=\"20\" height=\"8\" rx=\"2\" />\n <rect x=\"2\" y=\"14\" width=\"20\" height=\"8\" rx=\"2\" />\n <line x1=\"6\" y1=\"6\" x2=\"6.01\" y2=\"6\" />\n <line x1=\"6\" y1=\"18\" x2=\"6.01\" y2=\"18\" />\n </svg>\n );\n}\n\nfunction SettingsIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n <path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z\" />\n </svg>\n );\n}\n\nfunction ClipboardListIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2\" />\n <rect x=\"9\" y=\"3\" width=\"6\" height=\"4\" rx=\"1\" />\n <line x1=\"9\" y1=\"12\" x2=\"15\" y2=\"12\" />\n <line x1=\"9\" y1=\"16\" x2=\"13\" y2=\"16\" />\n </svg>\n );\n}\n\nfunction GlobeIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"2\" y1=\"12\" x2=\"22\" y2=\"12\" />\n <path d=\"M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z\" />\n </svg>\n );\n}\n\nfunction ChevronLeftIcon() {\n return (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <polyline points=\"15 18 9 12 15 6\" />\n </svg>\n );\n}\n\nfunction ChevronRightIcon() {\n return (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <polyline points=\"9 18 15 12 9 6\" />\n </svg>\n );\n}\n\nfunction MoreVerticalIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <circle cx=\"12\" cy=\"5\" r=\"1\" fill=\"currentColor\" />\n <circle cx=\"12\" cy=\"12\" r=\"1\" fill=\"currentColor\" />\n <circle cx=\"12\" cy=\"19\" r=\"1\" fill=\"currentColor\" />\n </svg>\n );\n}\n\nfunction LogOutIcon() {\n return (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\" />\n <polyline points=\"16 17 21 12 16 7\" />\n <line x1=\"21\" y1=\"12\" x2=\"9\" y2=\"12\" />\n </svg>\n );\n}\n\n// ── Logo ────────────────────────────────────────────────────────────────────\n\nfunction SidebarLogo({ collapsed }: { collapsed: boolean }) {\n return (\n <div\n className={clsx(\n 'flex shrink-0 items-center overflow-hidden p-4',\n collapsed ? 'justify-center' : 'gap-2.5',\n )}\n >\n <div className=\"flex shrink-0 size-10 items-center justify-center rounded-xl bg-background-brand-hover overflow-hidden\">\n <div className=\"grid grid-cols-2 gap-[3px]\">\n <div className=\"size-2 rounded-[2px] bg-white\" />\n <div className=\"size-2 rounded-[2px] bg-white/50\" />\n <div className=\"size-2 rounded-[2px] bg-white/50\" />\n <div className=\"size-2 rounded-[2px] bg-white\" />\n </div>\n </div>\n {!collapsed && (\n <span className=\"text-heading font-semibold text-text-default tracking-tight whitespace-nowrap\">\n SCIC\n </span>\n )}\n </div>\n );\n}\n\n// ── NavLink item ─────────────────────────────────────────────────────────────\n\ninterface NavLinkItemProps {\n to: string;\n icon: ReactNode;\n label: string;\n indicator?: boolean;\n collapsed: boolean;\n end?: boolean;\n}\n\nfunction NavLinkItem({ to, icon, label, indicator, collapsed, end }: NavLinkItemProps) {\n return (\n <NavLink to={to} end={end} className=\"block w-full no-underline\">\n {({ isActive }) => (\n <NavItem\n icon={icon}\n label={label}\n isActive={isActive}\n indicator={indicator}\n collapsed={collapsed}\n />\n )}\n </NavLink>\n );\n}\n\n// ── User card ────────────────────────────────────────────────────────────────\n\nfunction UserCard({ collapsed, name, role, onLogout }: { collapsed: boolean; name: string; role: string; onLogout: () => void }) {\n const [menuOpen, setMenuOpen] = useState(false);\n const menuRef = useRef<HTMLDivElement>(null);\n const initial = name.trim().charAt(0);\n\n useEffect(() => {\n if (!menuOpen) return;\n function handleClickOutside(e: MouseEvent) {\n if (menuRef.current && !menuRef.current.contains(e.target as Node)) {\n setMenuOpen(false);\n }\n }\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, [menuOpen]);\n\n const menuItems = (\n <button\n type=\"button\"\n onClick={() => { setMenuOpen(false); onLogout(); }}\n className=\"flex w-full items-center gap-2 px-3 py-2 text-body-sm text-text-default hover:bg-background-default-hover transition-colors\"\n >\n <LogOutIcon />\n Sign out\n </button>\n );\n\n return (\n <div\n className={clsx(\n 'flex shrink-0 items-center p-4',\n collapsed ? 'justify-center' : 'gap-2.5',\n )}\n >\n {collapsed ? (\n <div className=\"relative\" ref={menuRef}>\n <button\n type=\"button\"\n aria-label=\"User options\"\n aria-haspopup=\"menu\"\n aria-expanded={menuOpen}\n onClick={() => setMenuOpen(v => !v)}\n className=\"rounded-full\"\n >\n <Avatar initial={initial} size=\"md\" shape=\"circle\" />\n </button>\n {menuOpen && (\n <div className=\"absolute bottom-0 left-full ml-2 w-36 rounded-lg border border-border-default bg-background-default shadow-md py-1 z-20\">\n {menuItems}\n </div>\n )}\n </div>\n ) : (\n <>\n <Avatar initial={initial} size=\"md\" shape=\"circle\" />\n <div className=\"flex flex-1 min-w-0 flex-col gap-0.5\">\n <span className=\"truncate text-body-sm font-semibold text-text-default leading-snug\">\n {name}\n </span>\n <span className=\"truncate text-body-tiny font-regular text-text-default-secondary leading-none\">\n {role}\n </span>\n </div>\n <div className=\"relative shrink-0\" ref={menuRef}>\n <button\n type=\"button\"\n aria-label=\"User options\"\n aria-haspopup=\"menu\"\n aria-expanded={menuOpen}\n onClick={() => setMenuOpen(v => !v)}\n className=\"flex size-6 items-center justify-center rounded-md text-text-default-secondary hover:bg-background-default-hover hover:text-text-default transition-colors\"\n >\n <MoreVerticalIcon />\n </button>\n {menuOpen && (\n <div className=\"absolute bottom-full right-0 mb-1 w-36 rounded-lg border border-border-default bg-background-default shadow-md py-1 z-20\">\n {menuItems}\n </div>\n )}\n </div>\n </>\n )}\n </div>\n );\n}\n\n// ── Main sidebar ─────────────────────────────────────────────────────────────\n\ninterface AppSidebarProps {\n collapsed: boolean;\n onToggle: () => void;\n isAdmin?: boolean;\n userName: string;\n userRole: string;\n onLogout: () => void;\n}\n\nexport function AppSidebar({ collapsed, onToggle, isAdmin = false, userName, userRole, onLogout }: AppSidebarProps) {\n\n return (\n <aside\n className={clsx(\n 'relative flex flex-col shrink-0 transition-all duration-200',\n 'bg-background-default-secondary border-r border-border-default rounded-xl',\n 'h-full',\n collapsed ? 'w-20' : 'w-80',\n )}\n >\n {/* Toggle button */}\n <button\n type=\"button\"\n aria-label={collapsed ? 'Expand sidebar' : 'Collapse sidebar'}\n onClick={onToggle}\n className={clsx(\n 'absolute -right-3 top-5 z-10 flex size-6 items-center justify-center rounded-full',\n 'bg-background-default border border-border-default text-text-default-secondary',\n 'hover:bg-background-default-hover shadow-sm transition-colors',\n )}\n >\n {collapsed ? <ChevronRightIcon /> : <ChevronLeftIcon />}\n </button>\n\n {/* Top — logo + primary nav */}\n <div className=\"flex flex-1 min-h-0 flex-col gap-1\">\n <SidebarLogo collapsed={collapsed} />\n\n <nav className=\"flex flex-col gap-3 overflow-y-auto px-4 pt-2 pb-3\">\n <NavLinkItem to=\"/dashboard\" icon={<GridIcon />} label=\"Dashboard\" collapsed={collapsed} end />\n <NavLinkItem to=\"/entities\" icon={<LayersIcon />} label=\"Entities\" collapsed={collapsed} indicator />\n <NavLinkItem to=\"/suppliers\" icon={<BuildingIcon />} label=\"Suppliers\" collapsed={collapsed} />\n <NavLinkItem to=\"/customers\" icon={<UsersIcon />} label=\"Customers\" collapsed={collapsed} />\n <NavLinkItem to=\"/sources\" icon={<FileTextIcon />} label=\"Sources\" collapsed={collapsed} />\n <NavLinkItem to=\"/articles\" icon={<RssIcon />} label=\"Intelligence\" collapsed={collapsed} />\n <NavLinkItem to=\"/alerts\" icon={<BellIcon />} label=\"Alerts\" collapsed={collapsed} />\n <NavLinkItem to=\"/website-scraper\" icon={<GlobeIcon />} label=\"Website Intel\" collapsed={collapsed} />\n <NavLinkItem to=\"/review\" icon={<ClipboardListIcon />} label=\"Review queue\" collapsed={collapsed} />\n {isAdmin && (\n <NavLinkItem to=\"/queues\" icon={<ServerIcon />} label=\"Queues\" collapsed={collapsed} />\n )}\n </nav>\n </div>\n\n {/* Bottom — settings + user card */}\n <div className=\"flex flex-col\">\n {isAdmin && (\n <div className=\"px-4 pb-2\">\n <NavLinkItem\n to=\"/settings\"\n icon={<SettingsIcon />}\n label=\"Settings\"\n collapsed={collapsed}\n />\n </div>\n )}\n <div className=\"border-t border-border-default\">\n <UserCard collapsed={collapsed} name={userName} role={userRole} onLogout={onLogout} />\n </div>\n </div>\n </aside>\n );\n}\n","import clsx from 'clsx';\nimport type { ReactNode } from 'react';\n\nexport { Button } from './components/button';\nexport type { ButtonProps, ButtonVariant, ButtonSize } from './components/button';\n\nexport { IconButton } from './components/icon-button';\nexport type { IconButtonProps, IconButtonVariant } from './components/icon-button';\n\nexport { ButtonGroup } from './components/button-group';\nexport type { ButtonGroupProps, ButtonGroupItem, ButtonGroupVariant, ButtonGroupAlign } from './components/button-group';\n\nexport { Avatar } from './components/avatar';\nexport type { AvatarProps, AvatarInitialProps, AvatarImageProps, AvatarSize, AvatarShape } from './components/avatar';\n\nexport { AvatarGroup } from './components/avatar-group';\nexport type { AvatarGroupProps, AvatarGroupSpacing } from './components/avatar-group';\n\nexport { NavItem } from './components/nav-item';\nexport type { NavItemProps } from './components/nav-item';\n\nexport { Input } from './components/input';\nexport type { InputProps, InputSize } from './components/input';\n\nexport { Textarea } from './components/textarea';\nexport type { TextareaProps } from './components/textarea';\n\nexport { Select } from './components/select';\nexport type { SelectProps, SelectOption } from './components/select';\n\nexport { Stepper } from './components/stepper';\nexport type { StepperProps, StepItem, StepStatus } from './components/stepper';\n\nexport { MultiSelectCard } from './components/multiselect-card';\nexport type { MultiSelectCardProps } from './components/multiselect-card';\n\nexport { DataTable, TableCellLeadText, TableCellText, TableCellBadge, TableCellStatusPill, TableCellProgress } from './components/data-table';\nexport type { ColumnDef } from './components/data-table';\n\nexport { StatTile } from './components/stat-tile';\nexport type { StatTileProps } from './components/stat-tile';\n\nexport { Toggle } from './components/toggle';\nexport type { ToggleProps } from './components/toggle';\n\nexport { FileDropZone } from './components/file-drop-zone';\nexport type { FileDropZoneProps } from './components/file-drop-zone';\n\nexport { FormCard, FormCardHeader, FormCardFooter } from './components/form-card';\nexport type { FormCardHeaderProps, FormCardFooterProps } from './components/form-card';\n\nexport { DocumentRow } from './components/document-row';\nexport type { DocumentRowProps, DocumentStatus } from './components/document-row';\n\nexport function Panel({\n children,\n className\n}: {\n children: ReactNode;\n className?: string;\n}) {\n return (\n <section className={clsx('rounded-3xl border border-white/70 bg-white/90 p-6 shadow-panel backdrop-blur', className)}>\n {children}\n </section>\n );\n}\n\nexport function MetricCard({\n label,\n value,\n tone = 'default'\n}: {\n label: string;\n value: string | number;\n tone?: 'default' | 'signal' | 'ember' | 'moss';\n}) {\n const tones = {\n default: 'from-white to-slate-50 text-text-default',\n signal: 'from-background-brand-tertiary to-cyan-50 text-text-brand',\n ember: 'from-amber-50 to-orange-50 text-text-danger',\n moss: 'from-emerald-50 to-lime-50 text-text-positive'\n };\n\n return (\n <Panel className={clsx('bg-gradient-to-br', tones[tone])}>\n <p className=\"text-sm uppercase tracking-[0.2em] text-slate-500\">{label}</p>\n <p className=\"mt-3 text-3xl font-semibold\">{value}</p>\n </Panel>\n );\n}\n\nexport function SeverityBadge({ severity }: { severity?: string | null }) {\n const styles: Record<string, string> = {\n critical: 'bg-red-100 text-red-700',\n high: 'bg-orange-100 text-orange-700',\n medium: 'bg-amber-100 text-amber-700',\n low: 'bg-slate-100 text-slate-700'\n };\n\n return (\n <span className={clsx('inline-flex rounded-full px-3 py-1 text-xs font-semibold uppercase tracking-wide', styles[severity ?? 'low'])}>\n {severity ?? 'unknown'}\n </span>\n );\n}\n\nexport function SentimentBadge({ sentiment }: { sentiment?: string | null }) {\n const styles: Record<string, string> = {\n positive: 'bg-emerald-100 text-emerald-700',\n neutral: 'bg-slate-100 text-slate-700',\n negative: 'bg-rose-100 text-rose-700',\n concerning: 'bg-amber-100 text-amber-700'\n };\n\n return (\n <span className={clsx('inline-flex rounded-full px-3 py-1 text-xs font-semibold capitalize', styles[sentiment ?? 'neutral'] ?? styles.neutral)}>\n {sentiment ?? 'unknown'}\n </span>\n );\n}\n\nexport { Modal } from './components/modal';\nexport type { ModalProps } from './components/modal';\n\nexport { RoleBadge } from './components/role-badge';\nexport type { RoleBadgeProps } from './components/role-badge';\n\nexport { RoleComboBox, ROLE_COMBO_OPTIONS } from './components/role-combo-box';\nexport type { RoleComboBoxProps, RoleOption } from './components/role-combo-box';\n\nexport function SectionHeading({\n eyebrow,\n title,\n detail\n}: {\n eyebrow: string;\n title: string;\n detail?: string;\n}) {\n return (\n <div>\n <p className=\"text-xs uppercase tracking-[0.25em] text-text-brand\">{eyebrow}</p>\n <h2 className=\"mt-2 text-2xl font-semibold text-text-default\">{title}</h2>\n {detail ? <p className=\"mt-2 max-w-2xl text-sm text-slate-600\">{detail}</p> : null}\n </div>\n );\n}\n\n","import clsx from 'clsx';\n\nexport type AvatarSize = 'sm' | 'md' | 'lg';\nexport type AvatarShape = 'circle' | 'square';\n\nexport interface AvatarInitialProps {\n type?: 'initial';\n /** Single character — Figma spec: one letter only to avoid overflow */\n initial: string;\n size?: AvatarSize;\n shape?: AvatarShape;\n className?: string;\n}\n\nexport interface AvatarImageProps {\n type: 'image';\n src: string;\n alt?: string;\n size?: AvatarSize;\n shape?: AvatarShape;\n className?: string;\n}\n\nexport type AvatarProps = AvatarInitialProps | AvatarImageProps;\n\n// Figma sizes: lg=40px, md=32px, sm=24px\nconst sizeStyles: Record<AvatarSize, string> = {\n lg: 'size-10',\n md: 'size-8',\n sm: 'size-6',\n};\n\n// Figma text sizes for initials: body-medium at lg, scales down proportionally\nconst initialTextStyles: Record<AvatarSize, string> = {\n lg: 'text-body font-semibold',\n md: 'text-body-xs font-semibold',\n sm: 'text-body-tiny font-semibold',\n};\n\n// Figma shape radii: circle=full, square=8px (rounded-lg)\nconst shapeStyles: Record<AvatarShape, string> = {\n circle: 'rounded-full',\n square: 'rounded-lg',\n};\n\nexport function Avatar(props: AvatarProps) {\n const { size = 'lg', shape = 'circle', className } = props;\n\n const base = clsx(\n 'shrink-0 overflow-hidden',\n sizeStyles[size],\n shapeStyles[shape],\n className,\n );\n\n if (props.type === 'image') {\n return (\n <div className={base}>\n <img\n src={props.src}\n alt={props.alt ?? ''}\n className=\"size-full object-cover\"\n />\n </div>\n );\n }\n\n return (\n <div\n className={clsx(base, 'flex items-center justify-center')}\n style={{\n background:\n 'linear-gradient(135deg, var(--color-graphic-blue) 30%, var(--color-graphic-red) 100%)',\n }}\n >\n <span\n className={clsx(\n 'select-none leading-none text-text-brand-on-brand',\n initialTextStyles[size],\n )}\n >\n {props.initial.charAt(0).toUpperCase()}\n </span>\n </div>\n );\n}\n","import { type ReactNode } from 'react';\nimport clsx from 'clsx';\n\nexport interface NavItemProps {\n icon?: ReactNode;\n label: string;\n isActive?: boolean;\n /** Red indicator dot at top-right corner (e.g. unread count) */\n indicator?: boolean;\n /** Collapsed mode — icon only, label hidden */\n collapsed?: boolean;\n className?: string;\n}\n\nexport function NavItem({\n icon,\n label,\n isActive = false,\n indicator = false,\n collapsed = false,\n className,\n}: NavItemProps) {\n return (\n <span\n className={clsx(\n 'relative flex h-11 w-full items-center gap-3 rounded-xl px-3.5 py-2.5 transition-colors',\n collapsed && 'justify-center',\n isActive\n ? 'bg-background-brand text-text-brand-on-brand'\n : [\n 'border border-border-default bg-background-default text-text-default-secondary',\n 'hover:bg-background-brand-tertiary-hover hover:border-border-brand-tertiary hover:text-text-brand',\n ],\n className,\n )}\n >\n {icon !== undefined && (\n <span className=\"shrink-0 [&_svg]:size-4\">{icon}</span>\n )}\n {!collapsed && (\n <span className=\"flex-1 min-w-0 truncate text-body-sm font-regular leading-snug\">\n {label}\n </span>\n )}\n {indicator && (\n <span className=\"absolute -right-px -top-px size-2 rounded-full bg-background-danger\" />\n )}\n </span>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA4D;AAC5D,8BAAwB;AACxB,IAAAA,eAAiB;;;ACFhB,IAAAC,eAAiB;;;ACAlB,kBAAiB;AA0DT;AAhCR,IAAM,aAAyC;AAAA,EAC7C,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAGA,IAAM,oBAAgD;AAAA,EACpD,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAGA,IAAM,cAA2C;AAAA,EAC/C,QAAQ;AAAA,EACR,QAAQ;AACV;AAEO,SAAS,OAAO,OAAoB;AACzC,QAAM,EAAE,OAAO,MAAM,QAAQ,UAAU,UAAU,IAAI;AAErD,QAAM,WAAO,YAAAC;AAAA,IACX;AAAA,IACA,WAAW,IAAI;AAAA,IACf,YAAY,KAAK;AAAA,IACjB;AAAA,EACF;AAEA,MAAI,MAAM,SAAS,SAAS;AAC1B,WACE,4CAAC,SAAI,WAAW,MACd;AAAA,MAAC;AAAA;AAAA,QACC,KAAK,MAAM;AAAA,QACX,KAAK,MAAM,OAAO;AAAA,QAClB,WAAU;AAAA;AAAA,IACZ,GACF;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAW,YAAAA,SAAK,MAAM,kCAAkC;AAAA,MACxD,OAAO;AAAA,QACL,YACE;AAAA,MACJ;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,eAAW,YAAAA;AAAA,YACT;AAAA,YACA,kBAAkB,IAAI;AAAA,UACxB;AAAA,UAEC,gBAAM,QAAQ,OAAO,CAAC,EAAE,YAAY;AAAA;AAAA,MACvC;AAAA;AAAA,EACF;AAEJ;;;ACpFA,IAAAC,eAAiB;AAsBb,IAAAC,sBAAA;AATG,SAAS,QAAQ;AAAA,EACtB;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ;AACF,GAAiB;AACf,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAW,aAAAC;AAAA,QACT;AAAA,QACA,aAAa;AAAA,QACb,WACI,iDACA;AAAA,UACE;AAAA,UACA;AAAA,QACF;AAAA,QACJ;AAAA,MACF;AAAA,MAEC;AAAA,iBAAS,UACR,6CAAC,UAAK,WAAU,2BAA2B,gBAAK;AAAA,QAEjD,CAAC,aACA,6CAAC,UAAK,WAAU,kEACb,iBACH;AAAA,QAED,aACC,6CAAC,UAAK,WAAU,uEAAsE;AAAA;AAAA;AAAA,EAE1F;AAEJ;;;AFaI,IAAAC,sBAAA;;;ADpDA,IAAAC,sBAAA;AAFJ,SAAS,WAAW;AAClB,SACE,8CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACxJ;AAAA,iDAAC,UAAK,GAAE,KAAI,GAAE,KAAI,OAAM,KAAI,QAAO,KAAI,IAAG,KAAI;AAAA,IAC9C,6CAAC,UAAK,GAAE,MAAK,GAAE,KAAI,OAAM,KAAI,QAAO,KAAI,IAAG,KAAI;AAAA,IAC/C,6CAAC,UAAK,GAAE,MAAK,GAAE,MAAK,OAAM,KAAI,QAAO,KAAI,IAAG,KAAI;AAAA,IAChD,6CAAC,UAAK,GAAE,KAAI,GAAE,MAAK,OAAM,KAAI,QAAO,KAAI,IAAG,KAAI;AAAA,KACjD;AAEJ;AAEA,SAAS,aAAa;AACpB,SACE,8CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACxJ;AAAA,iDAAC,aAAQ,QAAO,4BAA2B;AAAA,IAC3C,6CAAC,cAAS,QAAO,oBAAmB;AAAA,IACpC,6CAAC,cAAS,QAAO,oBAAmB;AAAA,KACtC;AAEJ;AAEA,SAAS,eAAe;AACtB,SACE,8CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACxJ;AAAA,iDAAC,UAAK,GAAE,KAAI,GAAE,KAAI,OAAM,MAAK,QAAO,MAAK,IAAG,KAAI;AAAA,IAChD,6CAAC,UAAK,GAAE,8CAA6C;AAAA,KACvD;AAEJ;AAEA,SAAS,YAAY;AACnB,SACE,8CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACxJ;AAAA,iDAAC,UAAK,GAAE,6CAA4C;AAAA,IACpD,6CAAC,YAAO,IAAG,KAAI,IAAG,KAAI,GAAE,KAAI;AAAA,IAC5B,6CAAC,UAAK,GAAE,8BAA6B;AAAA,IACrC,6CAAC,UAAK,GAAE,6BAA4B;AAAA,KACtC;AAEJ;AAEA,SAAS,UAAU;AACjB,SACE,8CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACxJ;AAAA,iDAAC,UAAK,GAAE,uBAAsB;AAAA,IAC9B,6CAAC,UAAK,GAAE,0BAAyB;AAAA,IACjC,6CAAC,YAAO,IAAG,KAAI,IAAG,MAAK,GAAE,KAAI,MAAK,gBAAe;AAAA,KACnD;AAEJ;AAEA,SAAS,eAAe;AACtB,SACE,8CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACxJ;AAAA,iDAAC,UAAK,GAAE,8DAA6D;AAAA,IACrE,6CAAC,cAAS,QAAO,kBAAiB;AAAA,IAClC,6CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,KAAI,IAAG,MAAK;AAAA,IACrC,6CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,KAAI,IAAG,MAAK;AAAA,KACvC;AAEJ;AAEA,SAAS,WAAW;AAClB,SACE,8CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACxJ;AAAA,iDAAC,UAAK,GAAE,+CAA8C;AAAA,IACtD,6CAAC,UAAK,GAAE,8BAA6B;AAAA,KACvC;AAEJ;AAEA,SAAS,aAAa;AACpB,SACE,8CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACxJ;AAAA,iDAAC,UAAK,GAAE,KAAI,GAAE,KAAI,OAAM,MAAK,QAAO,KAAI,IAAG,KAAI;AAAA,IAC/C,6CAAC,UAAK,GAAE,KAAI,GAAE,MAAK,OAAM,MAAK,QAAO,KAAI,IAAG,KAAI;AAAA,IAChD,6CAAC,UAAK,IAAG,KAAI,IAAG,KAAI,IAAG,QAAO,IAAG,KAAI;AAAA,IACrC,6CAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,QAAO,IAAG,MAAK;AAAA,KACzC;AAEJ;AAEA,SAAS,eAAe;AACtB,SACE,8CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACxJ;AAAA,iDAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,IAC9B,6CAAC,UAAK,GAAE,0mBAAymB;AAAA,KACnnB;AAEJ;AAEA,SAAS,oBAAoB;AAC3B,SACE,8CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACxJ;AAAA,iDAAC,UAAK,GAAE,6EAA4E;AAAA,IACpF,6CAAC,UAAK,GAAE,KAAI,GAAE,KAAI,OAAM,KAAI,QAAO,KAAI,IAAG,KAAI;AAAA,IAC9C,6CAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA,IACrC,6CAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA,KACvC;AAEJ;AAEA,SAAS,YAAY;AACnB,SACE,8CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACxJ;AAAA,iDAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK;AAAA,IAC/B,6CAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA,IACrC,6CAAC,UAAK,GAAE,8FAA6F;AAAA,KACvG;AAEJ;AAEA,SAAS,kBAAkB;AACzB,SACE,6CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAAM,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MAC1J,uDAAC,cAAS,QAAO,mBAAkB,GACrC;AAEJ;AAEA,SAAS,mBAAmB;AAC1B,SACE,6CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAAM,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MAC1J,uDAAC,cAAS,QAAO,kBAAiB,GACpC;AAEJ;AAEA,SAAS,mBAAmB;AAC1B,SACE,8CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACxJ;AAAA,iDAAC,YAAO,IAAG,MAAK,IAAG,KAAI,GAAE,KAAI,MAAK,gBAAe;AAAA,IACjD,6CAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI,MAAK,gBAAe;AAAA,IAClD,6CAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI,MAAK,gBAAe;AAAA,KACpD;AAEJ;AAEA,SAAS,aAAa;AACpB,SACE,8CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACxJ;AAAA,iDAAC,UAAK,GAAE,2CAA0C;AAAA,IAClD,6CAAC,cAAS,QAAO,oBAAmB;AAAA,IACpC,6CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,KAAI,IAAG,MAAK;AAAA,KACvC;AAEJ;AAIA,SAAS,YAAY,EAAE,UAAU,GAA2B;AAC1D,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAW,aAAAC;AAAA,QACT;AAAA,QACA,YAAY,mBAAmB;AAAA,MACjC;AAAA,MAEA;AAAA,qDAAC,SAAI,WAAU,0GACb,wDAAC,SAAI,WAAU,8BACb;AAAA,uDAAC,SAAI,WAAU,iCAAgC;AAAA,UAC/C,6CAAC,SAAI,WAAU,oCAAmC;AAAA,UAClD,6CAAC,SAAI,WAAU,oCAAmC;AAAA,UAClD,6CAAC,SAAI,WAAU,iCAAgC;AAAA,WACjD,GACF;AAAA,QACC,CAAC,aACA,6CAAC,UAAK,WAAU,iFAAgF,kBAEhG;AAAA;AAAA;AAAA,EAEJ;AAEJ;AAaA,SAAS,YAAY,EAAE,IAAI,MAAM,OAAO,WAAW,WAAW,IAAI,GAAqB;AACrF,SACE,6CAAC,mCAAQ,IAAQ,KAAU,WAAU,6BAClC,WAAC,EAAE,SAAS,MACX;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,EACF,GAEJ;AAEJ;AAIA,SAAS,SAAS,EAAE,WAAW,MAAM,MAAM,SAAS,GAA6E;AAC/H,QAAM,CAAC,UAAU,WAAW,QAAI,uBAAS,KAAK;AAC9C,QAAM,cAAU,qBAAuB,IAAI;AAC3C,QAAM,UAAU,KAAK,KAAK,EAAE,OAAO,CAAC;AAEpC,8BAAU,MAAM;AACd,QAAI,CAAC,SAAU;AACf,aAAS,mBAAmB,GAAe;AACzC,UAAI,QAAQ,WAAW,CAAC,QAAQ,QAAQ,SAAS,EAAE,MAAc,GAAG;AAClE,oBAAY,KAAK;AAAA,MACnB;AAAA,IACF;AACA,aAAS,iBAAiB,aAAa,kBAAkB;AACzD,WAAO,MAAM,SAAS,oBAAoB,aAAa,kBAAkB;AAAA,EAC3E,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,YACJ;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,SAAS,MAAM;AAAE,oBAAY,KAAK;AAAG,iBAAS;AAAA,MAAG;AAAA,MACjD,WAAU;AAAA,MAEV;AAAA,qDAAC,cAAW;AAAA,QAAE;AAAA;AAAA;AAAA,EAEhB;AAGF,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAW,aAAAA;AAAA,QACT;AAAA,QACA,YAAY,mBAAmB;AAAA,MACjC;AAAA,MAEC,sBACC,8CAAC,SAAI,WAAU,YAAW,KAAK,SAC7B;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,cAAW;AAAA,YACX,iBAAc;AAAA,YACd,iBAAe;AAAA,YACf,SAAS,MAAM,YAAY,OAAK,CAAC,CAAC;AAAA,YAClC,WAAU;AAAA,YAEV,uDAAC,UAAO,SAAkB,MAAK,MAAK,OAAM,UAAS;AAAA;AAAA,QACrD;AAAA,QACC,YACC,6CAAC,SAAI,WAAU,2HACZ,qBACH;AAAA,SAEJ,IAEA,8EACE;AAAA,qDAAC,UAAO,SAAkB,MAAK,MAAK,OAAM,UAAS;AAAA,QACnD,8CAAC,SAAI,WAAU,wCACb;AAAA,uDAAC,UAAK,WAAU,sEACb,gBACH;AAAA,UACA,6CAAC,UAAK,WAAU,iFACb,gBACH;AAAA,WACF;AAAA,QACA,8CAAC,SAAI,WAAU,qBAAoB,KAAK,SACtC;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,cAAW;AAAA,cACX,iBAAc;AAAA,cACd,iBAAe;AAAA,cACf,SAAS,MAAM,YAAY,OAAK,CAAC,CAAC;AAAA,cAClC,WAAU;AAAA,cAEV,uDAAC,oBAAiB;AAAA;AAAA,UACpB;AAAA,UACC,YACC,6CAAC,SAAI,WAAU,4HACZ,qBACH;AAAA,WAEJ;AAAA,SACF;AAAA;AAAA,EAEJ;AAEJ;AAaO,SAAS,WAAW,EAAE,WAAW,UAAU,UAAU,OAAO,UAAU,UAAU,SAAS,GAAoB;AAElH,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAW,aAAAA;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACA,YAAY,SAAS;AAAA,MACvB;AAAA,MAGA;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,cAAY,YAAY,mBAAmB;AAAA,YAC3C,SAAS;AAAA,YACT,eAAW,aAAAA;AAAA,cACT;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAAA,YAEC,sBAAY,6CAAC,oBAAiB,IAAK,6CAAC,mBAAgB;AAAA;AAAA,QACvD;AAAA,QAGA,8CAAC,SAAI,WAAU,sCACb;AAAA,uDAAC,eAAY,WAAsB;AAAA,UAEnC,8CAAC,SAAI,WAAU,sDACb;AAAA,yDAAC,eAAY,IAAG,cAAa,MAAM,6CAAC,YAAS,GAAI,OAAM,aAAY,WAAsB,KAAG,MAAC;AAAA,YAC7F,6CAAC,eAAY,IAAG,aAAY,MAAM,6CAAC,cAAW,GAAI,OAAM,YAAW,WAAsB,WAAS,MAAC;AAAA,YACnG,6CAAC,eAAY,IAAG,cAAa,MAAM,6CAAC,gBAAa,GAAI,OAAM,aAAY,WAAsB;AAAA,YAC7F,6CAAC,eAAY,IAAG,cAAa,MAAM,6CAAC,aAAU,GAAI,OAAM,aAAY,WAAsB;AAAA,YAC1F,6CAAC,eAAY,IAAG,YAAW,MAAM,6CAAC,gBAAa,GAAI,OAAM,WAAU,WAAsB;AAAA,YACzF,6CAAC,eAAY,IAAG,aAAY,MAAM,6CAAC,WAAQ,GAAI,OAAM,gBAAe,WAAsB;AAAA,YAC1F,6CAAC,eAAY,IAAG,WAAU,MAAM,6CAAC,YAAS,GAAI,OAAM,UAAS,WAAsB;AAAA,YACnF,6CAAC,eAAY,IAAG,oBAAmB,MAAM,6CAAC,aAAU,GAAI,OAAM,iBAAgB,WAAsB;AAAA,YACpG,6CAAC,eAAY,IAAG,WAAU,MAAM,6CAAC,qBAAkB,GAAI,OAAM,gBAAe,WAAsB;AAAA,YACjG,WACC,6CAAC,eAAY,IAAG,WAAU,MAAM,6CAAC,cAAW,GAAI,OAAM,UAAS,WAAsB;AAAA,aAEzF;AAAA,WACF;AAAA,QAGA,8CAAC,SAAI,WAAU,iBACZ;AAAA,qBACC,6CAAC,SAAI,WAAU,aACb;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACH,MAAM,6CAAC,gBAAa;AAAA,cACpB,OAAM;AAAA,cACN;AAAA;AAAA,UACF,GACF;AAAA,UAEF,6CAAC,SAAI,WAAU,kCACb,uDAAC,YAAS,WAAsB,MAAM,UAAU,MAAM,UAAU,UAAoB,GACtF;AAAA,WACF;AAAA;AAAA;AAAA,EACF;AAEJ;","names":["import_clsx","import_clsx","clsx","import_clsx","import_jsx_runtime","clsx","import_jsx_runtime","import_jsx_runtime","clsx"]}
|
|
1
|
+
{"version":3,"sources":["../src/sidebar/index.tsx","../src/components/avatar/avatar.tsx","../src/components/chrome/nav-item.tsx","../src/sidebar/nav-tabs.tsx"],"sourcesContent":["import { type ReactNode, useEffect, useRef, useState } from 'react';\nimport { NavLink } from 'react-router-dom';\nimport clsx from 'clsx';\nimport {\n LuBell,\n LuBuilding,\n LuChevronLeft,\n LuChevronRight,\n LuClipboardList,\n LuEllipsisVertical,\n LuFileText,\n LuGlobe,\n LuLayers,\n LuLayoutGrid,\n LuLogOut,\n LuRss,\n LuServer,\n LuSettings,\n LuUsers,\n} from 'react-icons/lu';\n\nimport { Avatar, NavItem } from '../index';\n\n/** Every primary nav glyph renders at 16px. */\nconst NAV_ICON = 'size-4';\n\n// ── Logo ────────────────────────────────────────────────────────────────────\n\nfunction SidebarLogo({ collapsed }: { collapsed: boolean }) {\n return (\n <div\n className={clsx(\n 'flex shrink-0 items-center overflow-hidden p-4',\n collapsed ? 'justify-center' : 'gap-2.5',\n )}\n >\n <div className=\"flex shrink-0 size-10 items-center justify-center rounded-xl bg-brand-hover overflow-hidden\">\n <div className=\"grid grid-cols-2 gap-[3px]\">\n <div className=\"size-2 rounded-[2px] bg-white\" />\n <div className=\"size-2 rounded-[2px] bg-white/50\" />\n <div className=\"size-2 rounded-[2px] bg-white/50\" />\n <div className=\"size-2 rounded-[2px] bg-white\" />\n </div>\n </div>\n {!collapsed && (\n <span className=\"text-heading font-semibold text-default tracking-tight whitespace-nowrap\">\n SCIC\n </span>\n )}\n </div>\n );\n}\n\n// ── NavLink item ─────────────────────────────────────────────────────────────\n\ninterface NavLinkItemProps {\n to: string;\n icon: ReactNode;\n label: string;\n indicator?: boolean;\n collapsed: boolean;\n end?: boolean;\n}\n\nfunction NavLinkItem({ to, icon, label, indicator, collapsed, end }: NavLinkItemProps) {\n return (\n <NavLink to={to} end={end} className=\"block w-full no-underline\">\n {({ isActive }) => (\n <NavItem\n icon={icon}\n label={label}\n isActive={isActive}\n indicator={indicator}\n collapsed={collapsed}\n />\n )}\n </NavLink>\n );\n}\n\n// ── User card ────────────────────────────────────────────────────────────────\n\nfunction UserCard({ collapsed, name, role, onLogout }: { collapsed: boolean; name: string; role: string; onLogout: () => void }) {\n const [menuOpen, setMenuOpen] = useState(false);\n const menuRef = useRef<HTMLDivElement>(null);\n const initial = name.trim().charAt(0);\n\n useEffect(() => {\n if (!menuOpen) return;\n function handleClickOutside(e: MouseEvent) {\n if (menuRef.current && !menuRef.current.contains(e.target as Node)) {\n setMenuOpen(false);\n }\n }\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, [menuOpen]);\n\n const menuItems = (\n <button\n type=\"button\"\n onClick={() => { setMenuOpen(false); onLogout(); }}\n className=\"flex w-full items-center gap-2 px-3 py-2 text-body-sm text-default hover:bg-default-hover transition-colors\"\n >\n <LuLogOut className=\"size-3.5\" aria-hidden />\n Sign out\n </button>\n );\n\n return (\n <div\n className={clsx(\n 'flex shrink-0 items-center p-4',\n collapsed ? 'justify-center' : 'gap-2.5',\n )}\n >\n {collapsed ? (\n <div className=\"relative\" ref={menuRef}>\n <button\n type=\"button\"\n aria-label=\"User options\"\n aria-haspopup=\"menu\"\n aria-expanded={menuOpen}\n onClick={() => setMenuOpen(v => !v)}\n className=\"rounded-full\"\n >\n <Avatar initial={initial} size=\"md\" shape=\"circle\" />\n </button>\n {menuOpen && (\n <div className=\"absolute bottom-0 left-full ml-2 w-36 rounded-lg border border-default bg-default shadow-md py-1 z-20\">\n {menuItems}\n </div>\n )}\n </div>\n ) : (\n <>\n <Avatar initial={initial} size=\"md\" shape=\"circle\" />\n <div className=\"flex flex-1 min-w-0 flex-col gap-0.5\">\n <span className=\"truncate text-body-sm font-semibold text-default leading-snug\">\n {name}\n </span>\n <span className=\"truncate text-body-tiny font-regular text-default-secondary leading-none\">\n {role}\n </span>\n </div>\n <div className=\"relative shrink-0\" ref={menuRef}>\n <button\n type=\"button\"\n aria-label=\"User options\"\n aria-haspopup=\"menu\"\n aria-expanded={menuOpen}\n onClick={() => setMenuOpen(v => !v)}\n className=\"flex size-6 items-center justify-center rounded-md text-default-secondary hover:bg-default-hover hover:text-default transition-colors\"\n >\n <LuEllipsisVertical className=\"size-4\" aria-hidden />\n </button>\n {menuOpen && (\n <div className=\"absolute bottom-full right-0 mb-1 w-36 rounded-lg border border-default bg-default shadow-md py-1 z-20\">\n {menuItems}\n </div>\n )}\n </div>\n </>\n )}\n </div>\n );\n}\n\n// ── Main sidebar ─────────────────────────────────────────────────────────────\n\ninterface AppSidebarProps {\n collapsed: boolean;\n onToggle: () => void;\n isAdmin?: boolean;\n userName: string;\n userRole: string;\n onLogout: () => void;\n}\n\nexport function AppSidebar({ collapsed, onToggle, isAdmin = false, userName, userRole, onLogout }: AppSidebarProps) {\n\n return (\n <aside\n className={clsx(\n 'relative flex flex-col shrink-0 transition-all duration-200',\n 'bg-default-secondary border-r border-default rounded-xl',\n 'h-full',\n collapsed ? 'w-20' : 'w-80',\n )}\n >\n {/* Toggle button */}\n <button\n type=\"button\"\n aria-label={collapsed ? 'Expand sidebar' : 'Collapse sidebar'}\n onClick={onToggle}\n className={clsx(\n 'absolute -right-3 top-5 z-10 flex size-6 items-center justify-center rounded-full',\n 'bg-default border border-default text-default-secondary',\n 'hover:bg-default-hover shadow-sm transition-colors',\n )}\n >\n {collapsed ? (\n <LuChevronRight className=\"size-3\" strokeWidth={2.5} aria-hidden />\n ) : (\n <LuChevronLeft className=\"size-3\" strokeWidth={2.5} aria-hidden />\n )}\n </button>\n\n {/* Top — logo + primary nav */}\n <div className=\"flex flex-1 min-h-0 flex-col gap-1\">\n <SidebarLogo collapsed={collapsed} />\n\n <nav className=\"flex flex-col gap-3 overflow-y-auto px-4 pt-2 pb-3\">\n <NavLinkItem to=\"/dashboard\" icon={<LuLayoutGrid className={NAV_ICON} aria-hidden />} label=\"Dashboard\" collapsed={collapsed} end />\n <NavLinkItem to=\"/entities\" icon={<LuLayers className={NAV_ICON} aria-hidden />} label=\"Entities\" collapsed={collapsed} indicator />\n <NavLinkItem to=\"/suppliers\" icon={<LuBuilding className={NAV_ICON} aria-hidden />} label=\"Suppliers\" collapsed={collapsed} />\n <NavLinkItem to=\"/customers\" icon={<LuUsers className={NAV_ICON} aria-hidden />} label=\"Customers\" collapsed={collapsed} />\n <NavLinkItem to=\"/sources\" icon={<LuFileText className={NAV_ICON} aria-hidden />} label=\"Sources\" collapsed={collapsed} />\n <NavLinkItem to=\"/articles\" icon={<LuRss className={NAV_ICON} aria-hidden />} label=\"Intelligence\" collapsed={collapsed} />\n <NavLinkItem to=\"/alerts\" icon={<LuBell className={NAV_ICON} aria-hidden />} label=\"Alerts\" collapsed={collapsed} />\n <NavLinkItem to=\"/website-scraper\" icon={<LuGlobe className={NAV_ICON} aria-hidden />} label=\"Website Intel\" collapsed={collapsed} />\n <NavLinkItem to=\"/review\" icon={<LuClipboardList className={NAV_ICON} aria-hidden />} label=\"Review queue\" collapsed={collapsed} />\n {isAdmin && (\n <NavLinkItem to=\"/queues\" icon={<LuServer className={NAV_ICON} aria-hidden />} label=\"Queues\" collapsed={collapsed} />\n )}\n </nav>\n </div>\n\n {/* Bottom — settings + user card */}\n <div className=\"flex flex-col\">\n {isAdmin && (\n <div className=\"px-4 pb-2\">\n <NavLinkItem\n to=\"/settings\"\n icon={<LuSettings className={NAV_ICON} aria-hidden />}\n label=\"Settings\"\n collapsed={collapsed}\n />\n </div>\n )}\n <div className=\"border-t border-default\">\n <UserCard collapsed={collapsed} name={userName} role={userRole} onLogout={onLogout} />\n </div>\n </div>\n </aside>\n );\n}\n\n// ── Route-driven navigation ────────────────────────────────────────────────────\n// Lives on this entry point (not the main one) because it needs react-router-dom.\n\nexport { NavTabs } from './nav-tabs';\nexport type { NavTabsProps, NavTabItem } from './nav-tabs';\n","import clsx from 'clsx';\n\nexport type AvatarSize = 'sm' | 'md' | 'lg';\nexport type AvatarShape = 'circle' | 'square';\n\nexport interface AvatarInitialProps {\n type?: 'initial';\n /** Single character — Figma spec: one letter only to avoid overflow */\n initial: string;\n size?: AvatarSize;\n shape?: AvatarShape;\n className?: string;\n}\n\nexport interface AvatarImageProps {\n type: 'image';\n src: string;\n alt?: string;\n size?: AvatarSize;\n shape?: AvatarShape;\n className?: string;\n}\n\nexport type AvatarProps = AvatarInitialProps | AvatarImageProps;\n\n// Figma sizes: lg=40px, md=32px, sm=24px\nconst sizeStyles: Record<AvatarSize, string> = {\n lg: 'size-10',\n md: 'size-8',\n sm: 'size-6',\n};\n\n// Figma text sizes for initials: body-medium at lg, scales down proportionally\nconst initialTextStyles: Record<AvatarSize, string> = {\n lg: 'text-body font-semibold',\n md: 'text-body-xs font-semibold',\n sm: 'text-body-tiny font-semibold',\n};\n\n// Figma shape radii: circle=full, square: lg/md=8px (rounded-lg), sm=4px (rounded)\nfunction getShapeClass(shape: AvatarShape, size: AvatarSize): string {\n if (shape === 'circle') return 'rounded-full';\n return size === 'sm' ? 'rounded' : 'rounded-lg';\n}\n\nexport function Avatar(props: AvatarProps) {\n const { size = 'lg', shape = 'circle', className } = props;\n\n const base = clsx(\n 'shrink-0 overflow-hidden',\n sizeStyles[size],\n getShapeClass(shape, size),\n className,\n );\n\n if (props.type === 'image') {\n return (\n <div className={base}>\n <img\n src={props.src}\n alt={props.alt ?? ''}\n className=\"size-full object-cover\"\n />\n </div>\n );\n }\n\n return (\n <div\n className={clsx(base, 'flex items-center justify-center')}\n style={{\n background:\n 'linear-gradient(135deg, var(--color-graphic-blue) 30%, var(--color-graphic-red) 100%)',\n }}\n >\n <span\n className={clsx(\n 'select-none leading-none text-brand-on-brand',\n initialTextStyles[size],\n )}\n >\n {props.initial.charAt(0).toUpperCase()}\n </span>\n </div>\n );\n}\n","import { type ReactNode } from 'react';\nimport clsx from 'clsx';\n\nexport type NavItemSize = 'sm' | 'md';\n\nexport interface NavItemProps {\n icon?: ReactNode;\n label: string;\n isActive?: boolean;\n /** Red indicator dot at top-right corner (e.g. unread count) */\n indicator?: boolean;\n /** Collapsed mode — icon only, label hidden */\n collapsed?: boolean;\n /** Row height. `sm` suits a dense secondary nav or a nested group. */\n size?: NavItemSize;\n className?: string;\n}\n\nconst SIZE: Record<NavItemSize, { box: string; label: string }> = {\n sm: { box: 'h-9 gap-2 rounded-lg px-2.5 py-1.5', label: 'text-body-xs' },\n md: { box: 'h-11 gap-3 rounded-xl px-3.5 py-2.5', label: 'text-body-sm' },\n};\n\nexport function NavItem({\n icon,\n label,\n isActive = false,\n indicator = false,\n collapsed = false,\n size = 'md',\n className,\n}: NavItemProps) {\n const s = SIZE[size];\n return (\n <span\n className={clsx(\n 'relative flex w-full items-center transition-colors',\n s.box,\n collapsed && 'justify-center',\n isActive\n ? 'bg-brand text-brand-on-brand'\n : [\n 'border border-default bg-default text-default-secondary',\n 'hover:bg-brand-tertiary-hover hover:border-brand-tertiary hover:text-brand',\n ],\n className,\n )}\n >\n {icon !== undefined && (\n <span className=\"shrink-0 [&_svg]:size-4\">{icon}</span>\n )}\n {!collapsed && (\n <span className={clsx('min-w-0 flex-1 truncate font-regular leading-snug', s.label)}>\n {label}\n </span>\n )}\n {indicator && (\n <span className=\"absolute -right-px -top-px size-2 rounded-full bg-danger\" />\n )}\n </span>\n );\n}\n","import { NavLink } from 'react-router-dom';\nimport clsx from 'clsx';\n\nexport interface NavTabItem {\n to: string;\n label: string;\n /** Match this route exactly — needed for an index route like `/account`. */\n end?: boolean;\n}\n\nexport interface NavTabsProps {\n items: NavTabItem[];\n className?: string;\n}\n\n/** Route-driven tab strip, backed by react-router's `NavLink`.\n *\n * Use this when each tab is its own route. For state-driven tabs that do not change\n * the URL, use `Tabs` from the main entry point instead — it has no router dependency.\n *\n * The active underline and label use `brand-emphasis` (#0C2D58), the brand fill colour\n * Figma specifies for a tab rule, rather than the lighter `brand` border token. */\nexport function NavTabs({ items, className }: NavTabsProps) {\n return (\n <div className={clsx('flex gap-6 overflow-x-auto border-b border-default', className)}>\n {items.map((tab) => (\n <NavLink\n key={tab.to}\n to={tab.to}\n end={tab.end}\n className={({ isActive }) =>\n clsx(\n 'shrink-0 whitespace-nowrap border-b-2 pb-3 text-body-sm transition-colors',\n isActive\n ? 'border-brand-emphasis font-semibold text-brand-emphasis'\n : 'border-transparent font-medium text-default-secondary hover:text-default',\n )\n }\n >\n {tab.label}\n </NavLink>\n ))}\n </div>\n );\n}\n"],"mappings":"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","names":["import_react_router_dom","import_clsx","clsx","import_clsx","import_jsx_runtime","clsx","import_clsx","import_jsx_runtime","clsx","import_jsx_runtime","clsx"]}
|
package/dist/sidebar.d.cts
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
|
|
3
|
+
interface NavTabItem {
|
|
4
|
+
to: string;
|
|
5
|
+
label: string;
|
|
6
|
+
/** Match this route exactly — needed for an index route like `/account`. */
|
|
7
|
+
end?: boolean;
|
|
8
|
+
}
|
|
9
|
+
interface NavTabsProps {
|
|
10
|
+
items: NavTabItem[];
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
13
|
+
/** Route-driven tab strip, backed by react-router's `NavLink`.
|
|
14
|
+
*
|
|
15
|
+
* Use this when each tab is its own route. For state-driven tabs that do not change
|
|
16
|
+
* the URL, use `Tabs` from the main entry point instead — it has no router dependency.
|
|
17
|
+
*
|
|
18
|
+
* The active underline and label use `brand-emphasis` (#0C2D58), the brand fill colour
|
|
19
|
+
* Figma specifies for a tab rule, rather than the lighter `brand` border token. */
|
|
20
|
+
declare function NavTabs({ items, className }: NavTabsProps): react.JSX.Element;
|
|
21
|
+
|
|
3
22
|
interface AppSidebarProps {
|
|
4
23
|
collapsed: boolean;
|
|
5
24
|
onToggle: () => void;
|
|
@@ -10,4 +29,4 @@ interface AppSidebarProps {
|
|
|
10
29
|
}
|
|
11
30
|
declare function AppSidebar({ collapsed, onToggle, isAdmin, userName, userRole, onLogout }: AppSidebarProps): react.JSX.Element;
|
|
12
31
|
|
|
13
|
-
export { AppSidebar };
|
|
32
|
+
export { AppSidebar, type NavTabItem, NavTabs, type NavTabsProps };
|
package/dist/sidebar.d.ts
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
|
|
3
|
+
interface NavTabItem {
|
|
4
|
+
to: string;
|
|
5
|
+
label: string;
|
|
6
|
+
/** Match this route exactly — needed for an index route like `/account`. */
|
|
7
|
+
end?: boolean;
|
|
8
|
+
}
|
|
9
|
+
interface NavTabsProps {
|
|
10
|
+
items: NavTabItem[];
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
13
|
+
/** Route-driven tab strip, backed by react-router's `NavLink`.
|
|
14
|
+
*
|
|
15
|
+
* Use this when each tab is its own route. For state-driven tabs that do not change
|
|
16
|
+
* the URL, use `Tabs` from the main entry point instead — it has no router dependency.
|
|
17
|
+
*
|
|
18
|
+
* The active underline and label use `brand-emphasis` (#0C2D58), the brand fill colour
|
|
19
|
+
* Figma specifies for a tab rule, rather than the lighter `brand` border token. */
|
|
20
|
+
declare function NavTabs({ items, className }: NavTabsProps): react.JSX.Element;
|
|
21
|
+
|
|
3
22
|
interface AppSidebarProps {
|
|
4
23
|
collapsed: boolean;
|
|
5
24
|
onToggle: () => void;
|
|
@@ -10,4 +29,4 @@ interface AppSidebarProps {
|
|
|
10
29
|
}
|
|
11
30
|
declare function AppSidebar({ collapsed, onToggle, isAdmin, userName, userRole, onLogout }: AppSidebarProps): react.JSX.Element;
|
|
12
31
|
|
|
13
|
-
export { AppSidebar };
|
|
32
|
+
export { AppSidebar, type NavTabItem, NavTabs, type NavTabsProps };
|