@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.js
CHANGED
|
@@ -1,12 +1,26 @@
|
|
|
1
1
|
// src/sidebar/index.tsx
|
|
2
2
|
import { useEffect, useRef, useState } from "react";
|
|
3
|
-
import { NavLink } from "react-router-dom";
|
|
3
|
+
import { NavLink as NavLink2 } from "react-router-dom";
|
|
4
4
|
import clsx4 from "clsx";
|
|
5
|
+
import {
|
|
6
|
+
LuBell,
|
|
7
|
+
LuBuilding,
|
|
8
|
+
LuChevronLeft,
|
|
9
|
+
LuChevronRight,
|
|
10
|
+
LuClipboardList,
|
|
11
|
+
LuEllipsisVertical,
|
|
12
|
+
LuFileText,
|
|
13
|
+
LuGlobe,
|
|
14
|
+
LuLayers,
|
|
15
|
+
LuLayoutGrid,
|
|
16
|
+
LuLogOut,
|
|
17
|
+
LuRss,
|
|
18
|
+
LuServer,
|
|
19
|
+
LuSettings,
|
|
20
|
+
LuUsers
|
|
21
|
+
} from "react-icons/lu";
|
|
5
22
|
|
|
6
|
-
// src/
|
|
7
|
-
import clsx3 from "clsx";
|
|
8
|
-
|
|
9
|
-
// src/components/avatar.tsx
|
|
23
|
+
// src/components/avatar/avatar.tsx
|
|
10
24
|
import clsx from "clsx";
|
|
11
25
|
import { jsx } from "react/jsx-runtime";
|
|
12
26
|
var sizeStyles = {
|
|
@@ -19,16 +33,16 @@ var initialTextStyles = {
|
|
|
19
33
|
md: "text-body-xs font-semibold",
|
|
20
34
|
sm: "text-body-tiny font-semibold"
|
|
21
35
|
};
|
|
22
|
-
|
|
23
|
-
circle
|
|
24
|
-
|
|
25
|
-
}
|
|
36
|
+
function getShapeClass(shape, size) {
|
|
37
|
+
if (shape === "circle") return "rounded-full";
|
|
38
|
+
return size === "sm" ? "rounded" : "rounded-lg";
|
|
39
|
+
}
|
|
26
40
|
function Avatar(props) {
|
|
27
41
|
const { size = "lg", shape = "circle", className } = props;
|
|
28
42
|
const base = clsx(
|
|
29
43
|
"shrink-0 overflow-hidden",
|
|
30
44
|
sizeStyles[size],
|
|
31
|
-
|
|
45
|
+
getShapeClass(shape, size),
|
|
32
46
|
className
|
|
33
47
|
);
|
|
34
48
|
if (props.type === "image") {
|
|
@@ -52,7 +66,7 @@ function Avatar(props) {
|
|
|
52
66
|
"span",
|
|
53
67
|
{
|
|
54
68
|
className: clsx(
|
|
55
|
-
"select-none leading-none text-
|
|
69
|
+
"select-none leading-none text-brand-on-brand",
|
|
56
70
|
initialTextStyles[size]
|
|
57
71
|
),
|
|
58
72
|
children: props.initial.charAt(0).toUpperCase()
|
|
@@ -62,144 +76,70 @@ function Avatar(props) {
|
|
|
62
76
|
);
|
|
63
77
|
}
|
|
64
78
|
|
|
65
|
-
// src/components/nav-item.tsx
|
|
79
|
+
// src/components/chrome/nav-item.tsx
|
|
66
80
|
import clsx2 from "clsx";
|
|
67
81
|
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
82
|
+
var SIZE = {
|
|
83
|
+
sm: { box: "h-9 gap-2 rounded-lg px-2.5 py-1.5", label: "text-body-xs" },
|
|
84
|
+
md: { box: "h-11 gap-3 rounded-xl px-3.5 py-2.5", label: "text-body-sm" }
|
|
85
|
+
};
|
|
68
86
|
function NavItem({
|
|
69
87
|
icon,
|
|
70
88
|
label,
|
|
71
89
|
isActive = false,
|
|
72
90
|
indicator = false,
|
|
73
91
|
collapsed = false,
|
|
92
|
+
size = "md",
|
|
74
93
|
className
|
|
75
94
|
}) {
|
|
95
|
+
const s = SIZE[size];
|
|
76
96
|
return /* @__PURE__ */ jsxs(
|
|
77
97
|
"span",
|
|
78
98
|
{
|
|
79
99
|
className: clsx2(
|
|
80
|
-
"relative flex
|
|
100
|
+
"relative flex w-full items-center transition-colors",
|
|
101
|
+
s.box,
|
|
81
102
|
collapsed && "justify-center",
|
|
82
|
-
isActive ? "bg-
|
|
83
|
-
"border border-
|
|
84
|
-
"hover:bg-
|
|
103
|
+
isActive ? "bg-brand text-brand-on-brand" : [
|
|
104
|
+
"border border-default bg-default text-default-secondary",
|
|
105
|
+
"hover:bg-brand-tertiary-hover hover:border-brand-tertiary hover:text-brand"
|
|
85
106
|
],
|
|
86
107
|
className
|
|
87
108
|
),
|
|
88
109
|
children: [
|
|
89
110
|
icon !== void 0 && /* @__PURE__ */ jsx2("span", { className: "shrink-0 [&_svg]:size-4", children: icon }),
|
|
90
|
-
!collapsed && /* @__PURE__ */ jsx2("span", { className: "
|
|
91
|
-
indicator && /* @__PURE__ */ jsx2("span", { className: "absolute -right-px -top-px size-2 rounded-full bg-
|
|
111
|
+
!collapsed && /* @__PURE__ */ jsx2("span", { className: clsx2("min-w-0 flex-1 truncate font-regular leading-snug", s.label), children: label }),
|
|
112
|
+
indicator && /* @__PURE__ */ jsx2("span", { className: "absolute -right-px -top-px size-2 rounded-full bg-danger" })
|
|
92
113
|
]
|
|
93
114
|
}
|
|
94
115
|
);
|
|
95
116
|
}
|
|
96
117
|
|
|
97
|
-
// src/
|
|
98
|
-
import {
|
|
118
|
+
// src/sidebar/nav-tabs.tsx
|
|
119
|
+
import { NavLink } from "react-router-dom";
|
|
120
|
+
import clsx3 from "clsx";
|
|
121
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
122
|
+
function NavTabs({ items, className }) {
|
|
123
|
+
return /* @__PURE__ */ jsx3("div", { className: clsx3("flex gap-6 overflow-x-auto border-b border-default", className), children: items.map((tab) => /* @__PURE__ */ jsx3(
|
|
124
|
+
NavLink,
|
|
125
|
+
{
|
|
126
|
+
to: tab.to,
|
|
127
|
+
end: tab.end,
|
|
128
|
+
className: ({ isActive }) => clsx3(
|
|
129
|
+
"shrink-0 whitespace-nowrap border-b-2 pb-3 text-body-sm transition-colors",
|
|
130
|
+
isActive ? "border-brand-emphasis font-semibold text-brand-emphasis" : "border-transparent font-medium text-default-secondary hover:text-default"
|
|
131
|
+
),
|
|
132
|
+
children: tab.label
|
|
133
|
+
},
|
|
134
|
+
tab.to
|
|
135
|
+
)) });
|
|
136
|
+
}
|
|
99
137
|
|
|
100
138
|
// src/sidebar/index.tsx
|
|
101
|
-
import { Fragment, jsx as jsx4, jsxs as
|
|
102
|
-
|
|
103
|
-
return /* @__PURE__ */ jsxs3("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
104
|
-
/* @__PURE__ */ jsx4("rect", { x: "3", y: "3", width: "7", height: "7", rx: "1" }),
|
|
105
|
-
/* @__PURE__ */ jsx4("rect", { x: "14", y: "3", width: "7", height: "7", rx: "1" }),
|
|
106
|
-
/* @__PURE__ */ jsx4("rect", { x: "14", y: "14", width: "7", height: "7", rx: "1" }),
|
|
107
|
-
/* @__PURE__ */ jsx4("rect", { x: "3", y: "14", width: "7", height: "7", rx: "1" })
|
|
108
|
-
] });
|
|
109
|
-
}
|
|
110
|
-
function LayersIcon() {
|
|
111
|
-
return /* @__PURE__ */ jsxs3("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
112
|
-
/* @__PURE__ */ jsx4("polygon", { points: "12 2 2 7 12 12 22 7 12 2" }),
|
|
113
|
-
/* @__PURE__ */ jsx4("polyline", { points: "2 17 12 22 22 17" }),
|
|
114
|
-
/* @__PURE__ */ jsx4("polyline", { points: "2 12 12 17 22 12" })
|
|
115
|
-
] });
|
|
116
|
-
}
|
|
117
|
-
function BuildingIcon() {
|
|
118
|
-
return /* @__PURE__ */ jsxs3("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
119
|
-
/* @__PURE__ */ jsx4("rect", { x: "2", y: "7", width: "20", height: "14", rx: "2" }),
|
|
120
|
-
/* @__PURE__ */ jsx4("path", { d: "M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16" })
|
|
121
|
-
] });
|
|
122
|
-
}
|
|
123
|
-
function UsersIcon() {
|
|
124
|
-
return /* @__PURE__ */ jsxs3("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
125
|
-
/* @__PURE__ */ jsx4("path", { d: "M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2" }),
|
|
126
|
-
/* @__PURE__ */ jsx4("circle", { cx: "9", cy: "7", r: "4" }),
|
|
127
|
-
/* @__PURE__ */ jsx4("path", { d: "M23 21v-2a4 4 0 0 0-3-3.87" }),
|
|
128
|
-
/* @__PURE__ */ jsx4("path", { d: "M16 3.13a4 4 0 0 1 0 7.75" })
|
|
129
|
-
] });
|
|
130
|
-
}
|
|
131
|
-
function RssIcon() {
|
|
132
|
-
return /* @__PURE__ */ jsxs3("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
133
|
-
/* @__PURE__ */ jsx4("path", { d: "M4 11a9 9 0 0 1 9 9" }),
|
|
134
|
-
/* @__PURE__ */ jsx4("path", { d: "M4 4a16 16 0 0 1 16 16" }),
|
|
135
|
-
/* @__PURE__ */ jsx4("circle", { cx: "5", cy: "19", r: "1", fill: "currentColor" })
|
|
136
|
-
] });
|
|
137
|
-
}
|
|
138
|
-
function FileTextIcon() {
|
|
139
|
-
return /* @__PURE__ */ jsxs3("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
140
|
-
/* @__PURE__ */ jsx4("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
|
|
141
|
-
/* @__PURE__ */ jsx4("polyline", { points: "14 2 14 8 20 8" }),
|
|
142
|
-
/* @__PURE__ */ jsx4("line", { x1: "16", y1: "13", x2: "8", y2: "13" }),
|
|
143
|
-
/* @__PURE__ */ jsx4("line", { x1: "16", y1: "17", x2: "8", y2: "17" })
|
|
144
|
-
] });
|
|
145
|
-
}
|
|
146
|
-
function BellIcon() {
|
|
147
|
-
return /* @__PURE__ */ jsxs3("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
148
|
-
/* @__PURE__ */ jsx4("path", { d: "M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9" }),
|
|
149
|
-
/* @__PURE__ */ jsx4("path", { d: "M13.73 21a2 2 0 0 1-3.46 0" })
|
|
150
|
-
] });
|
|
151
|
-
}
|
|
152
|
-
function ServerIcon() {
|
|
153
|
-
return /* @__PURE__ */ jsxs3("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
154
|
-
/* @__PURE__ */ jsx4("rect", { x: "2", y: "2", width: "20", height: "8", rx: "2" }),
|
|
155
|
-
/* @__PURE__ */ jsx4("rect", { x: "2", y: "14", width: "20", height: "8", rx: "2" }),
|
|
156
|
-
/* @__PURE__ */ jsx4("line", { x1: "6", y1: "6", x2: "6.01", y2: "6" }),
|
|
157
|
-
/* @__PURE__ */ jsx4("line", { x1: "6", y1: "18", x2: "6.01", y2: "18" })
|
|
158
|
-
] });
|
|
159
|
-
}
|
|
160
|
-
function SettingsIcon() {
|
|
161
|
-
return /* @__PURE__ */ jsxs3("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
162
|
-
/* @__PURE__ */ jsx4("circle", { cx: "12", cy: "12", r: "3" }),
|
|
163
|
-
/* @__PURE__ */ jsx4("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" })
|
|
164
|
-
] });
|
|
165
|
-
}
|
|
166
|
-
function ClipboardListIcon() {
|
|
167
|
-
return /* @__PURE__ */ jsxs3("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
168
|
-
/* @__PURE__ */ jsx4("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" }),
|
|
169
|
-
/* @__PURE__ */ jsx4("rect", { x: "9", y: "3", width: "6", height: "4", rx: "1" }),
|
|
170
|
-
/* @__PURE__ */ jsx4("line", { x1: "9", y1: "12", x2: "15", y2: "12" }),
|
|
171
|
-
/* @__PURE__ */ jsx4("line", { x1: "9", y1: "16", x2: "13", y2: "16" })
|
|
172
|
-
] });
|
|
173
|
-
}
|
|
174
|
-
function GlobeIcon() {
|
|
175
|
-
return /* @__PURE__ */ jsxs3("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
176
|
-
/* @__PURE__ */ jsx4("circle", { cx: "12", cy: "12", r: "10" }),
|
|
177
|
-
/* @__PURE__ */ jsx4("line", { x1: "2", y1: "12", x2: "22", y2: "12" }),
|
|
178
|
-
/* @__PURE__ */ jsx4("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" })
|
|
179
|
-
] });
|
|
180
|
-
}
|
|
181
|
-
function ChevronLeftIcon() {
|
|
182
|
-
return /* @__PURE__ */ jsx4("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__ */ jsx4("polyline", { points: "15 18 9 12 15 6" }) });
|
|
183
|
-
}
|
|
184
|
-
function ChevronRightIcon() {
|
|
185
|
-
return /* @__PURE__ */ jsx4("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__ */ jsx4("polyline", { points: "9 18 15 12 9 6" }) });
|
|
186
|
-
}
|
|
187
|
-
function MoreVerticalIcon() {
|
|
188
|
-
return /* @__PURE__ */ jsxs3("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
189
|
-
/* @__PURE__ */ jsx4("circle", { cx: "12", cy: "5", r: "1", fill: "currentColor" }),
|
|
190
|
-
/* @__PURE__ */ jsx4("circle", { cx: "12", cy: "12", r: "1", fill: "currentColor" }),
|
|
191
|
-
/* @__PURE__ */ jsx4("circle", { cx: "12", cy: "19", r: "1", fill: "currentColor" })
|
|
192
|
-
] });
|
|
193
|
-
}
|
|
194
|
-
function LogOutIcon() {
|
|
195
|
-
return /* @__PURE__ */ jsxs3("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
196
|
-
/* @__PURE__ */ jsx4("path", { d: "M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" }),
|
|
197
|
-
/* @__PURE__ */ jsx4("polyline", { points: "16 17 21 12 16 7" }),
|
|
198
|
-
/* @__PURE__ */ jsx4("line", { x1: "21", y1: "12", x2: "9", y2: "12" })
|
|
199
|
-
] });
|
|
200
|
-
}
|
|
139
|
+
import { Fragment, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
140
|
+
var NAV_ICON = "size-4";
|
|
201
141
|
function SidebarLogo({ collapsed }) {
|
|
202
|
-
return /* @__PURE__ */
|
|
142
|
+
return /* @__PURE__ */ jsxs2(
|
|
203
143
|
"div",
|
|
204
144
|
{
|
|
205
145
|
className: clsx4(
|
|
@@ -207,19 +147,19 @@ function SidebarLogo({ collapsed }) {
|
|
|
207
147
|
collapsed ? "justify-center" : "gap-2.5"
|
|
208
148
|
),
|
|
209
149
|
children: [
|
|
210
|
-
/* @__PURE__ */ jsx4("div", { className: "flex shrink-0 size-10 items-center justify-center rounded-xl bg-
|
|
150
|
+
/* @__PURE__ */ jsx4("div", { className: "flex shrink-0 size-10 items-center justify-center rounded-xl bg-brand-hover overflow-hidden", children: /* @__PURE__ */ jsxs2("div", { className: "grid grid-cols-2 gap-[3px]", children: [
|
|
211
151
|
/* @__PURE__ */ jsx4("div", { className: "size-2 rounded-[2px] bg-white" }),
|
|
212
152
|
/* @__PURE__ */ jsx4("div", { className: "size-2 rounded-[2px] bg-white/50" }),
|
|
213
153
|
/* @__PURE__ */ jsx4("div", { className: "size-2 rounded-[2px] bg-white/50" }),
|
|
214
154
|
/* @__PURE__ */ jsx4("div", { className: "size-2 rounded-[2px] bg-white" })
|
|
215
155
|
] }) }),
|
|
216
|
-
!collapsed && /* @__PURE__ */ jsx4("span", { className: "text-heading font-semibold text-
|
|
156
|
+
!collapsed && /* @__PURE__ */ jsx4("span", { className: "text-heading font-semibold text-default tracking-tight whitespace-nowrap", children: "SCIC" })
|
|
217
157
|
]
|
|
218
158
|
}
|
|
219
159
|
);
|
|
220
160
|
}
|
|
221
161
|
function NavLinkItem({ to, icon, label, indicator, collapsed, end }) {
|
|
222
|
-
return /* @__PURE__ */ jsx4(
|
|
162
|
+
return /* @__PURE__ */ jsx4(NavLink2, { to, end, className: "block w-full no-underline", children: ({ isActive }) => /* @__PURE__ */ jsx4(
|
|
223
163
|
NavItem,
|
|
224
164
|
{
|
|
225
165
|
icon,
|
|
@@ -244,7 +184,7 @@ function UserCard({ collapsed, name, role, onLogout }) {
|
|
|
244
184
|
document.addEventListener("mousedown", handleClickOutside);
|
|
245
185
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
246
186
|
}, [menuOpen]);
|
|
247
|
-
const menuItems = /* @__PURE__ */
|
|
187
|
+
const menuItems = /* @__PURE__ */ jsxs2(
|
|
248
188
|
"button",
|
|
249
189
|
{
|
|
250
190
|
type: "button",
|
|
@@ -252,9 +192,9 @@ function UserCard({ collapsed, name, role, onLogout }) {
|
|
|
252
192
|
setMenuOpen(false);
|
|
253
193
|
onLogout();
|
|
254
194
|
},
|
|
255
|
-
className: "flex w-full items-center gap-2 px-3 py-2 text-body-sm text-
|
|
195
|
+
className: "flex w-full items-center gap-2 px-3 py-2 text-body-sm text-default hover:bg-default-hover transition-colors",
|
|
256
196
|
children: [
|
|
257
|
-
/* @__PURE__ */ jsx4(
|
|
197
|
+
/* @__PURE__ */ jsx4(LuLogOut, { className: "size-3.5", "aria-hidden": true }),
|
|
258
198
|
"Sign out"
|
|
259
199
|
]
|
|
260
200
|
}
|
|
@@ -266,7 +206,7 @@ function UserCard({ collapsed, name, role, onLogout }) {
|
|
|
266
206
|
"flex shrink-0 items-center p-4",
|
|
267
207
|
collapsed ? "justify-center" : "gap-2.5"
|
|
268
208
|
),
|
|
269
|
-
children: collapsed ? /* @__PURE__ */
|
|
209
|
+
children: collapsed ? /* @__PURE__ */ jsxs2("div", { className: "relative", ref: menuRef, children: [
|
|
270
210
|
/* @__PURE__ */ jsx4(
|
|
271
211
|
"button",
|
|
272
212
|
{
|
|
@@ -279,14 +219,14 @@ function UserCard({ collapsed, name, role, onLogout }) {
|
|
|
279
219
|
children: /* @__PURE__ */ jsx4(Avatar, { initial, size: "md", shape: "circle" })
|
|
280
220
|
}
|
|
281
221
|
),
|
|
282
|
-
menuOpen && /* @__PURE__ */ jsx4("div", { className: "absolute bottom-0 left-full ml-2 w-36 rounded-lg border border-
|
|
283
|
-
] }) : /* @__PURE__ */
|
|
222
|
+
menuOpen && /* @__PURE__ */ jsx4("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 })
|
|
223
|
+
] }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
284
224
|
/* @__PURE__ */ jsx4(Avatar, { initial, size: "md", shape: "circle" }),
|
|
285
|
-
/* @__PURE__ */
|
|
286
|
-
/* @__PURE__ */ jsx4("span", { className: "truncate text-body-sm font-semibold text-
|
|
287
|
-
/* @__PURE__ */ jsx4("span", { className: "truncate text-body-tiny font-regular text-
|
|
225
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex flex-1 min-w-0 flex-col gap-0.5", children: [
|
|
226
|
+
/* @__PURE__ */ jsx4("span", { className: "truncate text-body-sm font-semibold text-default leading-snug", children: name }),
|
|
227
|
+
/* @__PURE__ */ jsx4("span", { className: "truncate text-body-tiny font-regular text-default-secondary leading-none", children: role })
|
|
288
228
|
] }),
|
|
289
|
-
/* @__PURE__ */
|
|
229
|
+
/* @__PURE__ */ jsxs2("div", { className: "relative shrink-0", ref: menuRef, children: [
|
|
290
230
|
/* @__PURE__ */ jsx4(
|
|
291
231
|
"button",
|
|
292
232
|
{
|
|
@@ -295,23 +235,23 @@ function UserCard({ collapsed, name, role, onLogout }) {
|
|
|
295
235
|
"aria-haspopup": "menu",
|
|
296
236
|
"aria-expanded": menuOpen,
|
|
297
237
|
onClick: () => setMenuOpen((v) => !v),
|
|
298
|
-
className: "flex size-6 items-center justify-center rounded-md text-
|
|
299
|
-
children: /* @__PURE__ */ jsx4(
|
|
238
|
+
className: "flex size-6 items-center justify-center rounded-md text-default-secondary hover:bg-default-hover hover:text-default transition-colors",
|
|
239
|
+
children: /* @__PURE__ */ jsx4(LuEllipsisVertical, { className: "size-4", "aria-hidden": true })
|
|
300
240
|
}
|
|
301
241
|
),
|
|
302
|
-
menuOpen && /* @__PURE__ */ jsx4("div", { className: "absolute bottom-full right-0 mb-1 w-36 rounded-lg border border-
|
|
242
|
+
menuOpen && /* @__PURE__ */ jsx4("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 })
|
|
303
243
|
] })
|
|
304
244
|
] })
|
|
305
245
|
}
|
|
306
246
|
);
|
|
307
247
|
}
|
|
308
248
|
function AppSidebar({ collapsed, onToggle, isAdmin = false, userName, userRole, onLogout }) {
|
|
309
|
-
return /* @__PURE__ */
|
|
249
|
+
return /* @__PURE__ */ jsxs2(
|
|
310
250
|
"aside",
|
|
311
251
|
{
|
|
312
252
|
className: clsx4(
|
|
313
253
|
"relative flex flex-col shrink-0 transition-all duration-200",
|
|
314
|
-
"bg-
|
|
254
|
+
"bg-default-secondary border-r border-default rounded-xl",
|
|
315
255
|
"h-full",
|
|
316
256
|
collapsed ? "w-20" : "w-80"
|
|
317
257
|
),
|
|
@@ -324,44 +264,45 @@ function AppSidebar({ collapsed, onToggle, isAdmin = false, userName, userRole,
|
|
|
324
264
|
onClick: onToggle,
|
|
325
265
|
className: clsx4(
|
|
326
266
|
"absolute -right-3 top-5 z-10 flex size-6 items-center justify-center rounded-full",
|
|
327
|
-
"bg-
|
|
328
|
-
"hover:bg-
|
|
267
|
+
"bg-default border border-default text-default-secondary",
|
|
268
|
+
"hover:bg-default-hover shadow-sm transition-colors"
|
|
329
269
|
),
|
|
330
|
-
children: collapsed ? /* @__PURE__ */ jsx4(
|
|
270
|
+
children: collapsed ? /* @__PURE__ */ jsx4(LuChevronRight, { className: "size-3", strokeWidth: 2.5, "aria-hidden": true }) : /* @__PURE__ */ jsx4(LuChevronLeft, { className: "size-3", strokeWidth: 2.5, "aria-hidden": true })
|
|
331
271
|
}
|
|
332
272
|
),
|
|
333
|
-
/* @__PURE__ */
|
|
273
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex flex-1 min-h-0 flex-col gap-1", children: [
|
|
334
274
|
/* @__PURE__ */ jsx4(SidebarLogo, { collapsed }),
|
|
335
|
-
/* @__PURE__ */
|
|
336
|
-
/* @__PURE__ */ jsx4(NavLinkItem, { to: "/dashboard", icon: /* @__PURE__ */ jsx4(
|
|
337
|
-
/* @__PURE__ */ jsx4(NavLinkItem, { to: "/entities", icon: /* @__PURE__ */ jsx4(
|
|
338
|
-
/* @__PURE__ */ jsx4(NavLinkItem, { to: "/suppliers", icon: /* @__PURE__ */ jsx4(
|
|
339
|
-
/* @__PURE__ */ jsx4(NavLinkItem, { to: "/customers", icon: /* @__PURE__ */ jsx4(
|
|
340
|
-
/* @__PURE__ */ jsx4(NavLinkItem, { to: "/sources", icon: /* @__PURE__ */ jsx4(
|
|
341
|
-
/* @__PURE__ */ jsx4(NavLinkItem, { to: "/articles", icon: /* @__PURE__ */ jsx4(
|
|
342
|
-
/* @__PURE__ */ jsx4(NavLinkItem, { to: "/alerts", icon: /* @__PURE__ */ jsx4(
|
|
343
|
-
/* @__PURE__ */ jsx4(NavLinkItem, { to: "/website-scraper", icon: /* @__PURE__ */ jsx4(
|
|
344
|
-
/* @__PURE__ */ jsx4(NavLinkItem, { to: "/review", icon: /* @__PURE__ */ jsx4(
|
|
345
|
-
isAdmin && /* @__PURE__ */ jsx4(NavLinkItem, { to: "/queues", icon: /* @__PURE__ */ jsx4(
|
|
275
|
+
/* @__PURE__ */ jsxs2("nav", { className: "flex flex-col gap-3 overflow-y-auto px-4 pt-2 pb-3", children: [
|
|
276
|
+
/* @__PURE__ */ jsx4(NavLinkItem, { to: "/dashboard", icon: /* @__PURE__ */ jsx4(LuLayoutGrid, { className: NAV_ICON, "aria-hidden": true }), label: "Dashboard", collapsed, end: true }),
|
|
277
|
+
/* @__PURE__ */ jsx4(NavLinkItem, { to: "/entities", icon: /* @__PURE__ */ jsx4(LuLayers, { className: NAV_ICON, "aria-hidden": true }), label: "Entities", collapsed, indicator: true }),
|
|
278
|
+
/* @__PURE__ */ jsx4(NavLinkItem, { to: "/suppliers", icon: /* @__PURE__ */ jsx4(LuBuilding, { className: NAV_ICON, "aria-hidden": true }), label: "Suppliers", collapsed }),
|
|
279
|
+
/* @__PURE__ */ jsx4(NavLinkItem, { to: "/customers", icon: /* @__PURE__ */ jsx4(LuUsers, { className: NAV_ICON, "aria-hidden": true }), label: "Customers", collapsed }),
|
|
280
|
+
/* @__PURE__ */ jsx4(NavLinkItem, { to: "/sources", icon: /* @__PURE__ */ jsx4(LuFileText, { className: NAV_ICON, "aria-hidden": true }), label: "Sources", collapsed }),
|
|
281
|
+
/* @__PURE__ */ jsx4(NavLinkItem, { to: "/articles", icon: /* @__PURE__ */ jsx4(LuRss, { className: NAV_ICON, "aria-hidden": true }), label: "Intelligence", collapsed }),
|
|
282
|
+
/* @__PURE__ */ jsx4(NavLinkItem, { to: "/alerts", icon: /* @__PURE__ */ jsx4(LuBell, { className: NAV_ICON, "aria-hidden": true }), label: "Alerts", collapsed }),
|
|
283
|
+
/* @__PURE__ */ jsx4(NavLinkItem, { to: "/website-scraper", icon: /* @__PURE__ */ jsx4(LuGlobe, { className: NAV_ICON, "aria-hidden": true }), label: "Website Intel", collapsed }),
|
|
284
|
+
/* @__PURE__ */ jsx4(NavLinkItem, { to: "/review", icon: /* @__PURE__ */ jsx4(LuClipboardList, { className: NAV_ICON, "aria-hidden": true }), label: "Review queue", collapsed }),
|
|
285
|
+
isAdmin && /* @__PURE__ */ jsx4(NavLinkItem, { to: "/queues", icon: /* @__PURE__ */ jsx4(LuServer, { className: NAV_ICON, "aria-hidden": true }), label: "Queues", collapsed })
|
|
346
286
|
] })
|
|
347
287
|
] }),
|
|
348
|
-
/* @__PURE__ */
|
|
288
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex flex-col", children: [
|
|
349
289
|
isAdmin && /* @__PURE__ */ jsx4("div", { className: "px-4 pb-2", children: /* @__PURE__ */ jsx4(
|
|
350
290
|
NavLinkItem,
|
|
351
291
|
{
|
|
352
292
|
to: "/settings",
|
|
353
|
-
icon: /* @__PURE__ */ jsx4(
|
|
293
|
+
icon: /* @__PURE__ */ jsx4(LuSettings, { className: NAV_ICON, "aria-hidden": true }),
|
|
354
294
|
label: "Settings",
|
|
355
295
|
collapsed
|
|
356
296
|
}
|
|
357
297
|
) }),
|
|
358
|
-
/* @__PURE__ */ jsx4("div", { className: "border-t border-
|
|
298
|
+
/* @__PURE__ */ jsx4("div", { className: "border-t border-default", children: /* @__PURE__ */ jsx4(UserCard, { collapsed, name: userName, role: userRole, onLogout }) })
|
|
359
299
|
] })
|
|
360
300
|
]
|
|
361
301
|
}
|
|
362
302
|
);
|
|
363
303
|
}
|
|
364
304
|
export {
|
|
365
|
-
AppSidebar
|
|
305
|
+
AppSidebar,
|
|
306
|
+
NavTabs
|
|
366
307
|
};
|
|
367
308
|
//# sourceMappingURL=sidebar.js.map
|
package/dist/sidebar.js.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,SAAyB,WAAW,QAAQ,gBAAgB;AAC5D,SAAS,eAAe;AACxB,OAAOA,WAAU;;;ACFhB,OAAOC,WAAU;;;ACAlB,OAAO,UAAU;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,OAAO;AAAA,IACX;AAAA,IACA,WAAW,IAAI;AAAA,IACf,YAAY,KAAK;AAAA,IACjB;AAAA,EACF;AAEA,MAAI,MAAM,SAAS,SAAS;AAC1B,WACE,oBAAC,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,WAAW,KAAK,MAAM,kCAAkC;AAAA,MACxD,OAAO;AAAA,QACL,YACE;AAAA,MACJ;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,WAAW;AAAA,YACT;AAAA,YACA,kBAAkB,IAAI;AAAA,UACxB;AAAA,UAEC,gBAAM,QAAQ,OAAO,CAAC,EAAE,YAAY;AAAA;AAAA,MACvC;AAAA;AAAA,EACF;AAEJ;;;ACpFA,OAAOC,WAAU;AAsBb,SAcI,OAAAC,MAdJ;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,WAAWD;AAAA,QACT;AAAA,QACA,aAAa;AAAA,QACb,WACI,iDACA;AAAA,UACE;AAAA,UACA;AAAA,QACF;AAAA,QACJ;AAAA,MACF;AAAA,MAEC;AAAA,iBAAS,UACR,gBAAAC,KAAC,UAAK,WAAU,2BAA2B,gBAAK;AAAA,QAEjD,CAAC,aACA,gBAAAA,KAAC,UAAK,WAAU,kEACb,iBACH;AAAA,QAED,aACC,gBAAAA,KAAC,UAAK,WAAU,uEAAsE;AAAA;AAAA;AAAA,EAE1F;AAEJ;;;AFaI,gBAAAC,MAuBA,QAAAC,aAvBA;;;ADpDA,SA+PI,UA9PF,OAAAC,MADF,QAAAC,aAAA;AAFJ,SAAS,WAAW;AAClB,SACE,gBAAAA,MAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACxJ;AAAA,oBAAAD,KAAC,UAAK,GAAE,KAAI,GAAE,KAAI,OAAM,KAAI,QAAO,KAAI,IAAG,KAAI;AAAA,IAC9C,gBAAAA,KAAC,UAAK,GAAE,MAAK,GAAE,KAAI,OAAM,KAAI,QAAO,KAAI,IAAG,KAAI;AAAA,IAC/C,gBAAAA,KAAC,UAAK,GAAE,MAAK,GAAE,MAAK,OAAM,KAAI,QAAO,KAAI,IAAG,KAAI;AAAA,IAChD,gBAAAA,KAAC,UAAK,GAAE,KAAI,GAAE,MAAK,OAAM,KAAI,QAAO,KAAI,IAAG,KAAI;AAAA,KACjD;AAEJ;AAEA,SAAS,aAAa;AACpB,SACE,gBAAAC,MAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACxJ;AAAA,oBAAAD,KAAC,aAAQ,QAAO,4BAA2B;AAAA,IAC3C,gBAAAA,KAAC,cAAS,QAAO,oBAAmB;AAAA,IACpC,gBAAAA,KAAC,cAAS,QAAO,oBAAmB;AAAA,KACtC;AAEJ;AAEA,SAAS,eAAe;AACtB,SACE,gBAAAC,MAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACxJ;AAAA,oBAAAD,KAAC,UAAK,GAAE,KAAI,GAAE,KAAI,OAAM,MAAK,QAAO,MAAK,IAAG,KAAI;AAAA,IAChD,gBAAAA,KAAC,UAAK,GAAE,8CAA6C;AAAA,KACvD;AAEJ;AAEA,SAAS,YAAY;AACnB,SACE,gBAAAC,MAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACxJ;AAAA,oBAAAD,KAAC,UAAK,GAAE,6CAA4C;AAAA,IACpD,gBAAAA,KAAC,YAAO,IAAG,KAAI,IAAG,KAAI,GAAE,KAAI;AAAA,IAC5B,gBAAAA,KAAC,UAAK,GAAE,8BAA6B;AAAA,IACrC,gBAAAA,KAAC,UAAK,GAAE,6BAA4B;AAAA,KACtC;AAEJ;AAEA,SAAS,UAAU;AACjB,SACE,gBAAAC,MAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACxJ;AAAA,oBAAAD,KAAC,UAAK,GAAE,uBAAsB;AAAA,IAC9B,gBAAAA,KAAC,UAAK,GAAE,0BAAyB;AAAA,IACjC,gBAAAA,KAAC,YAAO,IAAG,KAAI,IAAG,MAAK,GAAE,KAAI,MAAK,gBAAe;AAAA,KACnD;AAEJ;AAEA,SAAS,eAAe;AACtB,SACE,gBAAAC,MAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACxJ;AAAA,oBAAAD,KAAC,UAAK,GAAE,8DAA6D;AAAA,IACrE,gBAAAA,KAAC,cAAS,QAAO,kBAAiB;AAAA,IAClC,gBAAAA,KAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,KAAI,IAAG,MAAK;AAAA,IACrC,gBAAAA,KAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,KAAI,IAAG,MAAK;AAAA,KACvC;AAEJ;AAEA,SAAS,WAAW;AAClB,SACE,gBAAAC,MAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACxJ;AAAA,oBAAAD,KAAC,UAAK,GAAE,+CAA8C;AAAA,IACtD,gBAAAA,KAAC,UAAK,GAAE,8BAA6B;AAAA,KACvC;AAEJ;AAEA,SAAS,aAAa;AACpB,SACE,gBAAAC,MAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACxJ;AAAA,oBAAAD,KAAC,UAAK,GAAE,KAAI,GAAE,KAAI,OAAM,MAAK,QAAO,KAAI,IAAG,KAAI;AAAA,IAC/C,gBAAAA,KAAC,UAAK,GAAE,KAAI,GAAE,MAAK,OAAM,MAAK,QAAO,KAAI,IAAG,KAAI;AAAA,IAChD,gBAAAA,KAAC,UAAK,IAAG,KAAI,IAAG,KAAI,IAAG,QAAO,IAAG,KAAI;AAAA,IACrC,gBAAAA,KAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,QAAO,IAAG,MAAK;AAAA,KACzC;AAEJ;AAEA,SAAS,eAAe;AACtB,SACE,gBAAAC,MAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACxJ;AAAA,oBAAAD,KAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,IAC9B,gBAAAA,KAAC,UAAK,GAAE,0mBAAymB;AAAA,KACnnB;AAEJ;AAEA,SAAS,oBAAoB;AAC3B,SACE,gBAAAC,MAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACxJ;AAAA,oBAAAD,KAAC,UAAK,GAAE,6EAA4E;AAAA,IACpF,gBAAAA,KAAC,UAAK,GAAE,KAAI,GAAE,KAAI,OAAM,KAAI,QAAO,KAAI,IAAG,KAAI;AAAA,IAC9C,gBAAAA,KAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA,IACrC,gBAAAA,KAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA,KACvC;AAEJ;AAEA,SAAS,YAAY;AACnB,SACE,gBAAAC,MAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACxJ;AAAA,oBAAAD,KAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK;AAAA,IAC/B,gBAAAA,KAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA,IACrC,gBAAAA,KAAC,UAAK,GAAE,8FAA6F;AAAA,KACvG;AAEJ;AAEA,SAAS,kBAAkB;AACzB,SACE,gBAAAA,KAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAAM,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MAC1J,0BAAAA,KAAC,cAAS,QAAO,mBAAkB,GACrC;AAEJ;AAEA,SAAS,mBAAmB;AAC1B,SACE,gBAAAA,KAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,OAAM,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MAC1J,0BAAAA,KAAC,cAAS,QAAO,kBAAiB,GACpC;AAEJ;AAEA,SAAS,mBAAmB;AAC1B,SACE,gBAAAC,MAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACxJ;AAAA,oBAAAD,KAAC,YAAO,IAAG,MAAK,IAAG,KAAI,GAAE,KAAI,MAAK,gBAAe;AAAA,IACjD,gBAAAA,KAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI,MAAK,gBAAe;AAAA,IAClD,gBAAAA,KAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI,MAAK,gBAAe;AAAA,KACpD;AAEJ;AAEA,SAAS,aAAa;AACpB,SACE,gBAAAC,MAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACxJ;AAAA,oBAAAD,KAAC,UAAK,GAAE,2CAA0C;AAAA,IAClD,gBAAAA,KAAC,cAAS,QAAO,oBAAmB;AAAA,IACpC,gBAAAA,KAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,KAAI,IAAG,MAAK;AAAA,KACvC;AAEJ;AAIA,SAAS,YAAY,EAAE,UAAU,GAA2B;AAC1D,SACE,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACC,WAAWC;AAAA,QACT;AAAA,QACA,YAAY,mBAAmB;AAAA,MACjC;AAAA,MAEA;AAAA,wBAAAF,KAAC,SAAI,WAAU,0GACb,0BAAAC,MAAC,SAAI,WAAU,8BACb;AAAA,0BAAAD,KAAC,SAAI,WAAU,iCAAgC;AAAA,UAC/C,gBAAAA,KAAC,SAAI,WAAU,oCAAmC;AAAA,UAClD,gBAAAA,KAAC,SAAI,WAAU,oCAAmC;AAAA,UAClD,gBAAAA,KAAC,SAAI,WAAU,iCAAgC;AAAA,WACjD,GACF;AAAA,QACC,CAAC,aACA,gBAAAA,KAAC,UAAK,WAAU,iFAAgF,kBAEhG;AAAA;AAAA;AAAA,EAEJ;AAEJ;AAaA,SAAS,YAAY,EAAE,IAAI,MAAM,OAAO,WAAW,WAAW,IAAI,GAAqB;AACrF,SACE,gBAAAA,KAAC,WAAQ,IAAQ,KAAU,WAAU,6BAClC,WAAC,EAAE,SAAS,MACX,gBAAAA;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,IAAI,SAAS,KAAK;AAC9C,QAAM,UAAU,OAAuB,IAAI;AAC3C,QAAM,UAAU,KAAK,KAAK,EAAE,OAAO,CAAC;AAEpC,YAAU,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,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,SAAS,MAAM;AAAE,oBAAY,KAAK;AAAG,iBAAS;AAAA,MAAG;AAAA,MACjD,WAAU;AAAA,MAEV;AAAA,wBAAAD,KAAC,cAAW;AAAA,QAAE;AAAA;AAAA;AAAA,EAEhB;AAGF,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAWE;AAAA,QACT;AAAA,QACA,YAAY,mBAAmB;AAAA,MACjC;AAAA,MAEC,sBACC,gBAAAD,MAAC,SAAI,WAAU,YAAW,KAAK,SAC7B;AAAA,wBAAAD;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,0BAAAA,KAAC,UAAO,SAAkB,MAAK,MAAK,OAAM,UAAS;AAAA;AAAA,QACrD;AAAA,QACC,YACC,gBAAAA,KAAC,SAAI,WAAU,2HACZ,qBACH;AAAA,SAEJ,IAEA,gBAAAC,MAAA,YACE;AAAA,wBAAAD,KAAC,UAAO,SAAkB,MAAK,MAAK,OAAM,UAAS;AAAA,QACnD,gBAAAC,MAAC,SAAI,WAAU,wCACb;AAAA,0BAAAD,KAAC,UAAK,WAAU,sEACb,gBACH;AAAA,UACA,gBAAAA,KAAC,UAAK,WAAU,iFACb,gBACH;AAAA,WACF;AAAA,QACA,gBAAAC,MAAC,SAAI,WAAU,qBAAoB,KAAK,SACtC;AAAA,0BAAAD;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,0BAAAA,KAAC,oBAAiB;AAAA;AAAA,UACpB;AAAA,UACC,YACC,gBAAAA,KAAC,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,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACC,WAAWC;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACA,YAAY,SAAS;AAAA,MACvB;AAAA,MAGA;AAAA,wBAAAF;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,cAAY,YAAY,mBAAmB;AAAA,YAC3C,SAAS;AAAA,YACT,WAAWE;AAAA,cACT;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAAA,YAEC,sBAAY,gBAAAF,KAAC,oBAAiB,IAAK,gBAAAA,KAAC,mBAAgB;AAAA;AAAA,QACvD;AAAA,QAGA,gBAAAC,MAAC,SAAI,WAAU,sCACb;AAAA,0BAAAD,KAAC,eAAY,WAAsB;AAAA,UAEnC,gBAAAC,MAAC,SAAI,WAAU,sDACb;AAAA,4BAAAD,KAAC,eAAY,IAAG,cAAa,MAAM,gBAAAA,KAAC,YAAS,GAAI,OAAM,aAAY,WAAsB,KAAG,MAAC;AAAA,YAC7F,gBAAAA,KAAC,eAAY,IAAG,aAAY,MAAM,gBAAAA,KAAC,cAAW,GAAI,OAAM,YAAW,WAAsB,WAAS,MAAC;AAAA,YACnG,gBAAAA,KAAC,eAAY,IAAG,cAAa,MAAM,gBAAAA,KAAC,gBAAa,GAAI,OAAM,aAAY,WAAsB;AAAA,YAC7F,gBAAAA,KAAC,eAAY,IAAG,cAAa,MAAM,gBAAAA,KAAC,aAAU,GAAI,OAAM,aAAY,WAAsB;AAAA,YAC1F,gBAAAA,KAAC,eAAY,IAAG,YAAW,MAAM,gBAAAA,KAAC,gBAAa,GAAI,OAAM,WAAU,WAAsB;AAAA,YACzF,gBAAAA,KAAC,eAAY,IAAG,aAAY,MAAM,gBAAAA,KAAC,WAAQ,GAAI,OAAM,gBAAe,WAAsB;AAAA,YAC1F,gBAAAA,KAAC,eAAY,IAAG,WAAU,MAAM,gBAAAA,KAAC,YAAS,GAAI,OAAM,UAAS,WAAsB;AAAA,YACnF,gBAAAA,KAAC,eAAY,IAAG,oBAAmB,MAAM,gBAAAA,KAAC,aAAU,GAAI,OAAM,iBAAgB,WAAsB;AAAA,YACpG,gBAAAA,KAAC,eAAY,IAAG,WAAU,MAAM,gBAAAA,KAAC,qBAAkB,GAAI,OAAM,gBAAe,WAAsB;AAAA,YACjG,WACC,gBAAAA,KAAC,eAAY,IAAG,WAAU,MAAM,gBAAAA,KAAC,cAAW,GAAI,OAAM,UAAS,WAAsB;AAAA,aAEzF;AAAA,WACF;AAAA,QAGA,gBAAAC,MAAC,SAAI,WAAU,iBACZ;AAAA,qBACC,gBAAAD,KAAC,SAAI,WAAU,aACb,0BAAAA;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACH,MAAM,gBAAAA,KAAC,gBAAa;AAAA,cACpB,OAAM;AAAA,cACN;AAAA;AAAA,UACF,GACF;AAAA,UAEF,gBAAAA,KAAC,SAAI,WAAU,kCACb,0BAAAA,KAAC,YAAS,WAAsB,MAAM,UAAU,MAAM,UAAU,UAAoB,GACtF;AAAA,WACF;AAAA;AAAA;AAAA,EACF;AAEJ;","names":["clsx","clsx","clsx","jsx","jsx","jsxs","jsx","jsxs","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":["NavLink","clsx","clsx","jsx","clsx","jsx","jsx","jsxs","clsx","NavLink"]}
|