@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/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 import_react_router_dom = require("react-router-dom");
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/index.tsx
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
- var shapeStyles = {
57
- circle: "rounded-full",
58
- square: "rounded-lg"
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
- shapeStyles[shape],
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-text-brand-on-brand",
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 h-11 w-full items-center gap-3 rounded-xl px-3.5 py-2.5 transition-colors",
119
+ "relative flex w-full items-center transition-colors",
120
+ s.box,
115
121
  collapsed && "justify-center",
116
- isActive ? "bg-background-brand text-text-brand-on-brand" : [
117
- "border border-border-default bg-background-default text-text-default-secondary",
118
- "hover:bg-background-brand-tertiary-hover hover:border-border-brand-tertiary hover:text-text-brand"
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: "flex-1 min-w-0 truncate text-body-sm font-regular leading-snug", children: label }),
125
- indicator && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "absolute -right-px -top-px size-2 rounded-full bg-background-danger" })
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/index.tsx
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
- function GridIcon() {
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-background-brand-hover overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "grid grid-cols-2 gap-[3px]", children: [
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-text-default tracking-tight whitespace-nowrap", children: "SCIC" })
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)(import_react_router_dom.NavLink, { to, end, className: "block w-full no-underline", children: ({ isActive }) => /* @__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-text-default hover:bg-background-default-hover transition-colors",
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)(LogOutIcon, {}),
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-border-default bg-background-default shadow-md py-1 z-20", children: menuItems })
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-text-default leading-snug", children: name }),
321
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "truncate text-body-tiny font-regular text-text-default-secondary leading-none", children: role })
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-text-default-secondary hover:bg-background-default-hover hover:text-text-default transition-colors",
333
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MoreVerticalIcon, {})
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-border-default bg-background-default shadow-md py-1 z-20", children: menuItems })
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-background-default-secondary border-r border-border-default rounded-xl",
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-background-default border border-border-default text-text-default-secondary",
362
- "hover:bg-background-default-hover shadow-sm transition-colors"
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)(ChevronRightIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ChevronLeftIcon, {})
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)(GridIcon, {}), label: "Dashboard", collapsed, end: true }),
371
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLinkItem, { to: "/entities", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LayersIcon, {}), label: "Entities", collapsed, indicator: true }),
372
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLinkItem, { to: "/suppliers", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(BuildingIcon, {}), label: "Suppliers", collapsed }),
373
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLinkItem, { to: "/customers", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(UsersIcon, {}), label: "Customers", collapsed }),
374
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLinkItem, { to: "/sources", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(FileTextIcon, {}), label: "Sources", collapsed }),
375
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLinkItem, { to: "/articles", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(RssIcon, {}), label: "Intelligence", collapsed }),
376
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLinkItem, { to: "/alerts", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(BellIcon, {}), label: "Alerts", collapsed }),
377
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLinkItem, { to: "/website-scraper", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(GlobeIcon, {}), label: "Website Intel", collapsed }),
378
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLinkItem, { to: "/review", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ClipboardListIcon, {}), label: "Review queue", collapsed }),
379
- isAdmin && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavLinkItem, { to: "/queues", icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ServerIcon, {}), label: "Queues", collapsed })
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)(SettingsIcon, {}),
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-border-default", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(UserCard, { collapsed, name: userName, role: userRole, onLogout }) })
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
@@ -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":"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","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"]}
@@ -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 };