@greatapps/common 1.1.1 → 1.1.3
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/components/layouts/NavBarItem.mjs +23 -0
- package/dist/components/layouts/NavBarItem.mjs.map +1 -0
- package/dist/components/layouts/NotificationsPopover.mjs +77 -0
- package/dist/components/layouts/NotificationsPopover.mjs.map +1 -0
- package/dist/components/layouts/ProfilePopover.mjs +141 -0
- package/dist/components/layouts/ProfilePopover.mjs.map +1 -0
- package/dist/components/layouts/UsersSelectorPopover.mjs +142 -0
- package/dist/components/layouts/UsersSelectorPopover.mjs.map +1 -0
- package/dist/components/ui/data-display/UserAvatar.mjs +49 -0
- package/dist/components/ui/data-display/UserAvatar.mjs.map +1 -0
- package/dist/index.mjs +144 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/layouts/NavBarItem.tsx +29 -0
- package/src/components/layouts/NotificationsPopover.tsx +99 -0
- package/src/components/layouts/ProfilePopover.tsx +171 -0
- package/src/components/layouts/UsersSelectorPopover.tsx +158 -0
- package/src/components/ui/data-display/UserAvatar.tsx +67 -0
- package/src/index.ts +51 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { cn } from "../../infra/utils/clsx";
|
|
4
|
+
function NavBarItem({ icon, label, onClick, className, labelClassName }) {
|
|
5
|
+
return /* @__PURE__ */ jsxs(
|
|
6
|
+
"div",
|
|
7
|
+
{
|
|
8
|
+
className: cn(
|
|
9
|
+
"rounded-lg flex items-center gap-2 px-2 py-2 h-10 cursor-pointer transition-colors bg-white hover:bg-gray-100 active:bg-gray-50",
|
|
10
|
+
className
|
|
11
|
+
),
|
|
12
|
+
onClick,
|
|
13
|
+
children: [
|
|
14
|
+
icon,
|
|
15
|
+
/* @__PURE__ */ jsx("span", { className: cn("text-sm font-medium text-gray-950", labelClassName), children: label })
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
export {
|
|
21
|
+
NavBarItem
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=NavBarItem.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/layouts/NavBarItem.tsx"],"sourcesContent":["\"use client\"\r\n\r\nimport { cn } from '../../infra/utils/clsx';\r\n\r\ntype NavBarItemProps = {\r\n icon?: React.ReactNode;\r\n label: string;\r\n onClick: () => void;\r\n className?: string;\r\n labelClassName?: string;\r\n}\r\n\r\nfunction NavBarItem({ icon, label, onClick, className, labelClassName }: NavBarItemProps) {\r\n return (\r\n <div\r\n className={cn(\r\n 'rounded-lg flex items-center gap-2 px-2 py-2 h-10 cursor-pointer transition-colors bg-white hover:bg-gray-100 active:bg-gray-50',\r\n className\r\n )}\r\n onClick={onClick}\r\n >\r\n {icon}\r\n <span className={cn('text-sm font-medium text-gray-950', labelClassName)}>{label}</span>\r\n </div>\r\n );\r\n}\r\n\r\nexport { NavBarItem };\r\nexport type { NavBarItemProps };\r\n"],"mappings":";AAcI,SAQE,KARF;AAZJ,SAAS,UAAU;AAUnB,SAAS,WAAW,EAAE,MAAM,OAAO,SAAS,WAAW,eAAe,GAAoB;AACxF,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACA;AAAA,MAEC;AAAA;AAAA,QACD,oBAAC,UAAK,WAAW,GAAG,qCAAqC,cAAc,GAAI,iBAAM;AAAA;AAAA;AAAA,EACnF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { Bell } from "lucide-react";
|
|
5
|
+
import { Popover, PopoverContent, PopoverTrigger } from "../ui/overlay/Popover";
|
|
6
|
+
import { Button } from "../ui/buttons/Button";
|
|
7
|
+
import { NotificationItem } from "./NotificationItem";
|
|
8
|
+
import { cn } from "../../infra/utils/clsx";
|
|
9
|
+
function NotificationsPopover({
|
|
10
|
+
notifications = [],
|
|
11
|
+
onViewAll,
|
|
12
|
+
side,
|
|
13
|
+
align,
|
|
14
|
+
contentClassName,
|
|
15
|
+
badgeClassName = "bg-pages-400"
|
|
16
|
+
}) {
|
|
17
|
+
const [open, setOpen] = useState(false);
|
|
18
|
+
const [hasNewNotifications, setHasNewNotifications] = useState(true);
|
|
19
|
+
const handleOpenChange = (isOpen) => {
|
|
20
|
+
setOpen(isOpen);
|
|
21
|
+
if (isOpen) setHasNewNotifications(false);
|
|
22
|
+
};
|
|
23
|
+
return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: handleOpenChange, children: [
|
|
24
|
+
/* @__PURE__ */ jsx(PopoverTrigger, { className: "cursor-pointer", children: /* @__PURE__ */ jsxs(
|
|
25
|
+
"div",
|
|
26
|
+
{
|
|
27
|
+
className: `relative rounded-full p-2.5 ${open ? "bg-gray-100" : "hover:bg-gray-100"}`,
|
|
28
|
+
children: [
|
|
29
|
+
/* @__PURE__ */ jsx(Bell, { size: 20, className: "text-gray-500" }),
|
|
30
|
+
hasNewNotifications && /* @__PURE__ */ jsx("span", { className: cn("absolute top-2 right-2 size-2.5 rounded-full", badgeClassName) })
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
) }),
|
|
34
|
+
/* @__PURE__ */ jsxs(
|
|
35
|
+
PopoverContent,
|
|
36
|
+
{
|
|
37
|
+
className: cn(
|
|
38
|
+
"absolute bottom-2 left-[26px] w-[308px] p-0 pt-4 bg-white rounded-2xl shadow-md border border-gray-200",
|
|
39
|
+
contentClassName
|
|
40
|
+
),
|
|
41
|
+
side,
|
|
42
|
+
align,
|
|
43
|
+
sideOffset: 8,
|
|
44
|
+
children: [
|
|
45
|
+
/* @__PURE__ */ jsx("span", { className: "paragraph-small-semibold text-gray-950 px-4", children: "\xDAltimas notifica\xE7\xF5es" }),
|
|
46
|
+
notifications.length > 0 ? notifications.map((notification, index) => /* @__PURE__ */ jsx(
|
|
47
|
+
NotificationItem,
|
|
48
|
+
{
|
|
49
|
+
icon: notification.icon,
|
|
50
|
+
iconBgColor: notification.iconBgColor,
|
|
51
|
+
title: notification.title,
|
|
52
|
+
time: notification.time,
|
|
53
|
+
showBorder: index < notifications.length - 1
|
|
54
|
+
},
|
|
55
|
+
index
|
|
56
|
+
)) : /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-4 pt-[41.5px] pb-[33.5px]", children: [
|
|
57
|
+
/* @__PURE__ */ jsx("div", { className: "bg-gray-50 rounded-md p-2.5", children: /* @__PURE__ */ jsx(Bell, { size: 20, color: "var(--color-gray-950)" }) }),
|
|
58
|
+
/* @__PURE__ */ jsx("span", { className: "paragraph-small-medium text-gray-950", children: "Sem notifica\xE7\xF5es por enquanto" })
|
|
59
|
+
] }),
|
|
60
|
+
onViewAll && /* @__PURE__ */ jsx(
|
|
61
|
+
Button,
|
|
62
|
+
{
|
|
63
|
+
variant: "secondary",
|
|
64
|
+
className: "h-8! mt-2 mb-4 mx-4 paragraph-small-semibold",
|
|
65
|
+
onClick: onViewAll,
|
|
66
|
+
children: "Todas as notifica\xE7\xF5es"
|
|
67
|
+
}
|
|
68
|
+
)
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
)
|
|
72
|
+
] });
|
|
73
|
+
}
|
|
74
|
+
export {
|
|
75
|
+
NotificationsPopover
|
|
76
|
+
};
|
|
77
|
+
//# sourceMappingURL=NotificationsPopover.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/layouts/NotificationsPopover.tsx"],"sourcesContent":["\"use client\"\r\n\r\nimport { ReactNode, useState } from 'react';\r\nimport { Bell } from 'lucide-react';\r\nimport { Popover, PopoverContent, PopoverTrigger } from '../ui/overlay/Popover';\r\nimport { Button } from '../ui/buttons/Button';\r\nimport { NotificationItem } from './NotificationItem';\r\nimport { cn } from '../../infra/utils/clsx';\r\n\r\nexport interface NotificationData {\r\n icon: ReactNode;\r\n iconBgColor: string;\r\n title: string;\r\n time: string;\r\n}\r\n\r\nexport interface NotificationsPopoverProps {\r\n notifications?: NotificationData[];\r\n onViewAll?: () => void;\r\n side?: 'top' | 'bottom' | 'left' | 'right';\r\n align?: 'start' | 'center' | 'end';\r\n contentClassName?: string;\r\n badgeClassName?: string;\r\n}\r\n\r\nfunction NotificationsPopover({\r\n notifications = [],\r\n onViewAll,\r\n side,\r\n align,\r\n contentClassName,\r\n badgeClassName = 'bg-pages-400',\r\n}: NotificationsPopoverProps) {\r\n const [open, setOpen] = useState(false);\r\n const [hasNewNotifications, setHasNewNotifications] = useState(true);\r\n\r\n const handleOpenChange = (isOpen: boolean) => {\r\n setOpen(isOpen);\r\n if (isOpen) setHasNewNotifications(false);\r\n };\r\n\r\n return (\r\n <Popover open={open} onOpenChange={handleOpenChange}>\r\n <PopoverTrigger className=\"cursor-pointer\">\r\n <div\r\n className={`relative rounded-full p-2.5 ${open ? 'bg-gray-100' : 'hover:bg-gray-100'}`}\r\n >\r\n <Bell size={20} className=\"text-gray-500\" />\r\n {hasNewNotifications && (\r\n <span className={cn('absolute top-2 right-2 size-2.5 rounded-full', badgeClassName)} />\r\n )}\r\n </div>\r\n </PopoverTrigger>\r\n <PopoverContent\r\n className={cn(\r\n 'absolute bottom-2 left-[26px] w-[308px] p-0 pt-4 bg-white rounded-2xl shadow-md border border-gray-200',\r\n contentClassName\r\n )}\r\n side={side}\r\n align={align}\r\n sideOffset={8}\r\n >\r\n <span className=\"paragraph-small-semibold text-gray-950 px-4\">Últimas notificações</span>\r\n\r\n {notifications.length > 0 ? (\r\n notifications.map((notification, index) => (\r\n <NotificationItem\r\n key={index}\r\n icon={notification.icon}\r\n iconBgColor={notification.iconBgColor}\r\n title={notification.title}\r\n time={notification.time}\r\n showBorder={index < notifications.length - 1}\r\n />\r\n ))\r\n ) : (\r\n <div className=\"flex flex-col items-center gap-4 pt-[41.5px] pb-[33.5px]\">\r\n <div className=\"bg-gray-50 rounded-md p-2.5\">\r\n <Bell size={20} color=\"var(--color-gray-950)\" />\r\n </div>\r\n <span className=\"paragraph-small-medium text-gray-950\">Sem notificações por enquanto</span>\r\n </div>\r\n )}\r\n\r\n {onViewAll && (\r\n <Button\r\n variant=\"secondary\"\r\n className=\"h-8! mt-2 mb-4 mx-4 paragraph-small-semibold\"\r\n onClick={onViewAll}\r\n >\r\n Todas as notificações\r\n </Button>\r\n )}\r\n </PopoverContent>\r\n </Popover>\r\n );\r\n}\r\n\r\nexport { NotificationsPopover };\r\n"],"mappings":";AA4CQ,SAGE,KAHF;AA1CR,SAAoB,gBAAgB;AACpC,SAAS,YAAY;AACrB,SAAS,SAAS,gBAAgB,sBAAsB;AACxD,SAAS,cAAc;AACvB,SAAS,wBAAwB;AACjC,SAAS,UAAU;AAkBnB,SAAS,qBAAqB;AAAA,EAC5B,gBAAgB,CAAC;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,iBAAiB;AACnB,GAA8B;AAC5B,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AACtC,QAAM,CAAC,qBAAqB,sBAAsB,IAAI,SAAS,IAAI;AAEnE,QAAM,mBAAmB,CAAC,WAAoB;AAC5C,YAAQ,MAAM;AACd,QAAI,OAAQ,wBAAuB,KAAK;AAAA,EAC1C;AAEA,SACE,qBAAC,WAAQ,MAAY,cAAc,kBACjC;AAAA,wBAAC,kBAAe,WAAU,kBACxB;AAAA,MAAC;AAAA;AAAA,QACC,WAAW,+BAA+B,OAAO,gBAAgB,mBAAmB;AAAA,QAEpF;AAAA,8BAAC,QAAK,MAAM,IAAI,WAAU,iBAAgB;AAAA,UACzC,uBACC,oBAAC,UAAK,WAAW,GAAG,gDAAgD,cAAc,GAAG;AAAA;AAAA;AAAA,IAEzF,GACF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,WAAW;AAAA,UACT;AAAA,UACA;AAAA,QACF;AAAA,QACA;AAAA,QACA;AAAA,QACA,YAAY;AAAA,QAEZ;AAAA,8BAAC,UAAK,WAAU,+CAA8C,2CAAoB;AAAA,UAEjF,cAAc,SAAS,IACtB,cAAc,IAAI,CAAC,cAAc,UAC/B;AAAA,YAAC;AAAA;AAAA,cAEC,MAAM,aAAa;AAAA,cACnB,aAAa,aAAa;AAAA,cAC1B,OAAO,aAAa;AAAA,cACpB,MAAM,aAAa;AAAA,cACnB,YAAY,QAAQ,cAAc,SAAS;AAAA;AAAA,YALtC;AAAA,UAMP,CACD,IAED,qBAAC,SAAI,WAAU,4DACb;AAAA,gCAAC,SAAI,WAAU,+BACb,8BAAC,QAAK,MAAM,IAAI,OAAM,yBAAwB,GAChD;AAAA,YACA,oBAAC,UAAK,WAAU,wCAAuC,iDAA6B;AAAA,aACtF;AAAA,UAGD,aACC;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,WAAU;AAAA,cACV,SAAS;AAAA,cACV;AAAA;AAAA,UAED;AAAA;AAAA;AAAA,IAEJ;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { useRouter } from "next/navigation";
|
|
5
|
+
import { Popover, PopoverContent, PopoverTrigger } from "../ui/overlay/Popover";
|
|
6
|
+
import { Button } from "../ui/buttons/Button";
|
|
7
|
+
import { Progress } from "../ui/feedback/Progress";
|
|
8
|
+
import { Separator } from "../ui/data-display/Separator";
|
|
9
|
+
import { NavBarItem } from "./NavBarItem";
|
|
10
|
+
import { UserAvatar } from "../ui/data-display/UserAvatar";
|
|
11
|
+
import { useAuth } from "../../providers/auth.provider";
|
|
12
|
+
import { cn } from "../../infra/utils/clsx";
|
|
13
|
+
function ProfilePopover({
|
|
14
|
+
side = "top",
|
|
15
|
+
align = "start",
|
|
16
|
+
contentClassName,
|
|
17
|
+
onEditProfile,
|
|
18
|
+
credits,
|
|
19
|
+
onCreditsClick,
|
|
20
|
+
menuItems = [],
|
|
21
|
+
logoutRedirect = "/login",
|
|
22
|
+
storageUrl,
|
|
23
|
+
logoutOverlay
|
|
24
|
+
}) {
|
|
25
|
+
const router = useRouter();
|
|
26
|
+
const { user, logout } = useAuth();
|
|
27
|
+
const [isLoggingOut, setIsLoggingOut] = useState(false);
|
|
28
|
+
const handleLogout = async () => {
|
|
29
|
+
try {
|
|
30
|
+
setIsLoggingOut(true);
|
|
31
|
+
await logout();
|
|
32
|
+
router.push(logoutRedirect);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error("Erro ao fazer logout:", error);
|
|
35
|
+
} finally {
|
|
36
|
+
setIsLoggingOut(false);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const creditsPercentage = credits && credits.total > 0 ? credits.used / credits.total * 100 : 0;
|
|
40
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
41
|
+
isLoggingOut && logoutOverlay,
|
|
42
|
+
/* @__PURE__ */ jsxs(Popover, { children: [
|
|
43
|
+
/* @__PURE__ */ jsx(PopoverTrigger, { className: "cursor-pointer", children: user && /* @__PURE__ */ jsx(
|
|
44
|
+
UserAvatar,
|
|
45
|
+
{
|
|
46
|
+
photo: user.photo,
|
|
47
|
+
name: user.name,
|
|
48
|
+
size: 40,
|
|
49
|
+
storageUrl
|
|
50
|
+
},
|
|
51
|
+
user.id
|
|
52
|
+
) }),
|
|
53
|
+
/* @__PURE__ */ jsxs(
|
|
54
|
+
PopoverContent,
|
|
55
|
+
{
|
|
56
|
+
className: cn(
|
|
57
|
+
"w-64.75 p-0 bg-white rounded-2xl shadow-md border border-gray-200 z-99",
|
|
58
|
+
contentClassName
|
|
59
|
+
),
|
|
60
|
+
side,
|
|
61
|
+
align,
|
|
62
|
+
sideOffset: 8,
|
|
63
|
+
children: [
|
|
64
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[32px_1fr_auto] items-center gap-3 p-3 w-full", children: [
|
|
65
|
+
user && /* @__PURE__ */ jsx(
|
|
66
|
+
UserAvatar,
|
|
67
|
+
{
|
|
68
|
+
photo: user.photo,
|
|
69
|
+
name: user.name,
|
|
70
|
+
size: 32,
|
|
71
|
+
storageUrl
|
|
72
|
+
},
|
|
73
|
+
user.id
|
|
74
|
+
),
|
|
75
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5 min-w-0", children: [
|
|
76
|
+
/* @__PURE__ */ jsx("span", { className: "paragraph-small-semibold text-gray-950 truncate", children: user?.name || "" }),
|
|
77
|
+
/* @__PURE__ */ jsx("span", { className: "paragraph-xsmall-medium text-gray-500 truncate", children: user?.email || "" })
|
|
78
|
+
] }),
|
|
79
|
+
onEditProfile && /* @__PURE__ */ jsx(
|
|
80
|
+
Button,
|
|
81
|
+
{
|
|
82
|
+
variant: "secondary",
|
|
83
|
+
className: "paragraph-small-semibold h-8! whitespace-nowrap px-3 w-fit",
|
|
84
|
+
onClick: onEditProfile,
|
|
85
|
+
children: "Editar Perfil"
|
|
86
|
+
}
|
|
87
|
+
)
|
|
88
|
+
] }),
|
|
89
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 border-t border-gray-200 rounded-2xl p-1.5", children: [
|
|
90
|
+
credits && /* @__PURE__ */ jsxs(
|
|
91
|
+
"div",
|
|
92
|
+
{
|
|
93
|
+
className: cn(
|
|
94
|
+
"flex flex-col bg-gray-950 rounded-lg gap-4 w-full p-4 transition-colors",
|
|
95
|
+
onCreditsClick && "cursor-pointer hover:bg-gray-900"
|
|
96
|
+
),
|
|
97
|
+
onClick: onCreditsClick,
|
|
98
|
+
children: [
|
|
99
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
100
|
+
/* @__PURE__ */ jsx("span", { className: "paragraph-xsmall-semibold text-white truncate", children: "Cr\xE9ditos usados" }),
|
|
101
|
+
/* @__PURE__ */ jsxs("span", { className: "paragraph-xsmall-medium text-white/50", children: [
|
|
102
|
+
credits.used.toLocaleString("pt-BR"),
|
|
103
|
+
"/",
|
|
104
|
+
credits.total.toLocaleString("pt-BR")
|
|
105
|
+
] })
|
|
106
|
+
] }),
|
|
107
|
+
/* @__PURE__ */ jsx(
|
|
108
|
+
Progress,
|
|
109
|
+
{
|
|
110
|
+
className: "bg-white/10",
|
|
111
|
+
indicatorColor: "bg-white",
|
|
112
|
+
value: creditsPercentage
|
|
113
|
+
}
|
|
114
|
+
)
|
|
115
|
+
]
|
|
116
|
+
}
|
|
117
|
+
),
|
|
118
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
119
|
+
menuItems.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-col", children: menuItems.map((item, index) => /* @__PURE__ */ jsx(
|
|
120
|
+
NavBarItem,
|
|
121
|
+
{
|
|
122
|
+
icon: item.icon,
|
|
123
|
+
label: item.label,
|
|
124
|
+
onClick: item.onClick
|
|
125
|
+
},
|
|
126
|
+
index
|
|
127
|
+
)) }),
|
|
128
|
+
/* @__PURE__ */ jsx(Separator, {}),
|
|
129
|
+
/* @__PURE__ */ jsx(NavBarItem, { label: "Sair", onClick: handleLogout })
|
|
130
|
+
] })
|
|
131
|
+
] })
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
)
|
|
135
|
+
] })
|
|
136
|
+
] });
|
|
137
|
+
}
|
|
138
|
+
export {
|
|
139
|
+
ProfilePopover
|
|
140
|
+
};
|
|
141
|
+
//# sourceMappingURL=ProfilePopover.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/layouts/ProfilePopover.tsx"],"sourcesContent":["\"use client\"\r\n\r\nimport { useState } from 'react';\r\nimport { useRouter } from 'next/navigation';\r\nimport { Popover, PopoverContent, PopoverTrigger } from '../ui/overlay/Popover';\r\nimport { Button } from '../ui/buttons/Button';\r\nimport { Progress } from '../ui/feedback/Progress';\r\nimport { Separator } from '../ui/data-display/Separator';\r\nimport { NavBarItem } from './NavBarItem';\r\nimport { UserAvatar } from '../ui/data-display/UserAvatar';\r\nimport { useAuth } from '../../providers/auth.provider';\r\nimport { cn } from '../../infra/utils/clsx';\r\n\r\nexport interface ProfileMenuItem {\r\n icon?: React.ReactNode;\r\n label: string;\r\n onClick: () => void;\r\n}\r\n\r\nexport interface ProfilePopoverProps {\r\n side?: 'top' | 'bottom' | 'left' | 'right';\r\n align?: 'start' | 'center' | 'end';\r\n contentClassName?: string;\r\n onEditProfile?: () => void;\r\n credits?: { used: number; total: number };\r\n onCreditsClick?: () => void;\r\n menuItems?: ProfileMenuItem[];\r\n logoutRedirect?: string;\r\n storageUrl?: string;\r\n logoutOverlay?: React.ReactNode;\r\n}\r\n\r\nfunction ProfilePopover({\r\n side = 'top',\r\n align = 'start',\r\n contentClassName,\r\n onEditProfile,\r\n credits,\r\n onCreditsClick,\r\n menuItems = [],\r\n logoutRedirect = '/login',\r\n storageUrl,\r\n logoutOverlay,\r\n}: ProfilePopoverProps) {\r\n const router = useRouter();\r\n const { user, logout } = useAuth();\r\n const [isLoggingOut, setIsLoggingOut] = useState(false);\r\n\r\n const handleLogout = async () => {\r\n try {\r\n setIsLoggingOut(true);\r\n await logout();\r\n router.push(logoutRedirect);\r\n } catch (error) {\r\n console.error('Erro ao fazer logout:', error);\r\n } finally {\r\n setIsLoggingOut(false);\r\n }\r\n };\r\n\r\n const creditsPercentage =\r\n credits && credits.total > 0\r\n ? (credits.used / credits.total) * 100\r\n : 0;\r\n\r\n return (\r\n <>\r\n {isLoggingOut && logoutOverlay}\r\n <Popover>\r\n <PopoverTrigger className=\"cursor-pointer\">\r\n {user && (\r\n <UserAvatar\r\n key={user.id}\r\n photo={user.photo}\r\n name={user.name}\r\n size={40}\r\n storageUrl={storageUrl}\r\n />\r\n )}\r\n </PopoverTrigger>\r\n\r\n <PopoverContent\r\n className={cn(\r\n 'w-64.75 p-0 bg-white rounded-2xl shadow-md border border-gray-200 z-99',\r\n contentClassName\r\n )}\r\n side={side}\r\n align={align}\r\n sideOffset={8}\r\n >\r\n <div className=\"grid grid-cols-[32px_1fr_auto] items-center gap-3 p-3 w-full\">\r\n {user && (\r\n <UserAvatar\r\n key={user.id}\r\n photo={user.photo}\r\n name={user.name}\r\n size={32}\r\n storageUrl={storageUrl}\r\n />\r\n )}\r\n\r\n <div className=\"flex flex-col gap-0.5 min-w-0\">\r\n <span className=\"paragraph-small-semibold text-gray-950 truncate\">\r\n {user?.name || ''}\r\n </span>\r\n <span className=\"paragraph-xsmall-medium text-gray-500 truncate\">\r\n {user?.email || ''}\r\n </span>\r\n </div>\r\n\r\n {onEditProfile && (\r\n <Button\r\n variant=\"secondary\"\r\n className=\"paragraph-small-semibold h-8! whitespace-nowrap px-3 w-fit\"\r\n onClick={onEditProfile}\r\n >\r\n Editar Perfil\r\n </Button>\r\n )}\r\n </div>\r\n\r\n <div className=\"flex flex-col gap-2 border-t border-gray-200 rounded-2xl p-1.5\">\r\n {credits && (\r\n <div\r\n className={cn(\r\n 'flex flex-col bg-gray-950 rounded-lg gap-4 w-full p-4 transition-colors',\r\n onCreditsClick && 'cursor-pointer hover:bg-gray-900'\r\n )}\r\n onClick={onCreditsClick}\r\n >\r\n <div className=\"flex items-center justify-between gap-2\">\r\n <span className=\"paragraph-xsmall-semibold text-white truncate\">\r\n Créditos usados\r\n </span>\r\n <span className=\"paragraph-xsmall-medium text-white/50\">\r\n {credits.used.toLocaleString('pt-BR')}/\r\n {credits.total.toLocaleString('pt-BR')}\r\n </span>\r\n </div>\r\n <Progress\r\n className=\"bg-white/10\"\r\n indicatorColor=\"bg-white\"\r\n value={creditsPercentage}\r\n />\r\n </div>\r\n )}\r\n\r\n <div className=\"flex flex-col gap-2\">\r\n {menuItems.length > 0 && (\r\n <div className=\"flex flex-col\">\r\n {menuItems.map((item, index) => (\r\n <NavBarItem\r\n key={index}\r\n icon={item.icon}\r\n label={item.label}\r\n onClick={item.onClick}\r\n />\r\n ))}\r\n </div>\r\n )}\r\n <Separator />\r\n <NavBarItem label=\"Sair\" onClick={handleLogout} />\r\n </div>\r\n </div>\r\n </PopoverContent>\r\n </Popover>\r\n </>\r\n );\r\n}\r\n\r\nexport { ProfilePopover };\r\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { Plus, Settings, User } from "lucide-react";
|
|
5
|
+
import Image from "next/image";
|
|
6
|
+
import { useRouter } from "next/navigation";
|
|
7
|
+
import { Popover, PopoverContent, PopoverTrigger } from "../ui/overlay/Popover";
|
|
8
|
+
import { Button } from "../ui/buttons/Button";
|
|
9
|
+
import { Command, CommandEmpty, CommandInput, CommandItem, CommandList } from "../ui/overlay/Command";
|
|
10
|
+
import { Checkbox } from "../ui/form/Checkbox";
|
|
11
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/overlay/Tooltip";
|
|
12
|
+
import { cn } from "../../infra/utils/clsx";
|
|
13
|
+
function UsersSelectorPopover({
|
|
14
|
+
users: externalUsers,
|
|
15
|
+
onToggleUser,
|
|
16
|
+
addRoute = "/my-teams?createNew=true",
|
|
17
|
+
manageRoute = "/my-teams",
|
|
18
|
+
userCount = 5,
|
|
19
|
+
side,
|
|
20
|
+
align,
|
|
21
|
+
contentClassName
|
|
22
|
+
}) {
|
|
23
|
+
const route = useRouter();
|
|
24
|
+
const [open, setOpen] = useState(false);
|
|
25
|
+
const [internalUsers, setInternalUsers] = useState(externalUsers ?? []);
|
|
26
|
+
const [hoveredId, setHoveredId] = useState(null);
|
|
27
|
+
const users = externalUsers ?? internalUsers;
|
|
28
|
+
const toggleUser = (id) => {
|
|
29
|
+
if (onToggleUser) {
|
|
30
|
+
onToggleUser(id);
|
|
31
|
+
} else {
|
|
32
|
+
setInternalUsers(
|
|
33
|
+
(prev) => prev.map((u) => u.id === id ? { ...u, checked: !u.checked } : u)
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, children: [
|
|
38
|
+
/* @__PURE__ */ jsx(PopoverTrigger, { className: "cursor-pointer", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-gray-950 px-3 py-2 border border-gray-200 rounded-full hover:border-gray-950", children: [
|
|
39
|
+
/* @__PURE__ */ jsx("span", { className: "paragraph-small-semibold", children: userCount }),
|
|
40
|
+
/* @__PURE__ */ jsx(User, { size: 16 })
|
|
41
|
+
] }) }),
|
|
42
|
+
/* @__PURE__ */ jsx(
|
|
43
|
+
PopoverContent,
|
|
44
|
+
{
|
|
45
|
+
className: cn(
|
|
46
|
+
"absolute right-[-88px] w-[273px] p-0 bg-white rounded-2xl shadow-md border border-gray-200",
|
|
47
|
+
contentClassName
|
|
48
|
+
),
|
|
49
|
+
side,
|
|
50
|
+
align,
|
|
51
|
+
sideOffset: 8,
|
|
52
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col p-3 gap-2", children: [
|
|
53
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
54
|
+
/* @__PURE__ */ jsx("span", { className: "paragraph-small-semibold", children: "Usu\xE1rios" }),
|
|
55
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
56
|
+
/* @__PURE__ */ jsxs(
|
|
57
|
+
Button,
|
|
58
|
+
{
|
|
59
|
+
variant: "secondary",
|
|
60
|
+
className: "h-8 paragraph-small-semibold text-gray-950",
|
|
61
|
+
onClick: () => route.push(addRoute),
|
|
62
|
+
children: [
|
|
63
|
+
/* @__PURE__ */ jsx(Plus, { size: 16 }),
|
|
64
|
+
"Adicionar"
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
),
|
|
68
|
+
/* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
69
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
70
|
+
Button,
|
|
71
|
+
{
|
|
72
|
+
variant: "secondary",
|
|
73
|
+
className: "p-0 size-8",
|
|
74
|
+
onClick: () => route.push(manageRoute),
|
|
75
|
+
children: /* @__PURE__ */ jsx(Settings, { size: 18 })
|
|
76
|
+
}
|
|
77
|
+
) }),
|
|
78
|
+
/* @__PURE__ */ jsx(TooltipContent, { children: "Visualizar todos usu\xE1rios" })
|
|
79
|
+
] })
|
|
80
|
+
] })
|
|
81
|
+
] }),
|
|
82
|
+
/* @__PURE__ */ jsxs(Command, { className: "gap-2", value: "", children: [
|
|
83
|
+
/* @__PURE__ */ jsx(CommandInput, { placeholder: "Busque aqui" }),
|
|
84
|
+
/* @__PURE__ */ jsxs(CommandList, { className: "custom-scrollbar paragraph-small-medium text-gray-600 h-[162px]", children: [
|
|
85
|
+
/* @__PURE__ */ jsx(CommandEmpty, { children: "No results found." }),
|
|
86
|
+
users.map((user) => /* @__PURE__ */ jsx(
|
|
87
|
+
CommandItem,
|
|
88
|
+
{
|
|
89
|
+
autoFocus: false,
|
|
90
|
+
onPointerEnter: () => setHoveredId(user.id),
|
|
91
|
+
onPointerLeave: () => setHoveredId(null),
|
|
92
|
+
onFocus: () => setHoveredId(user.id),
|
|
93
|
+
onBlur: () => setHoveredId(null),
|
|
94
|
+
onSelect: () => toggleUser(user.id),
|
|
95
|
+
className: "cursor-pointer",
|
|
96
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between w-full", children: [
|
|
97
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
98
|
+
/* @__PURE__ */ jsx(
|
|
99
|
+
Image,
|
|
100
|
+
{
|
|
101
|
+
alt: "Avatar",
|
|
102
|
+
src: user.avatar,
|
|
103
|
+
width: 32,
|
|
104
|
+
height: 32,
|
|
105
|
+
className: "rounded-full"
|
|
106
|
+
}
|
|
107
|
+
),
|
|
108
|
+
user.name
|
|
109
|
+
] }),
|
|
110
|
+
/* @__PURE__ */ jsxs(Tooltip, { open: hoveredId === user.id, children: [
|
|
111
|
+
/* @__PURE__ */ jsx(
|
|
112
|
+
TooltipTrigger,
|
|
113
|
+
{
|
|
114
|
+
onClick: (e) => e.stopPropagation(),
|
|
115
|
+
onPointerDown: (e) => e.stopPropagation(),
|
|
116
|
+
children: /* @__PURE__ */ jsx(
|
|
117
|
+
Checkbox,
|
|
118
|
+
{
|
|
119
|
+
checked: user.checked,
|
|
120
|
+
onCheckedChange: () => toggleUser(user.id),
|
|
121
|
+
className: hoveredId === user.id ? "border-gray-950" : ""
|
|
122
|
+
}
|
|
123
|
+
)
|
|
124
|
+
}
|
|
125
|
+
),
|
|
126
|
+
/* @__PURE__ */ jsx(TooltipContent, { children: user.checked ? "Remover do projeto" : "Adicionar ao projeto" })
|
|
127
|
+
] })
|
|
128
|
+
] })
|
|
129
|
+
},
|
|
130
|
+
user.id
|
|
131
|
+
))
|
|
132
|
+
] })
|
|
133
|
+
] })
|
|
134
|
+
] })
|
|
135
|
+
}
|
|
136
|
+
)
|
|
137
|
+
] });
|
|
138
|
+
}
|
|
139
|
+
export {
|
|
140
|
+
UsersSelectorPopover
|
|
141
|
+
};
|
|
142
|
+
//# sourceMappingURL=UsersSelectorPopover.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/layouts/UsersSelectorPopover.tsx"],"sourcesContent":["\"use client\"\r\n\r\nimport { useState } from 'react';\r\nimport { Plus, Settings, User } from 'lucide-react';\r\nimport Image from 'next/image';\r\nimport { useRouter } from 'next/navigation';\r\nimport { Popover, PopoverContent, PopoverTrigger } from '../ui/overlay/Popover';\r\nimport { Button } from '../ui/buttons/Button';\r\nimport { Command, CommandEmpty, CommandInput, CommandItem, CommandList } from '../ui/overlay/Command';\r\nimport { Checkbox } from '../ui/form/Checkbox';\r\nimport { Tooltip, TooltipContent, TooltipTrigger } from '../ui/overlay/Tooltip';\r\nimport { cn } from '../../infra/utils/clsx';\r\n\r\nexport interface UserSelectorItem {\r\n id: number;\r\n name: string;\r\n avatar: string;\r\n checked: boolean;\r\n}\r\n\r\nexport interface UsersSelectorPopoverProps {\r\n users?: UserSelectorItem[];\r\n onToggleUser?: (id: number) => void;\r\n addRoute?: string;\r\n manageRoute?: string;\r\n userCount?: number;\r\n side?: 'top' | 'bottom' | 'left' | 'right';\r\n align?: 'start' | 'center' | 'end';\r\n contentClassName?: string;\r\n}\r\n\r\nfunction UsersSelectorPopover({\r\n users: externalUsers,\r\n onToggleUser,\r\n addRoute = '/my-teams?createNew=true',\r\n manageRoute = '/my-teams',\r\n userCount = 5,\r\n side,\r\n align,\r\n contentClassName,\r\n}: UsersSelectorPopoverProps) {\r\n const route = useRouter();\r\n const [open, setOpen] = useState(false);\r\n const [internalUsers, setInternalUsers] = useState<UserSelectorItem[]>(externalUsers ?? []);\r\n const [hoveredId, setHoveredId] = useState<number | null>(null);\r\n\r\n const users = externalUsers ?? internalUsers;\r\n\r\n const toggleUser = (id: number) => {\r\n if (onToggleUser) {\r\n onToggleUser(id);\r\n } else {\r\n setInternalUsers((prev) =>\r\n prev.map((u) => (u.id === id ? { ...u, checked: !u.checked } : u))\r\n );\r\n }\r\n };\r\n\r\n return (\r\n <Popover open={open} onOpenChange={setOpen}>\r\n <PopoverTrigger className=\"cursor-pointer\">\r\n <div className=\"flex items-center gap-2 text-gray-950 px-3 py-2 border border-gray-200 rounded-full hover:border-gray-950\">\r\n <span className=\"paragraph-small-semibold\">{userCount}</span>\r\n <User size={16} />\r\n </div>\r\n </PopoverTrigger>\r\n\r\n <PopoverContent\r\n className={cn(\r\n 'absolute right-[-88px] w-[273px] p-0 bg-white rounded-2xl shadow-md border border-gray-200',\r\n contentClassName\r\n )}\r\n side={side}\r\n align={align}\r\n sideOffset={8}\r\n >\r\n <div className=\"flex flex-col p-3 gap-2\">\r\n <div className=\"flex items-center justify-between\">\r\n <span className=\"paragraph-small-semibold\">Usuários</span>\r\n <div className=\"flex items-center gap-1.5\">\r\n <Button\r\n variant=\"secondary\"\r\n className=\"h-8 paragraph-small-semibold text-gray-950\"\r\n onClick={() => route.push(addRoute)}\r\n >\r\n <Plus size={16} />\r\n Adicionar\r\n </Button>\r\n\r\n <Tooltip>\r\n <TooltipTrigger asChild>\r\n <Button\r\n variant=\"secondary\"\r\n className=\"p-0 size-8\"\r\n onClick={() => route.push(manageRoute)}\r\n >\r\n <Settings size={18} />\r\n </Button>\r\n </TooltipTrigger>\r\n <TooltipContent>Visualizar todos usuários</TooltipContent>\r\n </Tooltip>\r\n </div>\r\n </div>\r\n\r\n <Command className=\"gap-2\" value=\"\">\r\n <CommandInput placeholder=\"Busque aqui\" />\r\n <CommandList className=\"custom-scrollbar paragraph-small-medium text-gray-600 h-[162px]\">\r\n <CommandEmpty>No results found.</CommandEmpty>\r\n {users.map((user) => (\r\n <CommandItem\r\n key={user.id}\r\n autoFocus={false}\r\n onPointerEnter={() => setHoveredId(user.id)}\r\n onPointerLeave={() => setHoveredId(null)}\r\n onFocus={() => setHoveredId(user.id)}\r\n onBlur={() => setHoveredId(null)}\r\n onSelect={() => toggleUser(user.id)}\r\n className=\"cursor-pointer\"\r\n >\r\n <div className=\"flex items-center justify-between w-full\">\r\n <div className=\"flex items-center gap-2\">\r\n <Image\r\n alt=\"Avatar\"\r\n src={user.avatar}\r\n width={32}\r\n height={32}\r\n className=\"rounded-full\"\r\n />\r\n {user.name}\r\n </div>\r\n\r\n <Tooltip open={hoveredId === user.id}>\r\n <TooltipTrigger\r\n onClick={(e) => e.stopPropagation()}\r\n onPointerDown={(e) => e.stopPropagation()}\r\n >\r\n <Checkbox\r\n checked={user.checked}\r\n onCheckedChange={() => toggleUser(user.id)}\r\n className={hoveredId === user.id ? 'border-gray-950' : ''}\r\n />\r\n </TooltipTrigger>\r\n <TooltipContent>\r\n {user.checked ? 'Remover do projeto' : 'Adicionar ao projeto'}\r\n </TooltipContent>\r\n </Tooltip>\r\n </div>\r\n </CommandItem>\r\n ))}\r\n </CommandList>\r\n </Command>\r\n </div>\r\n </PopoverContent>\r\n </Popover>\r\n );\r\n}\r\n\r\nexport { UsersSelectorPopover };\r\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import Image from "next/image";
|
|
4
|
+
import { cn } from "../../../infra/utils/clsx";
|
|
5
|
+
function getInitials(name, maxLength = 2) {
|
|
6
|
+
return name.split(" ").map((n) => n[0]).join("").slice(0, maxLength).toUpperCase();
|
|
7
|
+
}
|
|
8
|
+
function UserAvatar({
|
|
9
|
+
photo,
|
|
10
|
+
name,
|
|
11
|
+
initials,
|
|
12
|
+
size = 32,
|
|
13
|
+
shape = "circle",
|
|
14
|
+
className,
|
|
15
|
+
storageUrl
|
|
16
|
+
}) {
|
|
17
|
+
const shapeClass = shape === "circle" ? "rounded-full" : "rounded-lg";
|
|
18
|
+
const displayInitials = initials || (name ? getInitials(name) : "?");
|
|
19
|
+
const photoUrl = storageUrl && photo ? `${storageUrl}/${photo}` : photo;
|
|
20
|
+
if (photoUrl) {
|
|
21
|
+
return /* @__PURE__ */ jsx(
|
|
22
|
+
Image,
|
|
23
|
+
{
|
|
24
|
+
alt: name || "imagem do usuario",
|
|
25
|
+
src: photoUrl,
|
|
26
|
+
width: size,
|
|
27
|
+
height: size,
|
|
28
|
+
className: cn("object-cover shrink-0", shapeClass, className),
|
|
29
|
+
style: { width: size, height: size }
|
|
30
|
+
}
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
return /* @__PURE__ */ jsx(
|
|
34
|
+
"div",
|
|
35
|
+
{
|
|
36
|
+
className: cn(
|
|
37
|
+
"flex items-center justify-center shrink-0 bg-gray-100",
|
|
38
|
+
shapeClass,
|
|
39
|
+
className
|
|
40
|
+
),
|
|
41
|
+
style: { width: size, height: size },
|
|
42
|
+
children: /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-gray-700", children: displayInitials })
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
export {
|
|
47
|
+
UserAvatar
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=UserAvatar.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/ui/data-display/UserAvatar.tsx"],"sourcesContent":["\"use client\"\r\n\r\nimport Image from 'next/image';\r\nimport { cn } from '../../../infra/utils/clsx';\r\n\r\nfunction getInitials(name: string, maxLength: number = 2): string {\r\n return name\r\n .split(' ')\r\n .map((n) => n[0])\r\n .join('')\r\n .slice(0, maxLength)\r\n .toUpperCase();\r\n}\r\n\r\ninterface UserAvatarProps {\r\n photo?: string | null;\r\n name?: string;\r\n initials?: string;\r\n size?: number;\r\n shape?: 'circle' | 'square';\r\n className?: string;\r\n storageUrl?: string;\r\n}\r\n\r\nfunction UserAvatar({\r\n photo,\r\n name,\r\n initials,\r\n size = 32,\r\n shape = 'circle',\r\n className,\r\n storageUrl,\r\n}: UserAvatarProps) {\r\n const shapeClass = shape === 'circle' ? 'rounded-full' : 'rounded-lg';\r\n const displayInitials = initials || (name ? getInitials(name) : '?');\r\n\r\n const photoUrl = storageUrl && photo ? `${storageUrl}/${photo}` : photo;\r\n\r\n if (photoUrl) {\r\n return (\r\n <Image\r\n alt={name || 'imagem do usuario'}\r\n src={photoUrl}\r\n width={size}\r\n height={size}\r\n className={cn('object-cover shrink-0', shapeClass, className)}\r\n style={{ width: size, height: size }}\r\n />\r\n );\r\n }\r\n\r\n return (\r\n <div\r\n className={cn(\r\n 'flex items-center justify-center shrink-0 bg-gray-100',\r\n shapeClass,\r\n className\r\n )}\r\n style={{ width: size, height: size }}\r\n >\r\n <span className=\"text-xs font-semibold text-gray-700\">{displayInitials}</span>\r\n </div>\r\n );\r\n}\r\n\r\nexport { UserAvatar };\r\nexport type { UserAvatarProps };\r\n"],"mappings":";AAwCM;AAtCN,OAAO,WAAW;AAClB,SAAS,UAAU;AAEnB,SAAS,YAAY,MAAc,YAAoB,GAAW;AAChE,SAAO,KACJ,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,EACf,KAAK,EAAE,EACP,MAAM,GAAG,SAAS,EAClB,YAAY;AACjB;AAYA,SAAS,WAAW;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,QAAQ;AAAA,EACR;AAAA,EACA;AACF,GAAoB;AAClB,QAAM,aAAa,UAAU,WAAW,iBAAiB;AACzD,QAAM,kBAAkB,aAAa,OAAO,YAAY,IAAI,IAAI;AAEhE,QAAM,WAAW,cAAc,QAAQ,GAAG,UAAU,IAAI,KAAK,KAAK;AAElE,MAAI,UAAU;AACZ,WACE;AAAA,MAAC;AAAA;AAAA,QACC,KAAK,QAAQ;AAAA,QACb,KAAK;AAAA,QACL,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,WAAW,GAAG,yBAAyB,YAAY,SAAS;AAAA,QAC5D,OAAO,EAAE,OAAO,MAAM,QAAQ,KAAK;AAAA;AAAA,IACrC;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,OAAO,EAAE,OAAO,MAAM,QAAQ,KAAK;AAAA,MAEnC,8BAAC,UAAK,WAAU,uCAAuC,2BAAgB;AAAA;AAAA,EACzE;AAEJ;","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -17,24 +17,168 @@ import { NavBar } from "./components/layouts/NavBar";
|
|
|
17
17
|
import { SideBarNavigation } from "./components/layouts/SideBarNavigation";
|
|
18
18
|
import { MdSideBarNavigation } from "./components/layouts/MdSideBarNavigation";
|
|
19
19
|
import { NotificationItem } from "./components/layouts/NotificationItem";
|
|
20
|
+
import { NotificationsPopover } from "./components/layouts/NotificationsPopover";
|
|
21
|
+
import { UsersSelectorPopover } from "./components/layouts/UsersSelectorPopover";
|
|
22
|
+
import { ProfilePopover } from "./components/layouts/ProfilePopover";
|
|
23
|
+
import { NavBarItem } from "./components/layouts/NavBarItem";
|
|
24
|
+
import { Button, buttonVariants } from "./components/ui/buttons/Button";
|
|
25
|
+
import { CopyButton } from "./components/ui/buttons/CopyButton";
|
|
26
|
+
import { default as default2 } from "./components/ui/buttons/CancelButton";
|
|
27
|
+
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from "./components/ui/data-display/Accordion";
|
|
28
|
+
import { Badge, badgeVariants } from "./components/ui/data-display/Badge";
|
|
29
|
+
import { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent } from "./components/ui/data-display/Card";
|
|
30
|
+
import { Pagination, PaginationContent, PaginationLink, PaginationItem, PaginationPrevious, PaginationNext, PaginationEllipsis } from "./components/ui/data-display/Pagination";
|
|
31
|
+
import { ScrollArea, ScrollBar } from "./components/ui/data-display/ScrollArea";
|
|
32
|
+
import { Separator } from "./components/ui/data-display/Separator";
|
|
33
|
+
import { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption } from "./components/ui/data-display/Table";
|
|
34
|
+
import { Tabs, TabsList, TabsTrigger, TabsContent } from "./components/ui/data-display/Tabs";
|
|
35
|
+
import { UserAvatar } from "./components/ui/data-display/UserAvatar";
|
|
36
|
+
import { default as default3 } from "./components/ui/feedback/CircularProgress";
|
|
37
|
+
import { default as default4 } from "./components/ui/feedback/DefaultCircularProgress";
|
|
38
|
+
import { Progress } from "./components/ui/feedback/Progress";
|
|
39
|
+
import { Toast, toastVariants, toastIconContainerVariants } from "./components/ui/feedback/Toast";
|
|
40
|
+
import { Calendar, CalendarDayButton } from "./components/ui/form/Calendar";
|
|
41
|
+
import { Checkbox } from "./components/ui/form/Checkbox";
|
|
42
|
+
import { DatePicker } from "./components/ui/form/DatePicker";
|
|
43
|
+
import { DateRangePicker } from "./components/ui/form/DateRangePicker";
|
|
44
|
+
import { Input } from "./components/ui/form/Input";
|
|
45
|
+
import { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator } from "./components/ui/form/InputOtp";
|
|
46
|
+
import { RadioGroup, RadioGroupItem } from "./components/ui/form/RadioGroup";
|
|
47
|
+
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue } from "./components/ui/form/Select";
|
|
48
|
+
import { Switch } from "./components/ui/form/Switch";
|
|
49
|
+
import { Textarea } from "./components/ui/form/Textarea";
|
|
50
|
+
import { Command, CommandDialog, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandShortcut, CommandSeparator } from "./components/ui/overlay/Command";
|
|
51
|
+
import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger } from "./components/ui/overlay/Dialog";
|
|
52
|
+
import { Popover, PopoverTrigger, PopoverContent, PopoverAnchor } from "./components/ui/overlay/Popover";
|
|
53
|
+
import { Sheet, SheetTrigger, SheetClose, SheetContent, SheetHeader, SheetFooter, SheetTitle, SheetDescription } from "./components/ui/overlay/Sheet";
|
|
54
|
+
import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from "./components/ui/overlay/Tooltip";
|
|
20
55
|
import { useMdSidebarStore } from "./store/useMdSidebarStore";
|
|
21
56
|
export {
|
|
57
|
+
Accordion,
|
|
58
|
+
AccordionContent,
|
|
59
|
+
AccordionItem,
|
|
60
|
+
AccordionTrigger,
|
|
61
|
+
Badge,
|
|
62
|
+
Button,
|
|
63
|
+
Calendar,
|
|
64
|
+
CalendarDayButton,
|
|
65
|
+
default2 as CancelButton,
|
|
66
|
+
Card,
|
|
67
|
+
CardAction,
|
|
68
|
+
CardContent,
|
|
69
|
+
CardDescription,
|
|
70
|
+
CardFooter,
|
|
71
|
+
CardHeader,
|
|
72
|
+
CardTitle,
|
|
73
|
+
Checkbox,
|
|
74
|
+
default3 as CircularProgress,
|
|
75
|
+
Command,
|
|
76
|
+
CommandDialog,
|
|
77
|
+
CommandEmpty,
|
|
78
|
+
CommandGroup,
|
|
79
|
+
CommandInput,
|
|
80
|
+
CommandItem,
|
|
81
|
+
CommandList,
|
|
82
|
+
CommandSeparator,
|
|
83
|
+
CommandShortcut,
|
|
84
|
+
CopyButton,
|
|
85
|
+
DatePicker,
|
|
86
|
+
DateRangePicker,
|
|
87
|
+
default4 as DefaultCircularProgress,
|
|
88
|
+
Dialog,
|
|
89
|
+
DialogClose,
|
|
90
|
+
DialogContent,
|
|
91
|
+
DialogDescription,
|
|
92
|
+
DialogFooter,
|
|
93
|
+
DialogHeader,
|
|
94
|
+
DialogOverlay,
|
|
95
|
+
DialogPortal,
|
|
96
|
+
DialogTitle,
|
|
97
|
+
DialogTrigger,
|
|
98
|
+
Input,
|
|
99
|
+
InputOTP,
|
|
100
|
+
InputOTPGroup,
|
|
101
|
+
InputOTPSeparator,
|
|
102
|
+
InputOTPSlot,
|
|
22
103
|
MainLayout,
|
|
23
104
|
MainLayoutContent,
|
|
24
105
|
MainLayoutMain,
|
|
25
106
|
MainLayoutSpacer,
|
|
26
107
|
MdSideBarNavigation,
|
|
27
108
|
NavBar,
|
|
109
|
+
NavBarItem,
|
|
28
110
|
NotificationItem,
|
|
111
|
+
NotificationsPopover,
|
|
112
|
+
Pagination,
|
|
113
|
+
PaginationContent,
|
|
114
|
+
PaginationEllipsis,
|
|
115
|
+
PaginationItem,
|
|
116
|
+
PaginationLink,
|
|
117
|
+
PaginationNext,
|
|
118
|
+
PaginationPrevious,
|
|
119
|
+
Popover,
|
|
120
|
+
PopoverAnchor,
|
|
121
|
+
PopoverContent,
|
|
122
|
+
PopoverTrigger,
|
|
123
|
+
ProfilePopover,
|
|
124
|
+
Progress,
|
|
29
125
|
QueryProvider,
|
|
126
|
+
RadioGroup,
|
|
127
|
+
RadioGroupItem,
|
|
128
|
+
ScrollArea,
|
|
129
|
+
ScrollBar,
|
|
130
|
+
Select,
|
|
131
|
+
SelectContent,
|
|
132
|
+
SelectGroup,
|
|
133
|
+
SelectItem,
|
|
134
|
+
SelectLabel,
|
|
135
|
+
SelectScrollDownButton,
|
|
136
|
+
SelectScrollUpButton,
|
|
137
|
+
SelectSeparator,
|
|
138
|
+
SelectTrigger,
|
|
139
|
+
SelectValue,
|
|
140
|
+
Separator,
|
|
141
|
+
Sheet,
|
|
142
|
+
SheetClose,
|
|
143
|
+
SheetContent,
|
|
144
|
+
SheetDescription,
|
|
145
|
+
SheetFooter,
|
|
146
|
+
SheetHeader,
|
|
147
|
+
SheetTitle,
|
|
148
|
+
SheetTrigger,
|
|
30
149
|
SideBarNavigation,
|
|
150
|
+
Switch,
|
|
151
|
+
Table,
|
|
152
|
+
TableBody,
|
|
153
|
+
TableCaption,
|
|
154
|
+
TableCell,
|
|
155
|
+
TableFooter,
|
|
156
|
+
TableHead,
|
|
157
|
+
TableHeader,
|
|
158
|
+
TableRow,
|
|
159
|
+
Tabs,
|
|
160
|
+
TabsContent,
|
|
161
|
+
TabsList,
|
|
162
|
+
TabsTrigger,
|
|
163
|
+
Textarea,
|
|
164
|
+
Toast,
|
|
165
|
+
Tooltip,
|
|
166
|
+
TooltipContent,
|
|
167
|
+
TooltipProvider,
|
|
168
|
+
TooltipTrigger,
|
|
31
169
|
USER_QUERY_KEY,
|
|
170
|
+
UserAvatar,
|
|
171
|
+
UsersSelectorPopover,
|
|
172
|
+
badgeVariants,
|
|
32
173
|
buildQueryParams,
|
|
174
|
+
buttonVariants,
|
|
33
175
|
cn,
|
|
34
176
|
continueChain,
|
|
35
177
|
createAuthMiddleware,
|
|
36
178
|
createMiddlewareChain,
|
|
37
179
|
stopChain,
|
|
180
|
+
toastIconContainerVariants,
|
|
181
|
+
toastVariants,
|
|
38
182
|
useInvalidateUser,
|
|
39
183
|
useMdSidebarStore,
|
|
40
184
|
useSetUserData,
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Types\nexport * from './modules/auth/schema';\nexport * from './modules/users/schema';\nexport * from './modules/whitelabel/schema';\nexport * from './infra/api/types';\n\n// Contexts\nexport * from './providers/query.provider';\nexport * from './providers/auth.provider';\nexport * from './providers/whitelabel.provider';\n\n// Hooks\nexport { useUserQuery, useUserValidateSession, useInvalidateUser, useSetUserData, USER_QUERY_KEY } from './modules/auth/hooks/useUserQuery';\n\n// Providers\nexport { QueryProvider } from './providers/query.provider';\n\n// Middleware\nexport { createAuthMiddleware } from './middlewares/create-auth-middleware';\nexport { createMiddlewareChain } from './middlewares/chain';\nexport { continueChain, stopChain } from './middlewares/types';\nexport type { MiddlewareFunction, MiddlewareConfig, MiddlewareResult } from './middlewares/types';\n\n// Utils\nexport { cn } from './infra/utils/clsx';\nexport { buildQueryParams } from './infra/utils/params';\n\n// Layout\nexport { MainLayout, MainLayoutContent, MainLayoutSpacer, MainLayoutMain } from './components/layouts/MainLayout';\nexport { NavBar } from './components/layouts/NavBar';\nexport type { NavBarProps } from './components/layouts/NavBar';\nexport { SideBarNavigation } from './components/layouts/SideBarNavigation';\nexport { MdSideBarNavigation } from './components/layouts/MdSideBarNavigation';\nexport { NotificationItem } from './components/layouts/NotificationItem';\nexport type { NotificationItemProps } from './components/layouts/NotificationItem';\n\n// Store\nexport { useMdSidebarStore } from './store/useMdSidebarStore';\n"],"mappings":"AACA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,SAAS,cAAc,wBAAwB,mBAAmB,gBAAgB,sBAAsB;AAGxG,SAAS,qBAAqB;AAG9B,SAAS,4BAA4B;AACrC,SAAS,6BAA6B;AACtC,SAAS,eAAe,iBAAiB;AAIzC,SAAS,UAAU;AACnB,SAAS,wBAAwB;AAGjC,SAAS,YAAY,mBAAmB,kBAAkB,sBAAsB;AAChF,SAAS,cAAc;AAEvB,SAAS,yBAAyB;AAClC,SAAS,2BAA2B;AACpC,SAAS,wBAAwB;
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Types\nexport * from './modules/auth/schema';\nexport * from './modules/users/schema';\nexport * from './modules/whitelabel/schema';\nexport * from './infra/api/types';\n\n// Contexts\nexport * from './providers/query.provider';\nexport * from './providers/auth.provider';\nexport * from './providers/whitelabel.provider';\n\n// Hooks\nexport { useUserQuery, useUserValidateSession, useInvalidateUser, useSetUserData, USER_QUERY_KEY } from './modules/auth/hooks/useUserQuery';\n\n// Providers\nexport { QueryProvider } from './providers/query.provider';\n\n// Middleware\nexport { createAuthMiddleware } from './middlewares/create-auth-middleware';\nexport { createMiddlewareChain } from './middlewares/chain';\nexport { continueChain, stopChain } from './middlewares/types';\nexport type { MiddlewareFunction, MiddlewareConfig, MiddlewareResult } from './middlewares/types';\n\n// Utils\nexport { cn } from './infra/utils/clsx';\nexport { buildQueryParams } from './infra/utils/params';\n\n// Layout\nexport { MainLayout, MainLayoutContent, MainLayoutSpacer, MainLayoutMain } from './components/layouts/MainLayout';\nexport { NavBar } from './components/layouts/NavBar';\nexport type { NavBarProps } from './components/layouts/NavBar';\nexport { SideBarNavigation } from './components/layouts/SideBarNavigation';\nexport { MdSideBarNavigation } from './components/layouts/MdSideBarNavigation';\nexport { NotificationItem } from './components/layouts/NotificationItem';\nexport type { NotificationItemProps } from './components/layouts/NotificationItem';\nexport { NotificationsPopover } from './components/layouts/NotificationsPopover';\nexport type { NotificationsPopoverProps, NotificationData } from './components/layouts/NotificationsPopover';\nexport { UsersSelectorPopover } from './components/layouts/UsersSelectorPopover';\nexport type { UsersSelectorPopoverProps, UserSelectorItem } from './components/layouts/UsersSelectorPopover';\nexport { ProfilePopover } from './components/layouts/ProfilePopover';\nexport type { ProfilePopoverProps, ProfileMenuItem } from './components/layouts/ProfilePopover';\nexport { NavBarItem } from './components/layouts/NavBarItem';\nexport type { NavBarItemProps } from './components/layouts/NavBarItem';\n\n// UI - Buttons\nexport { Button, buttonVariants } from './components/ui/buttons/Button';\nexport { CopyButton } from './components/ui/buttons/CopyButton';\nexport { default as CancelButton } from './components/ui/buttons/CancelButton';\n\n// UI - Data Display\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from './components/ui/data-display/Accordion';\nexport { Badge, badgeVariants } from './components/ui/data-display/Badge';\nexport { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent } from './components/ui/data-display/Card';\nexport { Pagination, PaginationContent, PaginationLink, PaginationItem, PaginationPrevious, PaginationNext, PaginationEllipsis } from './components/ui/data-display/Pagination';\nexport { ScrollArea, ScrollBar } from './components/ui/data-display/ScrollArea';\nexport { Separator } from './components/ui/data-display/Separator';\nexport { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption } from './components/ui/data-display/Table';\nexport { Tabs, TabsList, TabsTrigger, TabsContent } from './components/ui/data-display/Tabs';\nexport { UserAvatar } from './components/ui/data-display/UserAvatar';\nexport type { UserAvatarProps } from './components/ui/data-display/UserAvatar';\n\n// UI - Feedback\nexport { default as CircularProgress } from './components/ui/feedback/CircularProgress';\nexport { default as DefaultCircularProgress } from './components/ui/feedback/DefaultCircularProgress';\nexport { Progress } from './components/ui/feedback/Progress';\nexport { Toast, toastVariants, toastIconContainerVariants } from './components/ui/feedback/Toast';\nexport type { ToastProps } from './components/ui/feedback/Toast';\n\n// UI - Form\nexport { Calendar, CalendarDayButton } from './components/ui/form/Calendar';\nexport { Checkbox } from './components/ui/form/Checkbox';\nexport { DatePicker } from './components/ui/form/DatePicker';\nexport { DateRangePicker } from './components/ui/form/DateRangePicker';\nexport { Input } from './components/ui/form/Input';\nexport { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator } from './components/ui/form/InputOtp';\nexport { RadioGroup, RadioGroupItem } from './components/ui/form/RadioGroup';\nexport { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue } from './components/ui/form/Select';\nexport { Switch } from './components/ui/form/Switch';\nexport { Textarea } from './components/ui/form/Textarea';\n\n// UI - Overlay\nexport { Command, CommandDialog, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandShortcut, CommandSeparator } from './components/ui/overlay/Command';\nexport { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger } from './components/ui/overlay/Dialog';\nexport { Popover, PopoverTrigger, PopoverContent, PopoverAnchor } from './components/ui/overlay/Popover';\nexport { Sheet, SheetTrigger, SheetClose, SheetContent, SheetHeader, SheetFooter, SheetTitle, SheetDescription } from './components/ui/overlay/Sheet';\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from './components/ui/overlay/Tooltip';\n\n// Store\nexport { useMdSidebarStore } from './store/useMdSidebarStore';\n"],"mappings":"AACA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AAGd,SAAS,cAAc,wBAAwB,mBAAmB,gBAAgB,sBAAsB;AAGxG,SAAS,qBAAqB;AAG9B,SAAS,4BAA4B;AACrC,SAAS,6BAA6B;AACtC,SAAS,eAAe,iBAAiB;AAIzC,SAAS,UAAU;AACnB,SAAS,wBAAwB;AAGjC,SAAS,YAAY,mBAAmB,kBAAkB,sBAAsB;AAChF,SAAS,cAAc;AAEvB,SAAS,yBAAyB;AAClC,SAAS,2BAA2B;AACpC,SAAS,wBAAwB;AAEjC,SAAS,4BAA4B;AAErC,SAAS,4BAA4B;AAErC,SAAS,sBAAsB;AAE/B,SAAS,kBAAkB;AAI3B,SAAS,QAAQ,sBAAsB;AACvC,SAAS,kBAAkB;AAC3B,SAAoB,WAAXA,gBAA+B;AAGxC,SAAS,WAAW,eAAe,kBAAkB,wBAAwB;AAC7E,SAAS,OAAO,qBAAqB;AACrC,SAAS,MAAM,YAAY,YAAY,WAAW,YAAY,iBAAiB,mBAAmB;AAClG,SAAS,YAAY,mBAAmB,gBAAgB,gBAAgB,oBAAoB,gBAAgB,0BAA0B;AACtI,SAAS,YAAY,iBAAiB;AACtC,SAAS,iBAAiB;AAC1B,SAAS,OAAO,aAAa,WAAW,aAAa,WAAW,UAAU,WAAW,oBAAoB;AACzG,SAAS,MAAM,UAAU,aAAa,mBAAmB;AACzD,SAAS,kBAAkB;AAI3B,SAAoB,WAAXA,gBAAmC;AAC5C,SAAoB,WAAXA,gBAA0C;AACnD,SAAS,gBAAgB;AACzB,SAAS,OAAO,eAAe,kCAAkC;AAIjE,SAAS,UAAU,yBAAyB;AAC5C,SAAS,gBAAgB;AACzB,SAAS,kBAAkB;AAC3B,SAAS,uBAAuB;AAChC,SAAS,aAAa;AACtB,SAAS,UAAU,eAAe,cAAc,yBAAyB;AACzE,SAAS,YAAY,sBAAsB;AAC3C,SAAS,QAAQ,eAAe,aAAa,YAAY,aAAa,wBAAwB,sBAAsB,iBAAiB,eAAe,mBAAmB;AACvK,SAAS,cAAc;AACvB,SAAS,gBAAgB;AAGzB,SAAS,SAAS,eAAe,cAAc,aAAa,cAAc,cAAc,aAAa,iBAAiB,wBAAwB;AAC9I,SAAS,QAAQ,aAAa,eAAe,mBAAmB,cAAc,cAAc,eAAe,cAAc,aAAa,qBAAqB;AAC3J,SAAS,SAAS,gBAAgB,gBAAgB,qBAAqB;AACvE,SAAS,OAAO,cAAc,YAAY,cAAc,aAAa,aAAa,YAAY,wBAAwB;AACtH,SAAS,SAAS,gBAAgB,gBAAgB,uBAAuB;AAGzE,SAAS,yBAAyB;","names":["default"]}
|
package/package.json
CHANGED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { cn } from '../../infra/utils/clsx';
|
|
4
|
+
|
|
5
|
+
type NavBarItemProps = {
|
|
6
|
+
icon?: React.ReactNode;
|
|
7
|
+
label: string;
|
|
8
|
+
onClick: () => void;
|
|
9
|
+
className?: string;
|
|
10
|
+
labelClassName?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function NavBarItem({ icon, label, onClick, className, labelClassName }: NavBarItemProps) {
|
|
14
|
+
return (
|
|
15
|
+
<div
|
|
16
|
+
className={cn(
|
|
17
|
+
'rounded-lg flex items-center gap-2 px-2 py-2 h-10 cursor-pointer transition-colors bg-white hover:bg-gray-100 active:bg-gray-50',
|
|
18
|
+
className
|
|
19
|
+
)}
|
|
20
|
+
onClick={onClick}
|
|
21
|
+
>
|
|
22
|
+
{icon}
|
|
23
|
+
<span className={cn('text-sm font-medium text-gray-950', labelClassName)}>{label}</span>
|
|
24
|
+
</div>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export { NavBarItem };
|
|
29
|
+
export type { NavBarItemProps };
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { ReactNode, useState } from 'react';
|
|
4
|
+
import { Bell } from 'lucide-react';
|
|
5
|
+
import { Popover, PopoverContent, PopoverTrigger } from '../ui/overlay/Popover';
|
|
6
|
+
import { Button } from '../ui/buttons/Button';
|
|
7
|
+
import { NotificationItem } from './NotificationItem';
|
|
8
|
+
import { cn } from '../../infra/utils/clsx';
|
|
9
|
+
|
|
10
|
+
export interface NotificationData {
|
|
11
|
+
icon: ReactNode;
|
|
12
|
+
iconBgColor: string;
|
|
13
|
+
title: string;
|
|
14
|
+
time: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface NotificationsPopoverProps {
|
|
18
|
+
notifications?: NotificationData[];
|
|
19
|
+
onViewAll?: () => void;
|
|
20
|
+
side?: 'top' | 'bottom' | 'left' | 'right';
|
|
21
|
+
align?: 'start' | 'center' | 'end';
|
|
22
|
+
contentClassName?: string;
|
|
23
|
+
badgeClassName?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function NotificationsPopover({
|
|
27
|
+
notifications = [],
|
|
28
|
+
onViewAll,
|
|
29
|
+
side,
|
|
30
|
+
align,
|
|
31
|
+
contentClassName,
|
|
32
|
+
badgeClassName = 'bg-pages-400',
|
|
33
|
+
}: NotificationsPopoverProps) {
|
|
34
|
+
const [open, setOpen] = useState(false);
|
|
35
|
+
const [hasNewNotifications, setHasNewNotifications] = useState(true);
|
|
36
|
+
|
|
37
|
+
const handleOpenChange = (isOpen: boolean) => {
|
|
38
|
+
setOpen(isOpen);
|
|
39
|
+
if (isOpen) setHasNewNotifications(false);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<Popover open={open} onOpenChange={handleOpenChange}>
|
|
44
|
+
<PopoverTrigger className="cursor-pointer">
|
|
45
|
+
<div
|
|
46
|
+
className={`relative rounded-full p-2.5 ${open ? 'bg-gray-100' : 'hover:bg-gray-100'}`}
|
|
47
|
+
>
|
|
48
|
+
<Bell size={20} className="text-gray-500" />
|
|
49
|
+
{hasNewNotifications && (
|
|
50
|
+
<span className={cn('absolute top-2 right-2 size-2.5 rounded-full', badgeClassName)} />
|
|
51
|
+
)}
|
|
52
|
+
</div>
|
|
53
|
+
</PopoverTrigger>
|
|
54
|
+
<PopoverContent
|
|
55
|
+
className={cn(
|
|
56
|
+
'absolute bottom-2 left-[26px] w-[308px] p-0 pt-4 bg-white rounded-2xl shadow-md border border-gray-200',
|
|
57
|
+
contentClassName
|
|
58
|
+
)}
|
|
59
|
+
side={side}
|
|
60
|
+
align={align}
|
|
61
|
+
sideOffset={8}
|
|
62
|
+
>
|
|
63
|
+
<span className="paragraph-small-semibold text-gray-950 px-4">Últimas notificações</span>
|
|
64
|
+
|
|
65
|
+
{notifications.length > 0 ? (
|
|
66
|
+
notifications.map((notification, index) => (
|
|
67
|
+
<NotificationItem
|
|
68
|
+
key={index}
|
|
69
|
+
icon={notification.icon}
|
|
70
|
+
iconBgColor={notification.iconBgColor}
|
|
71
|
+
title={notification.title}
|
|
72
|
+
time={notification.time}
|
|
73
|
+
showBorder={index < notifications.length - 1}
|
|
74
|
+
/>
|
|
75
|
+
))
|
|
76
|
+
) : (
|
|
77
|
+
<div className="flex flex-col items-center gap-4 pt-[41.5px] pb-[33.5px]">
|
|
78
|
+
<div className="bg-gray-50 rounded-md p-2.5">
|
|
79
|
+
<Bell size={20} color="var(--color-gray-950)" />
|
|
80
|
+
</div>
|
|
81
|
+
<span className="paragraph-small-medium text-gray-950">Sem notificações por enquanto</span>
|
|
82
|
+
</div>
|
|
83
|
+
)}
|
|
84
|
+
|
|
85
|
+
{onViewAll && (
|
|
86
|
+
<Button
|
|
87
|
+
variant="secondary"
|
|
88
|
+
className="h-8! mt-2 mb-4 mx-4 paragraph-small-semibold"
|
|
89
|
+
onClick={onViewAll}
|
|
90
|
+
>
|
|
91
|
+
Todas as notificações
|
|
92
|
+
</Button>
|
|
93
|
+
)}
|
|
94
|
+
</PopoverContent>
|
|
95
|
+
</Popover>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export { NotificationsPopover };
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { useRouter } from 'next/navigation';
|
|
5
|
+
import { Popover, PopoverContent, PopoverTrigger } from '../ui/overlay/Popover';
|
|
6
|
+
import { Button } from '../ui/buttons/Button';
|
|
7
|
+
import { Progress } from '../ui/feedback/Progress';
|
|
8
|
+
import { Separator } from '../ui/data-display/Separator';
|
|
9
|
+
import { NavBarItem } from './NavBarItem';
|
|
10
|
+
import { UserAvatar } from '../ui/data-display/UserAvatar';
|
|
11
|
+
import { useAuth } from '../../providers/auth.provider';
|
|
12
|
+
import { cn } from '../../infra/utils/clsx';
|
|
13
|
+
|
|
14
|
+
export interface ProfileMenuItem {
|
|
15
|
+
icon?: React.ReactNode;
|
|
16
|
+
label: string;
|
|
17
|
+
onClick: () => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ProfilePopoverProps {
|
|
21
|
+
side?: 'top' | 'bottom' | 'left' | 'right';
|
|
22
|
+
align?: 'start' | 'center' | 'end';
|
|
23
|
+
contentClassName?: string;
|
|
24
|
+
onEditProfile?: () => void;
|
|
25
|
+
credits?: { used: number; total: number };
|
|
26
|
+
onCreditsClick?: () => void;
|
|
27
|
+
menuItems?: ProfileMenuItem[];
|
|
28
|
+
logoutRedirect?: string;
|
|
29
|
+
storageUrl?: string;
|
|
30
|
+
logoutOverlay?: React.ReactNode;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function ProfilePopover({
|
|
34
|
+
side = 'top',
|
|
35
|
+
align = 'start',
|
|
36
|
+
contentClassName,
|
|
37
|
+
onEditProfile,
|
|
38
|
+
credits,
|
|
39
|
+
onCreditsClick,
|
|
40
|
+
menuItems = [],
|
|
41
|
+
logoutRedirect = '/login',
|
|
42
|
+
storageUrl,
|
|
43
|
+
logoutOverlay,
|
|
44
|
+
}: ProfilePopoverProps) {
|
|
45
|
+
const router = useRouter();
|
|
46
|
+
const { user, logout } = useAuth();
|
|
47
|
+
const [isLoggingOut, setIsLoggingOut] = useState(false);
|
|
48
|
+
|
|
49
|
+
const handleLogout = async () => {
|
|
50
|
+
try {
|
|
51
|
+
setIsLoggingOut(true);
|
|
52
|
+
await logout();
|
|
53
|
+
router.push(logoutRedirect);
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.error('Erro ao fazer logout:', error);
|
|
56
|
+
} finally {
|
|
57
|
+
setIsLoggingOut(false);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const creditsPercentage =
|
|
62
|
+
credits && credits.total > 0
|
|
63
|
+
? (credits.used / credits.total) * 100
|
|
64
|
+
: 0;
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<>
|
|
68
|
+
{isLoggingOut && logoutOverlay}
|
|
69
|
+
<Popover>
|
|
70
|
+
<PopoverTrigger className="cursor-pointer">
|
|
71
|
+
{user && (
|
|
72
|
+
<UserAvatar
|
|
73
|
+
key={user.id}
|
|
74
|
+
photo={user.photo}
|
|
75
|
+
name={user.name}
|
|
76
|
+
size={40}
|
|
77
|
+
storageUrl={storageUrl}
|
|
78
|
+
/>
|
|
79
|
+
)}
|
|
80
|
+
</PopoverTrigger>
|
|
81
|
+
|
|
82
|
+
<PopoverContent
|
|
83
|
+
className={cn(
|
|
84
|
+
'w-64.75 p-0 bg-white rounded-2xl shadow-md border border-gray-200 z-99',
|
|
85
|
+
contentClassName
|
|
86
|
+
)}
|
|
87
|
+
side={side}
|
|
88
|
+
align={align}
|
|
89
|
+
sideOffset={8}
|
|
90
|
+
>
|
|
91
|
+
<div className="grid grid-cols-[32px_1fr_auto] items-center gap-3 p-3 w-full">
|
|
92
|
+
{user && (
|
|
93
|
+
<UserAvatar
|
|
94
|
+
key={user.id}
|
|
95
|
+
photo={user.photo}
|
|
96
|
+
name={user.name}
|
|
97
|
+
size={32}
|
|
98
|
+
storageUrl={storageUrl}
|
|
99
|
+
/>
|
|
100
|
+
)}
|
|
101
|
+
|
|
102
|
+
<div className="flex flex-col gap-0.5 min-w-0">
|
|
103
|
+
<span className="paragraph-small-semibold text-gray-950 truncate">
|
|
104
|
+
{user?.name || ''}
|
|
105
|
+
</span>
|
|
106
|
+
<span className="paragraph-xsmall-medium text-gray-500 truncate">
|
|
107
|
+
{user?.email || ''}
|
|
108
|
+
</span>
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
{onEditProfile && (
|
|
112
|
+
<Button
|
|
113
|
+
variant="secondary"
|
|
114
|
+
className="paragraph-small-semibold h-8! whitespace-nowrap px-3 w-fit"
|
|
115
|
+
onClick={onEditProfile}
|
|
116
|
+
>
|
|
117
|
+
Editar Perfil
|
|
118
|
+
</Button>
|
|
119
|
+
)}
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
<div className="flex flex-col gap-2 border-t border-gray-200 rounded-2xl p-1.5">
|
|
123
|
+
{credits && (
|
|
124
|
+
<div
|
|
125
|
+
className={cn(
|
|
126
|
+
'flex flex-col bg-gray-950 rounded-lg gap-4 w-full p-4 transition-colors',
|
|
127
|
+
onCreditsClick && 'cursor-pointer hover:bg-gray-900'
|
|
128
|
+
)}
|
|
129
|
+
onClick={onCreditsClick}
|
|
130
|
+
>
|
|
131
|
+
<div className="flex items-center justify-between gap-2">
|
|
132
|
+
<span className="paragraph-xsmall-semibold text-white truncate">
|
|
133
|
+
Créditos usados
|
|
134
|
+
</span>
|
|
135
|
+
<span className="paragraph-xsmall-medium text-white/50">
|
|
136
|
+
{credits.used.toLocaleString('pt-BR')}/
|
|
137
|
+
{credits.total.toLocaleString('pt-BR')}
|
|
138
|
+
</span>
|
|
139
|
+
</div>
|
|
140
|
+
<Progress
|
|
141
|
+
className="bg-white/10"
|
|
142
|
+
indicatorColor="bg-white"
|
|
143
|
+
value={creditsPercentage}
|
|
144
|
+
/>
|
|
145
|
+
</div>
|
|
146
|
+
)}
|
|
147
|
+
|
|
148
|
+
<div className="flex flex-col gap-2">
|
|
149
|
+
{menuItems.length > 0 && (
|
|
150
|
+
<div className="flex flex-col">
|
|
151
|
+
{menuItems.map((item, index) => (
|
|
152
|
+
<NavBarItem
|
|
153
|
+
key={index}
|
|
154
|
+
icon={item.icon}
|
|
155
|
+
label={item.label}
|
|
156
|
+
onClick={item.onClick}
|
|
157
|
+
/>
|
|
158
|
+
))}
|
|
159
|
+
</div>
|
|
160
|
+
)}
|
|
161
|
+
<Separator />
|
|
162
|
+
<NavBarItem label="Sair" onClick={handleLogout} />
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
</PopoverContent>
|
|
166
|
+
</Popover>
|
|
167
|
+
</>
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export { ProfilePopover };
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { Plus, Settings, User } from 'lucide-react';
|
|
5
|
+
import Image from 'next/image';
|
|
6
|
+
import { useRouter } from 'next/navigation';
|
|
7
|
+
import { Popover, PopoverContent, PopoverTrigger } from '../ui/overlay/Popover';
|
|
8
|
+
import { Button } from '../ui/buttons/Button';
|
|
9
|
+
import { Command, CommandEmpty, CommandInput, CommandItem, CommandList } from '../ui/overlay/Command';
|
|
10
|
+
import { Checkbox } from '../ui/form/Checkbox';
|
|
11
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/overlay/Tooltip';
|
|
12
|
+
import { cn } from '../../infra/utils/clsx';
|
|
13
|
+
|
|
14
|
+
export interface UserSelectorItem {
|
|
15
|
+
id: number;
|
|
16
|
+
name: string;
|
|
17
|
+
avatar: string;
|
|
18
|
+
checked: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface UsersSelectorPopoverProps {
|
|
22
|
+
users?: UserSelectorItem[];
|
|
23
|
+
onToggleUser?: (id: number) => void;
|
|
24
|
+
addRoute?: string;
|
|
25
|
+
manageRoute?: string;
|
|
26
|
+
userCount?: number;
|
|
27
|
+
side?: 'top' | 'bottom' | 'left' | 'right';
|
|
28
|
+
align?: 'start' | 'center' | 'end';
|
|
29
|
+
contentClassName?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function UsersSelectorPopover({
|
|
33
|
+
users: externalUsers,
|
|
34
|
+
onToggleUser,
|
|
35
|
+
addRoute = '/my-teams?createNew=true',
|
|
36
|
+
manageRoute = '/my-teams',
|
|
37
|
+
userCount = 5,
|
|
38
|
+
side,
|
|
39
|
+
align,
|
|
40
|
+
contentClassName,
|
|
41
|
+
}: UsersSelectorPopoverProps) {
|
|
42
|
+
const route = useRouter();
|
|
43
|
+
const [open, setOpen] = useState(false);
|
|
44
|
+
const [internalUsers, setInternalUsers] = useState<UserSelectorItem[]>(externalUsers ?? []);
|
|
45
|
+
const [hoveredId, setHoveredId] = useState<number | null>(null);
|
|
46
|
+
|
|
47
|
+
const users = externalUsers ?? internalUsers;
|
|
48
|
+
|
|
49
|
+
const toggleUser = (id: number) => {
|
|
50
|
+
if (onToggleUser) {
|
|
51
|
+
onToggleUser(id);
|
|
52
|
+
} else {
|
|
53
|
+
setInternalUsers((prev) =>
|
|
54
|
+
prev.map((u) => (u.id === id ? { ...u, checked: !u.checked } : u))
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<Popover open={open} onOpenChange={setOpen}>
|
|
61
|
+
<PopoverTrigger className="cursor-pointer">
|
|
62
|
+
<div className="flex items-center gap-2 text-gray-950 px-3 py-2 border border-gray-200 rounded-full hover:border-gray-950">
|
|
63
|
+
<span className="paragraph-small-semibold">{userCount}</span>
|
|
64
|
+
<User size={16} />
|
|
65
|
+
</div>
|
|
66
|
+
</PopoverTrigger>
|
|
67
|
+
|
|
68
|
+
<PopoverContent
|
|
69
|
+
className={cn(
|
|
70
|
+
'absolute right-[-88px] w-[273px] p-0 bg-white rounded-2xl shadow-md border border-gray-200',
|
|
71
|
+
contentClassName
|
|
72
|
+
)}
|
|
73
|
+
side={side}
|
|
74
|
+
align={align}
|
|
75
|
+
sideOffset={8}
|
|
76
|
+
>
|
|
77
|
+
<div className="flex flex-col p-3 gap-2">
|
|
78
|
+
<div className="flex items-center justify-between">
|
|
79
|
+
<span className="paragraph-small-semibold">Usuários</span>
|
|
80
|
+
<div className="flex items-center gap-1.5">
|
|
81
|
+
<Button
|
|
82
|
+
variant="secondary"
|
|
83
|
+
className="h-8 paragraph-small-semibold text-gray-950"
|
|
84
|
+
onClick={() => route.push(addRoute)}
|
|
85
|
+
>
|
|
86
|
+
<Plus size={16} />
|
|
87
|
+
Adicionar
|
|
88
|
+
</Button>
|
|
89
|
+
|
|
90
|
+
<Tooltip>
|
|
91
|
+
<TooltipTrigger asChild>
|
|
92
|
+
<Button
|
|
93
|
+
variant="secondary"
|
|
94
|
+
className="p-0 size-8"
|
|
95
|
+
onClick={() => route.push(manageRoute)}
|
|
96
|
+
>
|
|
97
|
+
<Settings size={18} />
|
|
98
|
+
</Button>
|
|
99
|
+
</TooltipTrigger>
|
|
100
|
+
<TooltipContent>Visualizar todos usuários</TooltipContent>
|
|
101
|
+
</Tooltip>
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
|
|
105
|
+
<Command className="gap-2" value="">
|
|
106
|
+
<CommandInput placeholder="Busque aqui" />
|
|
107
|
+
<CommandList className="custom-scrollbar paragraph-small-medium text-gray-600 h-[162px]">
|
|
108
|
+
<CommandEmpty>No results found.</CommandEmpty>
|
|
109
|
+
{users.map((user) => (
|
|
110
|
+
<CommandItem
|
|
111
|
+
key={user.id}
|
|
112
|
+
autoFocus={false}
|
|
113
|
+
onPointerEnter={() => setHoveredId(user.id)}
|
|
114
|
+
onPointerLeave={() => setHoveredId(null)}
|
|
115
|
+
onFocus={() => setHoveredId(user.id)}
|
|
116
|
+
onBlur={() => setHoveredId(null)}
|
|
117
|
+
onSelect={() => toggleUser(user.id)}
|
|
118
|
+
className="cursor-pointer"
|
|
119
|
+
>
|
|
120
|
+
<div className="flex items-center justify-between w-full">
|
|
121
|
+
<div className="flex items-center gap-2">
|
|
122
|
+
<Image
|
|
123
|
+
alt="Avatar"
|
|
124
|
+
src={user.avatar}
|
|
125
|
+
width={32}
|
|
126
|
+
height={32}
|
|
127
|
+
className="rounded-full"
|
|
128
|
+
/>
|
|
129
|
+
{user.name}
|
|
130
|
+
</div>
|
|
131
|
+
|
|
132
|
+
<Tooltip open={hoveredId === user.id}>
|
|
133
|
+
<TooltipTrigger
|
|
134
|
+
onClick={(e) => e.stopPropagation()}
|
|
135
|
+
onPointerDown={(e) => e.stopPropagation()}
|
|
136
|
+
>
|
|
137
|
+
<Checkbox
|
|
138
|
+
checked={user.checked}
|
|
139
|
+
onCheckedChange={() => toggleUser(user.id)}
|
|
140
|
+
className={hoveredId === user.id ? 'border-gray-950' : ''}
|
|
141
|
+
/>
|
|
142
|
+
</TooltipTrigger>
|
|
143
|
+
<TooltipContent>
|
|
144
|
+
{user.checked ? 'Remover do projeto' : 'Adicionar ao projeto'}
|
|
145
|
+
</TooltipContent>
|
|
146
|
+
</Tooltip>
|
|
147
|
+
</div>
|
|
148
|
+
</CommandItem>
|
|
149
|
+
))}
|
|
150
|
+
</CommandList>
|
|
151
|
+
</Command>
|
|
152
|
+
</div>
|
|
153
|
+
</PopoverContent>
|
|
154
|
+
</Popover>
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export { UsersSelectorPopover };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import Image from 'next/image';
|
|
4
|
+
import { cn } from '../../../infra/utils/clsx';
|
|
5
|
+
|
|
6
|
+
function getInitials(name: string, maxLength: number = 2): string {
|
|
7
|
+
return name
|
|
8
|
+
.split(' ')
|
|
9
|
+
.map((n) => n[0])
|
|
10
|
+
.join('')
|
|
11
|
+
.slice(0, maxLength)
|
|
12
|
+
.toUpperCase();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface UserAvatarProps {
|
|
16
|
+
photo?: string | null;
|
|
17
|
+
name?: string;
|
|
18
|
+
initials?: string;
|
|
19
|
+
size?: number;
|
|
20
|
+
shape?: 'circle' | 'square';
|
|
21
|
+
className?: string;
|
|
22
|
+
storageUrl?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function UserAvatar({
|
|
26
|
+
photo,
|
|
27
|
+
name,
|
|
28
|
+
initials,
|
|
29
|
+
size = 32,
|
|
30
|
+
shape = 'circle',
|
|
31
|
+
className,
|
|
32
|
+
storageUrl,
|
|
33
|
+
}: UserAvatarProps) {
|
|
34
|
+
const shapeClass = shape === 'circle' ? 'rounded-full' : 'rounded-lg';
|
|
35
|
+
const displayInitials = initials || (name ? getInitials(name) : '?');
|
|
36
|
+
|
|
37
|
+
const photoUrl = storageUrl && photo ? `${storageUrl}/${photo}` : photo;
|
|
38
|
+
|
|
39
|
+
if (photoUrl) {
|
|
40
|
+
return (
|
|
41
|
+
<Image
|
|
42
|
+
alt={name || 'imagem do usuario'}
|
|
43
|
+
src={photoUrl}
|
|
44
|
+
width={size}
|
|
45
|
+
height={size}
|
|
46
|
+
className={cn('object-cover shrink-0', shapeClass, className)}
|
|
47
|
+
style={{ width: size, height: size }}
|
|
48
|
+
/>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<div
|
|
54
|
+
className={cn(
|
|
55
|
+
'flex items-center justify-center shrink-0 bg-gray-100',
|
|
56
|
+
shapeClass,
|
|
57
|
+
className
|
|
58
|
+
)}
|
|
59
|
+
style={{ width: size, height: size }}
|
|
60
|
+
>
|
|
61
|
+
<span className="text-xs font-semibold text-gray-700">{displayInitials}</span>
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export { UserAvatar };
|
|
67
|
+
export type { UserAvatarProps };
|
package/src/index.ts
CHANGED
|
@@ -33,6 +33,57 @@ export { SideBarNavigation } from './components/layouts/SideBarNavigation';
|
|
|
33
33
|
export { MdSideBarNavigation } from './components/layouts/MdSideBarNavigation';
|
|
34
34
|
export { NotificationItem } from './components/layouts/NotificationItem';
|
|
35
35
|
export type { NotificationItemProps } from './components/layouts/NotificationItem';
|
|
36
|
+
export { NotificationsPopover } from './components/layouts/NotificationsPopover';
|
|
37
|
+
export type { NotificationsPopoverProps, NotificationData } from './components/layouts/NotificationsPopover';
|
|
38
|
+
export { UsersSelectorPopover } from './components/layouts/UsersSelectorPopover';
|
|
39
|
+
export type { UsersSelectorPopoverProps, UserSelectorItem } from './components/layouts/UsersSelectorPopover';
|
|
40
|
+
export { ProfilePopover } from './components/layouts/ProfilePopover';
|
|
41
|
+
export type { ProfilePopoverProps, ProfileMenuItem } from './components/layouts/ProfilePopover';
|
|
42
|
+
export { NavBarItem } from './components/layouts/NavBarItem';
|
|
43
|
+
export type { NavBarItemProps } from './components/layouts/NavBarItem';
|
|
44
|
+
|
|
45
|
+
// UI - Buttons
|
|
46
|
+
export { Button, buttonVariants } from './components/ui/buttons/Button';
|
|
47
|
+
export { CopyButton } from './components/ui/buttons/CopyButton';
|
|
48
|
+
export { default as CancelButton } from './components/ui/buttons/CancelButton';
|
|
49
|
+
|
|
50
|
+
// UI - Data Display
|
|
51
|
+
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from './components/ui/data-display/Accordion';
|
|
52
|
+
export { Badge, badgeVariants } from './components/ui/data-display/Badge';
|
|
53
|
+
export { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent } from './components/ui/data-display/Card';
|
|
54
|
+
export { Pagination, PaginationContent, PaginationLink, PaginationItem, PaginationPrevious, PaginationNext, PaginationEllipsis } from './components/ui/data-display/Pagination';
|
|
55
|
+
export { ScrollArea, ScrollBar } from './components/ui/data-display/ScrollArea';
|
|
56
|
+
export { Separator } from './components/ui/data-display/Separator';
|
|
57
|
+
export { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption } from './components/ui/data-display/Table';
|
|
58
|
+
export { Tabs, TabsList, TabsTrigger, TabsContent } from './components/ui/data-display/Tabs';
|
|
59
|
+
export { UserAvatar } from './components/ui/data-display/UserAvatar';
|
|
60
|
+
export type { UserAvatarProps } from './components/ui/data-display/UserAvatar';
|
|
61
|
+
|
|
62
|
+
// UI - Feedback
|
|
63
|
+
export { default as CircularProgress } from './components/ui/feedback/CircularProgress';
|
|
64
|
+
export { default as DefaultCircularProgress } from './components/ui/feedback/DefaultCircularProgress';
|
|
65
|
+
export { Progress } from './components/ui/feedback/Progress';
|
|
66
|
+
export { Toast, toastVariants, toastIconContainerVariants } from './components/ui/feedback/Toast';
|
|
67
|
+
export type { ToastProps } from './components/ui/feedback/Toast';
|
|
68
|
+
|
|
69
|
+
// UI - Form
|
|
70
|
+
export { Calendar, CalendarDayButton } from './components/ui/form/Calendar';
|
|
71
|
+
export { Checkbox } from './components/ui/form/Checkbox';
|
|
72
|
+
export { DatePicker } from './components/ui/form/DatePicker';
|
|
73
|
+
export { DateRangePicker } from './components/ui/form/DateRangePicker';
|
|
74
|
+
export { Input } from './components/ui/form/Input';
|
|
75
|
+
export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator } from './components/ui/form/InputOtp';
|
|
76
|
+
export { RadioGroup, RadioGroupItem } from './components/ui/form/RadioGroup';
|
|
77
|
+
export { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue } from './components/ui/form/Select';
|
|
78
|
+
export { Switch } from './components/ui/form/Switch';
|
|
79
|
+
export { Textarea } from './components/ui/form/Textarea';
|
|
80
|
+
|
|
81
|
+
// UI - Overlay
|
|
82
|
+
export { Command, CommandDialog, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandShortcut, CommandSeparator } from './components/ui/overlay/Command';
|
|
83
|
+
export { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger } from './components/ui/overlay/Dialog';
|
|
84
|
+
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor } from './components/ui/overlay/Popover';
|
|
85
|
+
export { Sheet, SheetTrigger, SheetClose, SheetContent, SheetHeader, SheetFooter, SheetTitle, SheetDescription } from './components/ui/overlay/Sheet';
|
|
86
|
+
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from './components/ui/overlay/Tooltip';
|
|
36
87
|
|
|
37
88
|
// Store
|
|
38
89
|
export { useMdSidebarStore } from './store/useMdSidebarStore';
|