@greatapps/greatauth-ui 0.3.12 → 0.3.13
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/index.js +169 -77
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/app-header.tsx +46 -12
- package/src/components/login-form.tsx +131 -81
- package/src/components/users/users-page.tsx +1 -1
- package/src/theme.css +18 -12
package/dist/index.js
CHANGED
|
@@ -1062,8 +1062,9 @@ function AppSidebar({ config }) {
|
|
|
1062
1062
|
}
|
|
1063
1063
|
|
|
1064
1064
|
// src/components/app-header.tsx
|
|
1065
|
-
import { Fragment } from "react";
|
|
1065
|
+
import { Fragment, useMemo as useMemo2 } from "react";
|
|
1066
1066
|
import { usePathname as usePathname2 } from "next/navigation";
|
|
1067
|
+
import Link2 from "next/link";
|
|
1067
1068
|
|
|
1068
1069
|
// src/components/ui/breadcrumb.tsx
|
|
1069
1070
|
import { Slot as Slot4 } from "radix-ui";
|
|
@@ -1103,6 +1104,21 @@ function BreadcrumbItem({ className, ...props }) {
|
|
|
1103
1104
|
}
|
|
1104
1105
|
);
|
|
1105
1106
|
}
|
|
1107
|
+
function BreadcrumbLink({
|
|
1108
|
+
asChild,
|
|
1109
|
+
className,
|
|
1110
|
+
...props
|
|
1111
|
+
}) {
|
|
1112
|
+
const Comp = asChild ? Slot4.Root : "a";
|
|
1113
|
+
return /* @__PURE__ */ jsx13(
|
|
1114
|
+
Comp,
|
|
1115
|
+
{
|
|
1116
|
+
"data-slot": "breadcrumb-link",
|
|
1117
|
+
className: cn("hover:text-foreground transition-colors", className),
|
|
1118
|
+
...props
|
|
1119
|
+
}
|
|
1120
|
+
);
|
|
1121
|
+
}
|
|
1106
1122
|
function BreadcrumbPage({ className, ...props }) {
|
|
1107
1123
|
return /* @__PURE__ */ jsx13(
|
|
1108
1124
|
"span",
|
|
@@ -1133,6 +1149,28 @@ function BreadcrumbSeparator({
|
|
|
1133
1149
|
}
|
|
1134
1150
|
);
|
|
1135
1151
|
}
|
|
1152
|
+
function BreadcrumbEllipsis({
|
|
1153
|
+
className,
|
|
1154
|
+
...props
|
|
1155
|
+
}) {
|
|
1156
|
+
return /* @__PURE__ */ jsxs6(
|
|
1157
|
+
"span",
|
|
1158
|
+
{
|
|
1159
|
+
"data-slot": "breadcrumb-ellipsis",
|
|
1160
|
+
role: "presentation",
|
|
1161
|
+
"aria-hidden": "true",
|
|
1162
|
+
className: cn(
|
|
1163
|
+
"size-5 [&>svg]:size-4 flex items-center justify-center",
|
|
1164
|
+
className
|
|
1165
|
+
),
|
|
1166
|
+
...props,
|
|
1167
|
+
children: [
|
|
1168
|
+
/* @__PURE__ */ jsx13(MoreHorizontal, {}),
|
|
1169
|
+
/* @__PURE__ */ jsx13("span", { className: "sr-only", children: "More" })
|
|
1170
|
+
]
|
|
1171
|
+
}
|
|
1172
|
+
);
|
|
1173
|
+
}
|
|
1136
1174
|
|
|
1137
1175
|
// src/components/theme-toggle.tsx
|
|
1138
1176
|
import { useTheme } from "next-themes";
|
|
@@ -1170,14 +1208,30 @@ import { jsx as jsx15, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
|
1170
1208
|
function AppHeader({ config }) {
|
|
1171
1209
|
const pathname = usePathname2();
|
|
1172
1210
|
const segments = pathname.split("/").filter(Boolean);
|
|
1173
|
-
const breadcrumbs =
|
|
1211
|
+
const breadcrumbs = useMemo2(() => {
|
|
1212
|
+
const items = [];
|
|
1213
|
+
for (let i = 0; i < segments.length; i++) {
|
|
1214
|
+
const label = config.routeLabels[segments[i]];
|
|
1215
|
+
if (label) {
|
|
1216
|
+
const href = "/" + segments.slice(0, i + 1).join("/");
|
|
1217
|
+
items.push({ label, href });
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
return items;
|
|
1221
|
+
}, [segments, config.routeLabels]);
|
|
1222
|
+
const isLast = (i) => i === breadcrumbs.length - 1;
|
|
1223
|
+
const showEllipsis = breadcrumbs.length > 2;
|
|
1174
1224
|
return /* @__PURE__ */ jsxs8("header", { className: "flex h-14 shrink-0 items-center gap-2 border-b px-4", children: [
|
|
1175
1225
|
/* @__PURE__ */ jsx15(SidebarTrigger, { className: "-ml-1" }),
|
|
1176
1226
|
/* @__PURE__ */ jsx15(Separator, { orientation: "vertical", className: "mr-2 !h-4" }),
|
|
1177
|
-
/* @__PURE__ */ jsx15(Breadcrumb, { className: "flex-1", children: /* @__PURE__ */ jsx15(BreadcrumbList, { children: breadcrumbs.length > 0 ? breadcrumbs.map((
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1227
|
+
/* @__PURE__ */ jsx15(Breadcrumb, { className: "flex-1", children: /* @__PURE__ */ jsx15(BreadcrumbList, { children: breadcrumbs.length > 0 ? breadcrumbs.map((crumb, i) => {
|
|
1228
|
+
const hiddenOnMobile = showEllipsis && i < breadcrumbs.length - 2;
|
|
1229
|
+
return /* @__PURE__ */ jsxs8(Fragment, { children: [
|
|
1230
|
+
showEllipsis && i === breadcrumbs.length - 2 && /* @__PURE__ */ jsx15(BreadcrumbItem, { className: "sm:hidden", children: /* @__PURE__ */ jsx15(BreadcrumbEllipsis, {}) }),
|
|
1231
|
+
i > 0 && /* @__PURE__ */ jsx15(BreadcrumbSeparator, { className: hiddenOnMobile ? "hidden sm:flex" : void 0 }),
|
|
1232
|
+
/* @__PURE__ */ jsx15(BreadcrumbItem, { className: hiddenOnMobile ? "hidden sm:flex" : void 0, children: isLast(i) ? /* @__PURE__ */ jsx15(BreadcrumbPage, { children: crumb.label }) : /* @__PURE__ */ jsx15(BreadcrumbLink, { asChild: true, children: /* @__PURE__ */ jsx15(Link2, { href: crumb.href, children: crumb.label }) }) })
|
|
1233
|
+
] }, i);
|
|
1234
|
+
}) : config.defaultBreadcrumb ? /* @__PURE__ */ jsx15(BreadcrumbItem, { children: /* @__PURE__ */ jsx15(BreadcrumbPage, { children: config.defaultBreadcrumb }) }) : null }) }),
|
|
1181
1235
|
/* @__PURE__ */ jsx15(ThemeToggle, {})
|
|
1182
1236
|
] });
|
|
1183
1237
|
}
|
|
@@ -1200,7 +1254,7 @@ function AppShell({ config, children, renderAbove }) {
|
|
|
1200
1254
|
// src/components/login-form.tsx
|
|
1201
1255
|
import { useState as useState3 } from "react";
|
|
1202
1256
|
import { useRouter as useRouter2, useSearchParams } from "next/navigation";
|
|
1203
|
-
import { Loader2, Mail, Lock, AlertCircle } from "lucide-react";
|
|
1257
|
+
import { Loader2, Mail, Lock, AlertCircle, Eye, EyeOff } from "lucide-react";
|
|
1204
1258
|
|
|
1205
1259
|
// src/components/ui/label.tsx
|
|
1206
1260
|
import { Label as LabelPrimitive } from "radix-ui";
|
|
@@ -1232,6 +1286,7 @@ function LoginForm({ config }) {
|
|
|
1232
1286
|
const [password, setPassword] = useState3("");
|
|
1233
1287
|
const [loading, setLoading] = useState3(false);
|
|
1234
1288
|
const [error, setError] = useState3("");
|
|
1289
|
+
const [showPassword, setShowPassword] = useState3(false);
|
|
1235
1290
|
const handleSubmit = async (e) => {
|
|
1236
1291
|
e.preventDefault();
|
|
1237
1292
|
if (loading) return;
|
|
@@ -1262,73 +1317,110 @@ function LoginForm({ config }) {
|
|
|
1262
1317
|
setLoading(false);
|
|
1263
1318
|
}
|
|
1264
1319
|
};
|
|
1265
|
-
return /* @__PURE__ */
|
|
1266
|
-
/* @__PURE__ */
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
required: true
|
|
1294
|
-
}
|
|
1295
|
-
)
|
|
1296
|
-
] })
|
|
1297
|
-
] }),
|
|
1298
|
-
/* @__PURE__ */ jsxs10("div", { className: "space-y-1.5", children: [
|
|
1299
|
-
/* @__PURE__ */ jsx18(Label, { htmlFor: "login-password", className: "text-sm font-medium", children: "Senha" }),
|
|
1300
|
-
/* @__PURE__ */ jsxs10("div", { className: "relative", children: [
|
|
1301
|
-
/* @__PURE__ */ jsx18(Lock, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }),
|
|
1302
|
-
/* @__PURE__ */ jsx18(
|
|
1303
|
-
Input,
|
|
1304
|
-
{
|
|
1305
|
-
id: "login-password",
|
|
1306
|
-
type: "password",
|
|
1307
|
-
placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
|
|
1308
|
-
value: password,
|
|
1309
|
-
onChange: (e) => setPassword(e.target.value),
|
|
1310
|
-
className: "pl-9",
|
|
1311
|
-
autoComplete: "current-password",
|
|
1312
|
-
required: true
|
|
1313
|
-
}
|
|
1314
|
-
)
|
|
1315
|
-
] })
|
|
1320
|
+
return /* @__PURE__ */ jsxs10("div", { className: "relative flex min-h-svh", children: [
|
|
1321
|
+
/* @__PURE__ */ jsx18("div", { className: "fixed top-4 right-4 z-50", children: /* @__PURE__ */ jsx18(ThemeToggle, {}) }),
|
|
1322
|
+
/* @__PURE__ */ jsxs10(
|
|
1323
|
+
"div",
|
|
1324
|
+
{
|
|
1325
|
+
className: "relative hidden items-center justify-center overflow-hidden bg-primary md:flex md:w-1/2",
|
|
1326
|
+
style: {
|
|
1327
|
+
backgroundImage: "radial-gradient(circle, rgba(255,255,255,0.1) 1px, transparent 1px)",
|
|
1328
|
+
backgroundSize: "24px 24px"
|
|
1329
|
+
},
|
|
1330
|
+
children: [
|
|
1331
|
+
/* @__PURE__ */ jsx18("div", { className: "absolute inset-0 bg-gradient-to-br from-primary/80 via-primary to-primary/90" }),
|
|
1332
|
+
/* @__PURE__ */ jsxs10("div", { className: "relative z-10 flex flex-col items-center gap-4 px-8 text-center text-primary-foreground", children: [
|
|
1333
|
+
/* @__PURE__ */ jsx18("div", { className: "flex h-16 w-16 items-center justify-center rounded-2xl bg-primary-foreground/15 shadow-lg backdrop-blur-sm", children: config.icon }),
|
|
1334
|
+
/* @__PURE__ */ jsx18("h2", { className: "text-3xl font-bold tracking-tight", children: config.appName }),
|
|
1335
|
+
/* @__PURE__ */ jsx18("p", { className: "max-w-xs text-base text-primary-foreground/80", children: config.description })
|
|
1336
|
+
] })
|
|
1337
|
+
]
|
|
1338
|
+
}
|
|
1339
|
+
),
|
|
1340
|
+
/* @__PURE__ */ jsx18("div", { className: "flex w-full items-center justify-center bg-background p-4 md:w-1/2", children: /* @__PURE__ */ jsxs10("div", { className: "w-full max-w-sm", children: [
|
|
1341
|
+
/* @__PURE__ */ jsxs10("div", { className: "mb-8 text-center", children: [
|
|
1342
|
+
/* @__PURE__ */ jsx18("div", { className: "mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-xl bg-primary text-primary-foreground shadow-sm md:hidden", children: config.icon }),
|
|
1343
|
+
/* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-center gap-2", children: [
|
|
1344
|
+
/* @__PURE__ */ jsx18("h1", { className: "text-3xl font-bold tracking-tight", children: config.appName }),
|
|
1345
|
+
config.appBadge && /* @__PURE__ */ jsx18(Badge, { variant: config.appBadge.variant, className: "text-xs", children: config.appBadge.text })
|
|
1346
|
+
] }),
|
|
1347
|
+
/* @__PURE__ */ jsx18("p", { className: "mt-1.5 text-base text-muted-foreground", children: config.description })
|
|
1316
1348
|
] }),
|
|
1317
|
-
/* @__PURE__ */ jsx18(
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
"
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1349
|
+
/* @__PURE__ */ jsx18("div", { className: "rounded-xl border bg-card p-6 shadow-sm", children: /* @__PURE__ */ jsxs10("form", { onSubmit: handleSubmit, className: "space-y-4", children: [
|
|
1350
|
+
error && /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2 rounded-lg border border-destructive/30 bg-destructive/5 px-3 py-2.5 text-sm text-destructive", children: [
|
|
1351
|
+
/* @__PURE__ */ jsx18(AlertCircle, { className: "h-4 w-4 shrink-0" }),
|
|
1352
|
+
error
|
|
1353
|
+
] }),
|
|
1354
|
+
/* @__PURE__ */ jsxs10("div", { className: "space-y-1.5", children: [
|
|
1355
|
+
/* @__PURE__ */ jsx18(Label, { htmlFor: "login-email", className: "text-sm font-medium", children: "Email" }),
|
|
1356
|
+
/* @__PURE__ */ jsxs10("div", { className: "relative", children: [
|
|
1357
|
+
/* @__PURE__ */ jsx18(Mail, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }),
|
|
1358
|
+
/* @__PURE__ */ jsx18(
|
|
1359
|
+
Input,
|
|
1360
|
+
{
|
|
1361
|
+
id: "login-email",
|
|
1362
|
+
type: "email",
|
|
1363
|
+
placeholder: "email@exemplo.com",
|
|
1364
|
+
value: email,
|
|
1365
|
+
onChange: (e) => setEmail(e.target.value),
|
|
1366
|
+
className: "pl-9",
|
|
1367
|
+
autoComplete: "email",
|
|
1368
|
+
required: true
|
|
1369
|
+
}
|
|
1370
|
+
)
|
|
1371
|
+
] })
|
|
1372
|
+
] }),
|
|
1373
|
+
/* @__PURE__ */ jsxs10("div", { className: "space-y-1.5", children: [
|
|
1374
|
+
/* @__PURE__ */ jsx18(Label, { htmlFor: "login-password", className: "text-sm font-medium", children: "Senha" }),
|
|
1375
|
+
/* @__PURE__ */ jsxs10("div", { className: "relative", children: [
|
|
1376
|
+
/* @__PURE__ */ jsx18(Lock, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }),
|
|
1377
|
+
/* @__PURE__ */ jsx18(
|
|
1378
|
+
Input,
|
|
1379
|
+
{
|
|
1380
|
+
id: "login-password",
|
|
1381
|
+
type: showPassword ? "text" : "password",
|
|
1382
|
+
placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
|
|
1383
|
+
value: password,
|
|
1384
|
+
onChange: (e) => setPassword(e.target.value),
|
|
1385
|
+
className: "pl-9 pr-10",
|
|
1386
|
+
autoComplete: "current-password",
|
|
1387
|
+
required: true
|
|
1388
|
+
}
|
|
1389
|
+
),
|
|
1390
|
+
/* @__PURE__ */ jsx18(
|
|
1391
|
+
"button",
|
|
1392
|
+
{
|
|
1393
|
+
type: "button",
|
|
1394
|
+
onClick: () => setShowPassword(!showPassword),
|
|
1395
|
+
className: "absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground transition-colors",
|
|
1396
|
+
"aria-label": showPassword ? "Ocultar senha" : "Mostrar senha",
|
|
1397
|
+
children: showPassword ? /* @__PURE__ */ jsx18(EyeOff, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx18(Eye, { className: "h-4 w-4" })
|
|
1398
|
+
}
|
|
1399
|
+
)
|
|
1400
|
+
] })
|
|
1401
|
+
] }),
|
|
1402
|
+
/* @__PURE__ */ jsx18(
|
|
1403
|
+
Button,
|
|
1404
|
+
{
|
|
1405
|
+
type: "submit",
|
|
1406
|
+
className: cn("w-full", loading && "cursor-wait"),
|
|
1407
|
+
disabled: loading,
|
|
1408
|
+
children: loading ? /* @__PURE__ */ jsxs10(Fragment3, { children: [
|
|
1409
|
+
/* @__PURE__ */ jsx18(Loader2, { className: "h-4 w-4 animate-spin" }),
|
|
1410
|
+
"A entrar..."
|
|
1411
|
+
] }) : "Entrar"
|
|
1412
|
+
}
|
|
1413
|
+
)
|
|
1414
|
+
] }) }),
|
|
1415
|
+
/* @__PURE__ */ jsx18("p", { className: "mt-6 text-center text-xs text-muted-foreground", children: config.footerText || "Acesso restrito a utilizadores autorizados" }),
|
|
1416
|
+
/* @__PURE__ */ jsxs10("p", { className: "mt-1 text-center text-xs text-muted-foreground", children: [
|
|
1417
|
+
"\xA9 ",
|
|
1418
|
+
(/* @__PURE__ */ new Date()).getFullYear(),
|
|
1419
|
+
" ",
|
|
1420
|
+
config.appName
|
|
1421
|
+
] })
|
|
1422
|
+
] }) })
|
|
1423
|
+
] });
|
|
1332
1424
|
}
|
|
1333
1425
|
|
|
1334
1426
|
// src/components/entity-avatar.tsx
|
|
@@ -1891,7 +1983,7 @@ function useResetPassword(config) {
|
|
|
1891
1983
|
}
|
|
1892
1984
|
|
|
1893
1985
|
// src/components/users/users-page.tsx
|
|
1894
|
-
import { useMemo as
|
|
1986
|
+
import { useMemo as useMemo4, useState as useState7 } from "react";
|
|
1895
1987
|
|
|
1896
1988
|
// src/components/users/user-form-dialog.tsx
|
|
1897
1989
|
import { useEffect as useEffect3, useState as useState5 } from "react";
|
|
@@ -2580,7 +2672,7 @@ function UsersPage({ config, renderPhones }) {
|
|
|
2580
2672
|
const [search, setSearch] = useState7("");
|
|
2581
2673
|
const [profileFilter, setProfileFilter] = useState7("all");
|
|
2582
2674
|
const [page, setPage] = useState7(1);
|
|
2583
|
-
const queryParams =
|
|
2675
|
+
const queryParams = useMemo4(() => {
|
|
2584
2676
|
const params = {
|
|
2585
2677
|
limit: String(PAGE_SIZE),
|
|
2586
2678
|
page: String(page)
|
|
@@ -2597,7 +2689,7 @@ function UsersPage({ config, renderPhones }) {
|
|
|
2597
2689
|
const [resetUser, setResetUser] = useState7(null);
|
|
2598
2690
|
const users = data?.data || [];
|
|
2599
2691
|
const total = data?.total || 0;
|
|
2600
|
-
const filtered =
|
|
2692
|
+
const filtered = useMemo4(() => {
|
|
2601
2693
|
if (!search) return users;
|
|
2602
2694
|
const term = search.toLowerCase();
|
|
2603
2695
|
return users.filter(
|
|
@@ -2635,7 +2727,7 @@ function UsersPage({ config, renderPhones }) {
|
|
|
2635
2727
|
}
|
|
2636
2728
|
});
|
|
2637
2729
|
}
|
|
2638
|
-
return /* @__PURE__ */ jsxs19("div", { className: "flex flex-col gap-4 p-4", children: [
|
|
2730
|
+
return /* @__PURE__ */ jsxs19("div", { className: "flex flex-col gap-4 p-4 md:p-6", children: [
|
|
2639
2731
|
/* @__PURE__ */ jsxs19("div", { className: "flex items-center justify-between", children: [
|
|
2640
2732
|
/* @__PURE__ */ jsxs19("div", { children: [
|
|
2641
2733
|
/* @__PURE__ */ jsx29("h1", { className: "text-xl font-semibold", children: "Usu\xE1rios" }),
|