@tree-ia/design-system 1.6.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +197 -4
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1091 -111
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import React, { createContext, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
1
|
+
import React, { cloneElement, createContext, isValidElement, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { createPortal } from "react-dom";
|
|
4
|
-
import { AlertCircle, AlertOctagon, AlertTriangle, ArrowDown, ArrowUp, ArrowUpDown, Check, CheckCircle, ChevronDown, ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, Copy, File, GripVertical, Image, Inbox, Info, Lightbulb, LogOut, Monitor, Moon, Search, ShieldAlert, Sun, Upload, User, X, XCircle } from "lucide-react";
|
|
4
|
+
import { AlertCircle, AlertOctagon, AlertTriangle, ArrowDown, ArrowUp, ArrowUpDown, Building2, Check, CheckCircle, ChevronDown, ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, Copy, File, GripVertical, Image, Inbox, Info, Lightbulb, LogOut, Menu, Monitor, Moon, Search, ShieldAlert, Sun, Upload, User, X, XCircle } from "lucide-react";
|
|
5
5
|
import { Bar, Doughnut, Line } from "react-chartjs-2";
|
|
6
6
|
import { ArcElement, BarElement, CategoryScale, Chart, Filler, Legend, LineElement, LinearScale, PointElement, Title as Title$1, Tooltip as Tooltip$1 } from "chart.js";
|
|
7
7
|
import { createColumnHelper, flexRender, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable } from "@tanstack/react-table";
|
|
@@ -35,7 +35,7 @@ function Loading({ size = "md", className = "", text, textColor, color, variant
|
|
|
35
35
|
|
|
36
36
|
//#endregion
|
|
37
37
|
//#region src/components/Button/index.tsx
|
|
38
|
-
const cn$
|
|
38
|
+
const cn$34 = (...classes) => classes.filter(Boolean).join(" ");
|
|
39
39
|
function Button({ children, variant = "primary", size = "md", isLoading = false, icon, iconPosition = "left", className, disabled, ...props }) {
|
|
40
40
|
const baseStyles = "font-medium rounded-lg transition-all duration-200 ease-out cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed inline-flex items-center justify-center focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--dashboard-primary,#2563EB)] active:scale-[0.97]";
|
|
41
41
|
const variantStyles = {
|
|
@@ -45,18 +45,18 @@ function Button({ children, variant = "primary", size = "md", isLoading = false,
|
|
|
45
45
|
ghost: "bg-transparent hover:bg-[var(--dashboard-text-secondary,#64748B)]/8 text-[var(--dashboard-text-primary,#0F172A)]"
|
|
46
46
|
};
|
|
47
47
|
const sizeStyles = {
|
|
48
|
-
sm: "px-2
|
|
49
|
-
md: "px-3
|
|
50
|
-
lg: "px-4
|
|
48
|
+
sm: "h-8 px-2 text-xs sm:px-3 sm:text-sm",
|
|
49
|
+
md: "h-9 px-3 text-sm sm:px-4 sm:text-base",
|
|
50
|
+
lg: "h-10 px-4 text-base sm:px-6 sm:text-lg"
|
|
51
51
|
};
|
|
52
52
|
const iconOnlySizeStyles = {
|
|
53
|
-
sm: "
|
|
54
|
-
md: "
|
|
55
|
-
lg: "
|
|
53
|
+
sm: "h-8 w-8",
|
|
54
|
+
md: "h-9 w-9",
|
|
55
|
+
lg: "h-10 w-10"
|
|
56
56
|
};
|
|
57
57
|
const isIconOnly = !!icon && (children === void 0 || children === null || typeof children === "string" && children.trim() === "");
|
|
58
58
|
return /* @__PURE__ */ jsx("button", {
|
|
59
|
-
className: cn$
|
|
59
|
+
className: cn$34(baseStyles, variantStyles[variant], isIconOnly ? iconOnlySizeStyles[size] : sizeStyles[size], className),
|
|
60
60
|
disabled: disabled || isLoading,
|
|
61
61
|
...props,
|
|
62
62
|
children: isLoading ? /* @__PURE__ */ jsxs("span", {
|
|
@@ -81,8 +81,13 @@ function Button({ children, variant = "primary", size = "md", isLoading = false,
|
|
|
81
81
|
|
|
82
82
|
//#endregion
|
|
83
83
|
//#region src/components/Input/index.tsx
|
|
84
|
-
const cn$
|
|
85
|
-
const
|
|
84
|
+
const cn$33 = (...classes) => classes.filter(Boolean).join(" ");
|
|
85
|
+
const sizeStyles = {
|
|
86
|
+
sm: "h-8 px-2.5 text-xs",
|
|
87
|
+
md: "h-9 px-3 text-sm",
|
|
88
|
+
lg: "h-10 px-4 text-base"
|
|
89
|
+
};
|
|
90
|
+
const Input = React.forwardRef(({ className, type = "text", label, error, children, id, size = "md", ...props }, ref) => {
|
|
86
91
|
const inputId = id || (label ? `input-${label.toLowerCase().replace(/\s+/g, "-")}` : void 0);
|
|
87
92
|
return /* @__PURE__ */ jsxs("div", {
|
|
88
93
|
className: "w-full",
|
|
@@ -97,7 +102,7 @@ const Input = React.forwardRef(({ className, type = "text", label, error, childr
|
|
|
97
102
|
children: [/* @__PURE__ */ jsx("input", {
|
|
98
103
|
type,
|
|
99
104
|
id: inputId,
|
|
100
|
-
className: cn$
|
|
105
|
+
className: cn$33("flex w-full rounded-md border border-[var(--dashboard-text-secondary,#6b7280)]/30 bg-[var(--dashboard-surface,#ffffff)] text-[var(--dashboard-text-primary,#2d2d2d)] shadow-sm transition-colors duration-200 focus:border-[var(--dashboard-primary,#37a501)] placeholder:text-[var(--dashboard-text-secondary,#6b7280)] focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50", sizeStyles[size], error ? "border-[var(--dashboard-status-danger,#EF4444)] focus:border-[var(--dashboard-status-danger,#EF4444)]" : void 0, children ? "pr-10" : void 0, className),
|
|
101
106
|
ref,
|
|
102
107
|
...props
|
|
103
108
|
}), children && /* @__PURE__ */ jsx("div", {
|
|
@@ -116,7 +121,7 @@ Input.displayName = "Input";
|
|
|
116
121
|
|
|
117
122
|
//#endregion
|
|
118
123
|
//#region src/components/Dropdown/index.tsx
|
|
119
|
-
function Dropdown({ options, value, onChange, label, placeholder = "Selecione uma opção", disabled = false, className = "", containerClassName = "", fullWidth = false, size = "
|
|
124
|
+
function Dropdown({ options, value, onChange, label, placeholder = "Selecione uma opção", disabled = false, className = "", containerClassName = "", fullWidth = false, size = "md", error, variant = "default", customDropdownHeight, icon, fitContent = false, isActive = false }) {
|
|
120
125
|
const [isOpen, setIsOpen] = useState(false);
|
|
121
126
|
const [isVisible, setIsVisible] = useState(false);
|
|
122
127
|
const [position, setPosition] = useState({
|
|
@@ -127,23 +132,23 @@ function Dropdown({ options, value, onChange, label, placeholder = "Selecione um
|
|
|
127
132
|
const dropdownRef = useRef(null);
|
|
128
133
|
const selectedOption = options.find((option) => option.value === value);
|
|
129
134
|
const selectedStyle = {
|
|
130
|
-
|
|
131
|
-
container: "h-8 px-2",
|
|
135
|
+
sm: {
|
|
136
|
+
container: "h-8 px-2.5",
|
|
132
137
|
text: "text-xs",
|
|
133
138
|
wrapper: "space-y-1",
|
|
134
139
|
label: "text-sm",
|
|
135
140
|
iconPadding: "pl-8"
|
|
136
141
|
},
|
|
137
|
-
|
|
138
|
-
container: "h-
|
|
142
|
+
md: {
|
|
143
|
+
container: "h-9 px-3",
|
|
139
144
|
text: "text-sm",
|
|
140
145
|
wrapper: "space-y-2",
|
|
141
146
|
label: "text-base",
|
|
142
147
|
iconPadding: "pl-10"
|
|
143
148
|
},
|
|
144
|
-
|
|
145
|
-
container: "h-
|
|
146
|
-
text: "text-
|
|
149
|
+
lg: {
|
|
150
|
+
container: "h-10 px-4",
|
|
151
|
+
text: "text-base",
|
|
147
152
|
wrapper: "space-y-3",
|
|
148
153
|
label: "text-lg",
|
|
149
154
|
iconPadding: "pl-12"
|
|
@@ -362,13 +367,14 @@ function TableEmpty({ message, icon }) {
|
|
|
362
367
|
//#region src/components/Modal/index.tsx
|
|
363
368
|
const ANIMATION_MS = 200;
|
|
364
369
|
const sizeClasses$2 = {
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
+
sm: "max-w-sm",
|
|
371
|
+
md: "max-w-md",
|
|
372
|
+
lg: "max-w-lg",
|
|
373
|
+
xl: "max-w-2xl",
|
|
374
|
+
"2xl": "max-w-4xl",
|
|
375
|
+
"3xl": "max-w-screen-xl"
|
|
370
376
|
};
|
|
371
|
-
function Modal({ isOpen, onClose, onSave, title = "", children, showFooter = false, saveButtonText = "Salvar", cancelButtonText = "Cancelar", size = "
|
|
377
|
+
function Modal({ isOpen, onClose, onSave, title = "", children, showFooter = false, saveButtonText = "Salvar", cancelButtonText = "Cancelar", size = "md", disableSaveButton = false, saveButtonVariant = "primary", closeOnEscape = true, closeOnOverlayClick = true }) {
|
|
372
378
|
const [shouldRender, setShouldRender] = useState(false);
|
|
373
379
|
const modalRef = useRef(null);
|
|
374
380
|
if (isOpen && !shouldRender) setShouldRender(true);
|
|
@@ -619,7 +625,7 @@ function Pagination({ currentPage, totalPages, onPageChange, itemsPerPage, total
|
|
|
619
625
|
options: dropdownOptions,
|
|
620
626
|
value: String(itemsPerPage),
|
|
621
627
|
onChange: (val) => onItemsPerPageChange(Number(val)),
|
|
622
|
-
size: "
|
|
628
|
+
size: "sm",
|
|
623
629
|
variant: "compact",
|
|
624
630
|
fitContent: true
|
|
625
631
|
}), /* @__PURE__ */ jsx("span", {
|
|
@@ -751,16 +757,16 @@ function FormField({ label, name, type = "text", value, onChange, error, require
|
|
|
751
757
|
|
|
752
758
|
//#endregion
|
|
753
759
|
//#region src/components/Tabs/index.tsx
|
|
754
|
-
const cn$
|
|
760
|
+
const cn$32 = (...classes) => classes.filter(Boolean).join(" ");
|
|
755
761
|
function Tabs({ tabs, activeTab, onChange, variant = "underline", className }) {
|
|
756
762
|
if (variant === "pill") return /* @__PURE__ */ jsx("div", {
|
|
757
|
-
className: cn$
|
|
763
|
+
className: cn$32("flex flex-wrap gap-2", className),
|
|
758
764
|
role: "tablist",
|
|
759
765
|
children: tabs.map((tab) => {
|
|
760
766
|
const isActive = activeTab === tab.id;
|
|
761
767
|
return /* @__PURE__ */ jsxs("button", {
|
|
762
768
|
onClick: () => onChange(tab.id),
|
|
763
|
-
className: cn$
|
|
769
|
+
className: cn$32("flex items-center gap-2 px-4 py-2 rounded-full text-sm font-medium transition-colors cursor-pointer", isActive ? "bg-[var(--dashboard-primary,#37a501)] text-white" : "bg-[var(--dashboard-text-secondary,#6b7280)]/10 text-[var(--dashboard-text-secondary,#6b7280)] hover:bg-[var(--dashboard-text-secondary,#6b7280)]/20"),
|
|
764
770
|
role: "tab",
|
|
765
771
|
"aria-selected": isActive,
|
|
766
772
|
children: [
|
|
@@ -770,7 +776,7 @@ function Tabs({ tabs, activeTab, onChange, variant = "underline", className }) {
|
|
|
770
776
|
}),
|
|
771
777
|
tab.label,
|
|
772
778
|
tab.count !== void 0 && /* @__PURE__ */ jsx("span", {
|
|
773
|
-
className: cn$
|
|
779
|
+
className: cn$32("ml-1 text-xs rounded-full px-1.5 py-0.5", isActive ? "bg-white/20 text-white" : "bg-[var(--dashboard-text-secondary,#6b7280)]/10 text-[var(--dashboard-text-secondary,#6b7280)]"),
|
|
774
780
|
children: tab.count
|
|
775
781
|
})
|
|
776
782
|
]
|
|
@@ -778,7 +784,7 @@ function Tabs({ tabs, activeTab, onChange, variant = "underline", className }) {
|
|
|
778
784
|
})
|
|
779
785
|
});
|
|
780
786
|
return /* @__PURE__ */ jsx("div", {
|
|
781
|
-
className: cn$
|
|
787
|
+
className: cn$32("border-b border-[var(--dashboard-text-secondary,#6b7280)]/20", className),
|
|
782
788
|
children: /* @__PURE__ */ jsx("nav", {
|
|
783
789
|
className: "flex gap-6",
|
|
784
790
|
"aria-label": "Tabs",
|
|
@@ -786,7 +792,7 @@ function Tabs({ tabs, activeTab, onChange, variant = "underline", className }) {
|
|
|
786
792
|
const isActive = activeTab === tab.id;
|
|
787
793
|
return /* @__PURE__ */ jsxs("button", {
|
|
788
794
|
onClick: () => onChange(tab.id),
|
|
789
|
-
className: cn$
|
|
795
|
+
className: cn$32("relative pb-3 px-1 text-sm font-medium transition-colors border-b-2 flex items-center gap-2 cursor-pointer", isActive ? "text-[var(--dashboard-primary,#37a501)] border-[var(--dashboard-primary,#37a501)]" : "text-[var(--dashboard-text-secondary,#6b7280)] hover:text-[var(--dashboard-text-primary,#2d2d2d)] border-transparent"),
|
|
790
796
|
role: "tab",
|
|
791
797
|
"aria-selected": isActive,
|
|
792
798
|
children: [
|
|
@@ -796,7 +802,7 @@ function Tabs({ tabs, activeTab, onChange, variant = "underline", className }) {
|
|
|
796
802
|
}),
|
|
797
803
|
tab.label,
|
|
798
804
|
tab.count !== void 0 && /* @__PURE__ */ jsx("span", {
|
|
799
|
-
className: cn$
|
|
805
|
+
className: cn$32("ml-1 text-xs rounded-full px-1.5 py-0.5", isActive ? "bg-[var(--dashboard-primary,#37a501)]/10 text-[var(--dashboard-primary,#37a501)]" : "bg-[var(--dashboard-text-secondary,#6b7280)]/10 text-[var(--dashboard-text-secondary,#6b7280)]"),
|
|
800
806
|
children: tab.count
|
|
801
807
|
})
|
|
802
808
|
]
|
|
@@ -808,8 +814,8 @@ function Tabs({ tabs, activeTab, onChange, variant = "underline", className }) {
|
|
|
808
814
|
|
|
809
815
|
//#endregion
|
|
810
816
|
//#region src/components/DateRangePicker/index.tsx
|
|
811
|
-
const cn$
|
|
812
|
-
const locales = {
|
|
817
|
+
const cn$31 = (...classes) => classes.filter(Boolean).join(" ");
|
|
818
|
+
const locales$1 = {
|
|
813
819
|
pt: {
|
|
814
820
|
months: [
|
|
815
821
|
"Janeiro",
|
|
@@ -867,7 +873,7 @@ const locales = {
|
|
|
867
873
|
};
|
|
868
874
|
function DateRangePicker({ value, onChange, locale = "pt", className }) {
|
|
869
875
|
const [currentMonth, setCurrentMonth] = useState(/* @__PURE__ */ new Date());
|
|
870
|
-
const l = locales[locale];
|
|
876
|
+
const l = locales$1[locale];
|
|
871
877
|
const getDaysInMonth = (date) => {
|
|
872
878
|
const year = date.getFullYear();
|
|
873
879
|
const month = date.getMonth();
|
|
@@ -915,7 +921,7 @@ function DateRangePicker({ value, onChange, locale = "pt", className }) {
|
|
|
915
921
|
};
|
|
916
922
|
const days = getDaysInMonth(currentMonth);
|
|
917
923
|
return /* @__PURE__ */ jsxs("div", {
|
|
918
|
-
className: cn$
|
|
924
|
+
className: cn$31("w-64 bg-[var(--dashboard-surface,#ffffff)] rounded-lg p-4 shadow-sm border border-[var(--dashboard-text-secondary,#6b7280)]/20", className),
|
|
919
925
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
920
926
|
className: "flex items-center justify-between mb-4",
|
|
921
927
|
children: [
|
|
@@ -953,9 +959,9 @@ function DateRangePicker({ value, onChange, locale = "pt", className }) {
|
|
|
953
959
|
const isSelected = isStart || isEnd;
|
|
954
960
|
return /* @__PURE__ */ jsxs("div", {
|
|
955
961
|
className: "relative h-8 w-8",
|
|
956
|
-
children: [value.start && value.end && (inRange || isStart || isEnd) && /* @__PURE__ */ jsx("div", { className: cn$
|
|
962
|
+
children: [value.start && value.end && (inRange || isStart || isEnd) && /* @__PURE__ */ jsx("div", { className: cn$31("absolute inset-0 bg-[var(--dashboard-text-secondary,#6b7280)]/10", isStart && "rounded-l-full", isEnd && "rounded-r-full") }), /* @__PURE__ */ jsx("button", {
|
|
957
963
|
onClick: () => handleDayClick(day),
|
|
958
|
-
className: cn$
|
|
964
|
+
className: cn$31("relative h-8 w-8 flex items-center justify-center text-xs font-medium transition-colors z-10 rounded-full cursor-pointer", isSelected ? "bg-[var(--dashboard-primary,#37a501)] text-white hover:opacity-90" : "text-[var(--dashboard-text-primary,#2d2d2d)] hover:bg-[var(--dashboard-text-secondary,#6b7280)]/20"),
|
|
959
965
|
children: day
|
|
960
966
|
})]
|
|
961
967
|
}, day);
|
|
@@ -964,9 +970,157 @@ function DateRangePicker({ value, onChange, locale = "pt", className }) {
|
|
|
964
970
|
});
|
|
965
971
|
}
|
|
966
972
|
|
|
973
|
+
//#endregion
|
|
974
|
+
//#region src/components/DatePicker/index.tsx
|
|
975
|
+
const cn$30 = (...classes) => classes.filter(Boolean).join(" ");
|
|
976
|
+
const locales = {
|
|
977
|
+
pt: {
|
|
978
|
+
months: [
|
|
979
|
+
"Janeiro",
|
|
980
|
+
"Fevereiro",
|
|
981
|
+
"Março",
|
|
982
|
+
"Abril",
|
|
983
|
+
"Maio",
|
|
984
|
+
"Junho",
|
|
985
|
+
"Julho",
|
|
986
|
+
"Agosto",
|
|
987
|
+
"Setembro",
|
|
988
|
+
"Outubro",
|
|
989
|
+
"Novembro",
|
|
990
|
+
"Dezembro"
|
|
991
|
+
],
|
|
992
|
+
weekDays: [
|
|
993
|
+
"D",
|
|
994
|
+
"S",
|
|
995
|
+
"T",
|
|
996
|
+
"Q",
|
|
997
|
+
"Q",
|
|
998
|
+
"S",
|
|
999
|
+
"S"
|
|
1000
|
+
],
|
|
1001
|
+
prevMonth: "Mês anterior",
|
|
1002
|
+
nextMonth: "Próximo mês"
|
|
1003
|
+
},
|
|
1004
|
+
en: {
|
|
1005
|
+
months: [
|
|
1006
|
+
"January",
|
|
1007
|
+
"February",
|
|
1008
|
+
"March",
|
|
1009
|
+
"April",
|
|
1010
|
+
"May",
|
|
1011
|
+
"June",
|
|
1012
|
+
"July",
|
|
1013
|
+
"August",
|
|
1014
|
+
"September",
|
|
1015
|
+
"October",
|
|
1016
|
+
"November",
|
|
1017
|
+
"December"
|
|
1018
|
+
],
|
|
1019
|
+
weekDays: [
|
|
1020
|
+
"S",
|
|
1021
|
+
"M",
|
|
1022
|
+
"T",
|
|
1023
|
+
"W",
|
|
1024
|
+
"T",
|
|
1025
|
+
"F",
|
|
1026
|
+
"S"
|
|
1027
|
+
],
|
|
1028
|
+
prevMonth: "Previous month",
|
|
1029
|
+
nextMonth: "Next month"
|
|
1030
|
+
}
|
|
1031
|
+
};
|
|
1032
|
+
const startOfDay = (date) => new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
|
1033
|
+
function DatePicker({ value, onChange, locale = "pt", minDate, maxDate, className }) {
|
|
1034
|
+
const [currentMonth, setCurrentMonth] = useState(value ?? /* @__PURE__ */ new Date());
|
|
1035
|
+
const l = locales[locale];
|
|
1036
|
+
const getDaysInMonth = (date) => {
|
|
1037
|
+
const year = date.getFullYear();
|
|
1038
|
+
const month = date.getMonth();
|
|
1039
|
+
const firstDay = new Date(year, month, 1);
|
|
1040
|
+
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
|
1041
|
+
const startDayOfWeek = firstDay.getDay();
|
|
1042
|
+
const days = [];
|
|
1043
|
+
for (let i = 0; i < startDayOfWeek; i++) days.push(null);
|
|
1044
|
+
for (let i = 1; i <= daysInMonth; i++) days.push(i);
|
|
1045
|
+
return days;
|
|
1046
|
+
};
|
|
1047
|
+
const buildDate = (day) => new Date(currentMonth.getFullYear(), currentMonth.getMonth(), day);
|
|
1048
|
+
const isDisabled = (day) => {
|
|
1049
|
+
const date = buildDate(day);
|
|
1050
|
+
if (minDate && date < startOfDay(minDate)) return true;
|
|
1051
|
+
if (maxDate && date > startOfDay(maxDate)) return true;
|
|
1052
|
+
return false;
|
|
1053
|
+
};
|
|
1054
|
+
const isSelected = (day) => {
|
|
1055
|
+
if (!value) return false;
|
|
1056
|
+
return buildDate(day).getTime() === startOfDay(value).getTime();
|
|
1057
|
+
};
|
|
1058
|
+
const handleDayClick = (day) => {
|
|
1059
|
+
if (isDisabled(day)) return;
|
|
1060
|
+
onChange(buildDate(day));
|
|
1061
|
+
};
|
|
1062
|
+
const previousMonth = () => {
|
|
1063
|
+
setCurrentMonth(new Date(currentMonth.getFullYear(), currentMonth.getMonth() - 1));
|
|
1064
|
+
};
|
|
1065
|
+
const nextMonth = () => {
|
|
1066
|
+
setCurrentMonth(new Date(currentMonth.getFullYear(), currentMonth.getMonth() + 1));
|
|
1067
|
+
};
|
|
1068
|
+
const days = getDaysInMonth(currentMonth);
|
|
1069
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1070
|
+
className: cn$30("w-64 bg-[var(--dashboard-surface,#ffffff)] rounded-lg p-4 shadow-sm border border-[var(--dashboard-text-secondary,#6b7280)]/20", className),
|
|
1071
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
1072
|
+
className: "flex items-center justify-between mb-4",
|
|
1073
|
+
children: [
|
|
1074
|
+
/* @__PURE__ */ jsx("button", {
|
|
1075
|
+
type: "button",
|
|
1076
|
+
onClick: previousMonth,
|
|
1077
|
+
className: "p-1 hover:bg-[var(--dashboard-text-secondary,#6b7280)]/10 rounded transition-colors cursor-pointer",
|
|
1078
|
+
"aria-label": l.prevMonth,
|
|
1079
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, { className: "w-4 h-4 text-[var(--dashboard-text-primary,#2d2d2d)]" })
|
|
1080
|
+
}),
|
|
1081
|
+
/* @__PURE__ */ jsxs("h2", {
|
|
1082
|
+
className: "text-base font-semibold text-[var(--dashboard-text-primary,#2d2d2d)]",
|
|
1083
|
+
children: [
|
|
1084
|
+
l.months[currentMonth.getMonth()],
|
|
1085
|
+
" ",
|
|
1086
|
+
currentMonth.getFullYear()
|
|
1087
|
+
]
|
|
1088
|
+
}),
|
|
1089
|
+
/* @__PURE__ */ jsx("button", {
|
|
1090
|
+
type: "button",
|
|
1091
|
+
onClick: nextMonth,
|
|
1092
|
+
className: "p-1 hover:bg-[var(--dashboard-text-secondary,#6b7280)]/10 rounded transition-colors cursor-pointer",
|
|
1093
|
+
"aria-label": l.nextMonth,
|
|
1094
|
+
children: /* @__PURE__ */ jsx(ChevronRight, { className: "w-4 h-4 text-[var(--dashboard-text-primary,#2d2d2d)]" })
|
|
1095
|
+
})
|
|
1096
|
+
]
|
|
1097
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
1098
|
+
className: "grid grid-cols-7",
|
|
1099
|
+
children: [l.weekDays.map((day, index) => /* @__PURE__ */ jsx("div", {
|
|
1100
|
+
className: "h-8 w-8 flex items-center justify-center text-xs font-medium text-[var(--dashboard-text-secondary,#6b7280)]",
|
|
1101
|
+
children: day
|
|
1102
|
+
}, index)), days.map((day, index) => {
|
|
1103
|
+
if (day === null) return /* @__PURE__ */ jsx("div", { className: "h-8 w-8" }, `empty-${index}`);
|
|
1104
|
+
const selected = isSelected(day);
|
|
1105
|
+
const disabled = isDisabled(day);
|
|
1106
|
+
return /* @__PURE__ */ jsx("div", {
|
|
1107
|
+
className: "relative h-8 w-8",
|
|
1108
|
+
children: /* @__PURE__ */ jsx("button", {
|
|
1109
|
+
type: "button",
|
|
1110
|
+
onClick: () => handleDayClick(day),
|
|
1111
|
+
disabled,
|
|
1112
|
+
className: cn$30("relative h-8 w-8 flex items-center justify-center text-xs font-medium transition-colors z-10 rounded-full", disabled ? "text-[var(--dashboard-text-secondary,#6b7280)]/40 cursor-not-allowed" : "cursor-pointer", !disabled && selected ? "bg-[var(--dashboard-primary,#37a501)] text-white hover:opacity-90" : !disabled && "text-[var(--dashboard-text-primary,#2d2d2d)] hover:bg-[var(--dashboard-text-secondary,#6b7280)]/20"),
|
|
1113
|
+
children: day
|
|
1114
|
+
})
|
|
1115
|
+
}, day);
|
|
1116
|
+
})]
|
|
1117
|
+
})]
|
|
1118
|
+
});
|
|
1119
|
+
}
|
|
1120
|
+
|
|
967
1121
|
//#endregion
|
|
968
1122
|
//#region src/components/Title/index.tsx
|
|
969
|
-
const cn$
|
|
1123
|
+
const cn$29 = (...classes) => classes.filter(Boolean).join(" ");
|
|
970
1124
|
const defaultSizeByLevel = {
|
|
971
1125
|
1: "text-2xl sm:text-3xl md:text-4xl lg:text-5xl",
|
|
972
1126
|
2: "text-xl sm:text-2xl md:text-3xl lg:text-4xl",
|
|
@@ -1001,7 +1155,7 @@ function Title({ children, level = 1, size, weight = "bold", align = "left", col
|
|
|
1001
1155
|
const sizeClass = size ? customSizes[size] : defaultSizeByLevel[level];
|
|
1002
1156
|
const colorClass = color || "text-[var(--dashboard-text-primary,#2d2d2d)]";
|
|
1003
1157
|
return /* @__PURE__ */ jsx(Tag, {
|
|
1004
|
-
className: cn$
|
|
1158
|
+
className: cn$29(sizeClass, weightStyles[weight], alignStyles[align], colorClass, className),
|
|
1005
1159
|
...props,
|
|
1006
1160
|
children
|
|
1007
1161
|
});
|
|
@@ -1009,7 +1163,7 @@ function Title({ children, level = 1, size, weight = "bold", align = "left", col
|
|
|
1009
1163
|
|
|
1010
1164
|
//#endregion
|
|
1011
1165
|
//#region src/components/ToggleSwitch/index.tsx
|
|
1012
|
-
const cn$
|
|
1166
|
+
const cn$28 = (...classes) => classes.filter(Boolean).join(" ");
|
|
1013
1167
|
const sizeConfig$1 = {
|
|
1014
1168
|
sm: {
|
|
1015
1169
|
track: "h-5 w-9",
|
|
@@ -1033,7 +1187,7 @@ const sizeConfig$1 = {
|
|
|
1033
1187
|
function ToggleSwitch({ enabled, onChange, disabled = false, size = "md", label, className }) {
|
|
1034
1188
|
const config = sizeConfig$1[size];
|
|
1035
1189
|
return /* @__PURE__ */ jsxs("div", {
|
|
1036
|
-
className: cn$
|
|
1190
|
+
className: cn$28("inline-flex items-center gap-2", className),
|
|
1037
1191
|
children: [/* @__PURE__ */ jsx("button", {
|
|
1038
1192
|
type: "button",
|
|
1039
1193
|
role: "switch",
|
|
@@ -1041,10 +1195,10 @@ function ToggleSwitch({ enabled, onChange, disabled = false, size = "md", label,
|
|
|
1041
1195
|
"aria-label": label,
|
|
1042
1196
|
disabled,
|
|
1043
1197
|
onClick: () => onChange(!enabled),
|
|
1044
|
-
className: cn$
|
|
1045
|
-
children: /* @__PURE__ */ jsx("span", { className: cn$
|
|
1198
|
+
className: cn$28("relative inline-flex items-center rounded-full transition-colors outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-[var(--dashboard-primary,#37a501)]", config.track, enabled ? "bg-[var(--dashboard-primary,#37a501)]" : "bg-[var(--dashboard-text-secondary,#6b7280)]/30", disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"),
|
|
1199
|
+
children: /* @__PURE__ */ jsx("span", { className: cn$28("inline-block transform rounded-full bg-white shadow-sm transition-transform", config.thumb, enabled ? config.translateOn : config.translateOff) })
|
|
1046
1200
|
}), label && /* @__PURE__ */ jsx("span", {
|
|
1047
|
-
className: cn$
|
|
1201
|
+
className: cn$28("text-sm text-[var(--dashboard-text-primary,#2d2d2d)]", disabled && "opacity-50"),
|
|
1048
1202
|
children: label
|
|
1049
1203
|
})]
|
|
1050
1204
|
});
|
|
@@ -1052,7 +1206,7 @@ function ToggleSwitch({ enabled, onChange, disabled = false, size = "md", label,
|
|
|
1052
1206
|
|
|
1053
1207
|
//#endregion
|
|
1054
1208
|
//#region src/components/BadgeStatus/index.tsx
|
|
1055
|
-
const cn$
|
|
1209
|
+
const cn$27 = (...classes) => classes.filter(Boolean).join(" ");
|
|
1056
1210
|
const variantStyles = {
|
|
1057
1211
|
success: {
|
|
1058
1212
|
color: "text-[var(--dashboard-status-success,#10B981)]",
|
|
@@ -1083,7 +1237,7 @@ function BadgeStatus({ label, variant = "neutral", color, bgColor, size = "md",
|
|
|
1083
1237
|
const styles = variantStyles[variant];
|
|
1084
1238
|
const useCustomColors = color || bgColor;
|
|
1085
1239
|
return /* @__PURE__ */ jsx("span", {
|
|
1086
|
-
className: cn$
|
|
1240
|
+
className: cn$27("inline-flex w-fit items-center justify-center rounded-full font-medium whitespace-nowrap", sizeClasses$1[size], !useCustomColors && styles.color, !useCustomColors && styles.bgColor, className),
|
|
1087
1241
|
style: useCustomColors ? {
|
|
1088
1242
|
color: color || void 0,
|
|
1089
1243
|
backgroundColor: bgColor || void 0
|
|
@@ -1094,15 +1248,15 @@ function BadgeStatus({ label, variant = "neutral", color, bgColor, size = "md",
|
|
|
1094
1248
|
|
|
1095
1249
|
//#endregion
|
|
1096
1250
|
//#region src/components/Sidebar/index.tsx
|
|
1097
|
-
const cn$
|
|
1098
|
-
function DefaultLink({ href, className, children }) {
|
|
1251
|
+
const cn$26 = (...classes) => classes.filter(Boolean).join(" ");
|
|
1252
|
+
function DefaultLink$1({ href, className, children }) {
|
|
1099
1253
|
return /* @__PURE__ */ jsx("a", {
|
|
1100
1254
|
href,
|
|
1101
1255
|
className,
|
|
1102
1256
|
children
|
|
1103
1257
|
});
|
|
1104
1258
|
}
|
|
1105
|
-
function Sidebar({ menuItems, logo, collapsedLogo, currentPath, linkComponent: LinkComponent = DefaultLink, isCollapsed = false, onToggleCollapse, user, onUserClick, onLogout, logoutLabel = "Sair", footerItems, footerSlot, defaultExpandedIds, persistExpandedKey, className }) {
|
|
1259
|
+
function Sidebar({ menuItems, logo, collapsedLogo, currentPath, linkComponent: LinkComponent = DefaultLink$1, isCollapsed = false, onToggleCollapse, user, onUserClick, onLogout, logoutLabel = "Sair", footerItems, footerSlot, defaultExpandedIds, persistExpandedKey, showMobileHeader = true, className }) {
|
|
1106
1260
|
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
|
1107
1261
|
const [expandedIds, setExpandedIds] = useState(() => new Set(defaultExpandedIds ?? []));
|
|
1108
1262
|
const cubicBezier = "cubic-bezier(0.4, 0, 0.2, 1)";
|
|
@@ -1170,7 +1324,7 @@ function Sidebar({ menuItems, logo, collapsedLogo, currentPath, linkComponent: L
|
|
|
1170
1324
|
const isChildActive = item.children?.some((c) => currentPath === c.href);
|
|
1171
1325
|
if (hasChildren) return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("button", {
|
|
1172
1326
|
onClick: () => toggleExpand(item.id),
|
|
1173
|
-
className: cn$
|
|
1327
|
+
className: cn$26("w-full flex items-center px-4 py-3 rounded-lg text-sm font-medium cursor-pointer", collapsed && !mobile ? "justify-center" : "justify-start", isChildActive ? "text-[var(--dashboard-sidebar-active-text,#ff521d)]" : "text-[var(--dashboard-sidebar-text,#403f52)] hover:bg-[var(--dashboard-primary,#ff521d)]/10"),
|
|
1174
1328
|
style: { transition: "background-color 200ms, color 200ms" },
|
|
1175
1329
|
title: collapsed && !mobile ? item.label : void 0,
|
|
1176
1330
|
children: [/* @__PURE__ */ jsx(Icon, {
|
|
@@ -1185,7 +1339,7 @@ function Sidebar({ menuItems, logo, collapsedLogo, currentPath, linkComponent: L
|
|
|
1185
1339
|
children: item.label
|
|
1186
1340
|
}), /* @__PURE__ */ jsx(ChevronRight, {
|
|
1187
1341
|
size: 14,
|
|
1188
|
-
className: cn$
|
|
1342
|
+
className: cn$26("ml-auto flex-shrink-0 transition-transform duration-200", isExpanded ? "rotate-90" : "")
|
|
1189
1343
|
})] })]
|
|
1190
1344
|
}), (!collapsed || mobile) && /* @__PURE__ */ jsx("div", {
|
|
1191
1345
|
className: "overflow-hidden transition-all duration-200 ml-7 border-l-2 border-[var(--dashboard-sidebar-border,#e0dfe3)]",
|
|
@@ -1197,7 +1351,7 @@ function Sidebar({ menuItems, logo, collapsedLogo, currentPath, linkComponent: L
|
|
|
1197
1351
|
href: child.href,
|
|
1198
1352
|
className: "block",
|
|
1199
1353
|
children: /* @__PURE__ */ jsxs("div", {
|
|
1200
|
-
className: cn$
|
|
1354
|
+
className: cn$26("w-full flex items-center pl-4 pr-4 py-2 rounded-r-lg text-[13px] cursor-pointer", childActive ? "text-[var(--dashboard-sidebar-active-text,#ff521d)] font-semibold border-l-2 border-[var(--dashboard-primary,#ff521d)] -ml-[2px]" : "text-[var(--dashboard-sidebar-text,#403f52)] hover:text-[var(--dashboard-sidebar-active-text,#ff521d)]"),
|
|
1201
1355
|
style: { transition: "background-color 200ms, color 200ms" },
|
|
1202
1356
|
children: [/* @__PURE__ */ jsx(ChildIcon, {
|
|
1203
1357
|
size: 15,
|
|
@@ -1214,7 +1368,7 @@ function Sidebar({ menuItems, logo, collapsedLogo, currentPath, linkComponent: L
|
|
|
1214
1368
|
href: item.href,
|
|
1215
1369
|
className: "block",
|
|
1216
1370
|
children: /* @__PURE__ */ jsxs("div", {
|
|
1217
|
-
className: cn$
|
|
1371
|
+
className: cn$26("w-full flex items-center px-4 py-3 rounded-lg text-sm font-medium cursor-pointer", collapsed && !mobile ? "justify-center" : "justify-start", isActive ? "bg-[var(--dashboard-primary,#ff521d)]/25 text-[var(--dashboard-sidebar-active-text,#ff521d)]" : "text-[var(--dashboard-sidebar-text,#403f52)] hover:bg-[var(--dashboard-primary,#ff521d)]/10"),
|
|
1218
1372
|
style: { transition: "background-color 200ms, color 200ms" },
|
|
1219
1373
|
title: collapsed && !mobile ? item.label : void 0,
|
|
1220
1374
|
children: [/* @__PURE__ */ jsx(Icon, {
|
|
@@ -1242,7 +1396,7 @@ function Sidebar({ menuItems, logo, collapsedLogo, currentPath, linkComponent: L
|
|
|
1242
1396
|
children: [group.section && renderSectionHeader(group.section, collapsed), group.items.map((item) => renderMenuItem(item, collapsed, mobile))]
|
|
1243
1397
|
}, group.section || `group-${i}`));
|
|
1244
1398
|
}
|
|
1245
|
-
|
|
1399
|
+
const mobileHeader = /* @__PURE__ */ jsxs("header", {
|
|
1246
1400
|
className: "xl:hidden fixed top-0 left-0 right-0 z-40 bg-[var(--dashboard-sidebar-bg,#f0f0f0)] border-b border-[var(--dashboard-sidebar-border,#e0dfe3)]",
|
|
1247
1401
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
1248
1402
|
className: "flex items-center justify-center px-4 h-16 relative",
|
|
@@ -1307,8 +1461,9 @@ function Sidebar({ menuItems, logo, collapsedLogo, currentPath, linkComponent: L
|
|
|
1307
1461
|
})]
|
|
1308
1462
|
})
|
|
1309
1463
|
})]
|
|
1310
|
-
})
|
|
1311
|
-
|
|
1464
|
+
});
|
|
1465
|
+
const desktopSidebar = /* @__PURE__ */ jsxs("aside", {
|
|
1466
|
+
className: cn$26("hidden xl:flex xl:flex-col xl:fixed xl:left-0 xl:top-0 xl:h-screen bg-[var(--dashboard-sidebar-bg,#f0f0f0)] border-r border-[var(--dashboard-sidebar-border,#e0dfe3)] overflow-visible", isCollapsed ? "xl:w-[109px]" : "xl:w-[280px]", className),
|
|
1312
1467
|
style: { transition: `width 400ms ${cubicBezier}` },
|
|
1313
1468
|
children: [onToggleCollapse && /* @__PURE__ */ jsxs("button", {
|
|
1314
1469
|
onClick: onToggleCollapse,
|
|
@@ -1382,7 +1537,7 @@ function Sidebar({ menuItems, logo, collapsedLogo, currentPath, linkComponent: L
|
|
|
1382
1537
|
children: [
|
|
1383
1538
|
user && /* @__PURE__ */ jsxs("button", {
|
|
1384
1539
|
onClick: onUserClick,
|
|
1385
|
-
className: cn$
|
|
1540
|
+
className: cn$26("w-full flex items-center px-4 py-3 rounded-lg bg-[var(--dashboard-primary,#ff521d)]/5 hover:bg-[var(--dashboard-primary,#ff521d)]/10 transition-colors cursor-pointer", isCollapsed ? "justify-center" : "justify-start"),
|
|
1386
1541
|
title: isCollapsed ? `${user.subtitle ? user.subtitle + " - " : ""}${user.name}` : void 0,
|
|
1387
1542
|
children: [/* @__PURE__ */ jsx("div", {
|
|
1388
1543
|
className: "flex items-center justify-center w-8 h-8 rounded-full bg-[var(--dashboard-primary,#ff521d)]/30 text-[var(--dashboard-sidebar-text,#403f52)] flex-shrink-0",
|
|
@@ -1415,7 +1570,7 @@ function Sidebar({ menuItems, logo, collapsedLogo, currentPath, linkComponent: L
|
|
|
1415
1570
|
footerItems?.map((item) => renderMenuItem(item, isCollapsed, false)),
|
|
1416
1571
|
onLogout && /* @__PURE__ */ jsxs("button", {
|
|
1417
1572
|
onClick: onLogout,
|
|
1418
|
-
className: cn$
|
|
1573
|
+
className: cn$26("w-full flex items-center px-4 py-3 rounded-lg text-sm font-medium cursor-pointer text-[var(--dashboard-sidebar-text,#403f52)] hover:bg-[var(--dashboard-primary,#ff521d)]/10", isCollapsed ? "justify-center" : "justify-start"),
|
|
1419
1574
|
style: { transition: "background-color 200ms" },
|
|
1420
1575
|
title: isCollapsed ? logoutLabel : void 0,
|
|
1421
1576
|
children: [/* @__PURE__ */ jsx(LogOut, {
|
|
@@ -1438,7 +1593,440 @@ function Sidebar({ menuItems, logo, collapsedLogo, currentPath, linkComponent: L
|
|
|
1438
1593
|
})
|
|
1439
1594
|
]
|
|
1440
1595
|
})]
|
|
1441
|
-
})
|
|
1596
|
+
});
|
|
1597
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [showMobileHeader && mobileHeader, desktopSidebar] });
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
//#endregion
|
|
1601
|
+
//#region src/components/Header/index.tsx
|
|
1602
|
+
const cn$25 = (...classes) => classes.filter(Boolean).join(" ");
|
|
1603
|
+
function isGroup(item) {
|
|
1604
|
+
return "children" in item && Array.isArray(item.children);
|
|
1605
|
+
}
|
|
1606
|
+
function DefaultLink({ href, className, onClick, children }) {
|
|
1607
|
+
return /* @__PURE__ */ jsx("a", {
|
|
1608
|
+
href,
|
|
1609
|
+
className,
|
|
1610
|
+
onClick,
|
|
1611
|
+
children
|
|
1612
|
+
});
|
|
1613
|
+
}
|
|
1614
|
+
function useOnClickOutside(ref, handler) {
|
|
1615
|
+
useEffect(() => {
|
|
1616
|
+
const listener = (event) => {
|
|
1617
|
+
if (!ref.current || ref.current.contains(event.target)) return;
|
|
1618
|
+
handler();
|
|
1619
|
+
};
|
|
1620
|
+
document.addEventListener("mousedown", listener);
|
|
1621
|
+
document.addEventListener("touchstart", listener);
|
|
1622
|
+
return () => {
|
|
1623
|
+
document.removeEventListener("mousedown", listener);
|
|
1624
|
+
document.removeEventListener("touchstart", listener);
|
|
1625
|
+
};
|
|
1626
|
+
}, [ref, handler]);
|
|
1627
|
+
}
|
|
1628
|
+
function Header({ menuItems, logo, currentPath, linkComponent: LinkComponent = DefaultLink, user, establishments = [], establishmentsLabel = "Estabelecimento", onEstablishmentChange, actions, onUserClick, onLogout, logoutLabel = "Sair", menuLabel = "Menu", desktopOffsetLeft = 0, className }) {
|
|
1629
|
+
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
|
1630
|
+
const [isUserMenuOpen, setIsUserMenuOpen] = useState(false);
|
|
1631
|
+
const [openDropdownId, setOpenDropdownId] = useState(null);
|
|
1632
|
+
const dropdownRef = useRef(null);
|
|
1633
|
+
const userMenuRef = useRef(null);
|
|
1634
|
+
useOnClickOutside(dropdownRef, () => setOpenDropdownId(null));
|
|
1635
|
+
useOnClickOutside(userMenuRef, () => setIsUserMenuOpen(false));
|
|
1636
|
+
const closeMenus = () => {
|
|
1637
|
+
setIsMobileMenuOpen(false);
|
|
1638
|
+
setIsUserMenuOpen(false);
|
|
1639
|
+
setOpenDropdownId(null);
|
|
1640
|
+
};
|
|
1641
|
+
const isItemActive = (item) => {
|
|
1642
|
+
if (isGroup(item)) return item.children.some((child) => currentPath === child.href || child.href !== "/dashboard" && currentPath.startsWith(child.href));
|
|
1643
|
+
return currentPath === item.href;
|
|
1644
|
+
};
|
|
1645
|
+
const renderNavLink = (item, options = {}) => {
|
|
1646
|
+
const Icon = item.icon;
|
|
1647
|
+
const active = currentPath === item.href;
|
|
1648
|
+
if (item.disabled) return /* @__PURE__ */ jsxs("span", {
|
|
1649
|
+
className: cn$25("flex items-center gap-2 rounded-lg text-sm font-medium cursor-not-allowed", options.mobile ? "px-4 py-3" : "h-10 px-3", "text-[var(--dashboard-text-secondary,#6b7280)]/40"),
|
|
1650
|
+
title: "Em breve",
|
|
1651
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
1652
|
+
size: 18,
|
|
1653
|
+
className: "flex-shrink-0 opacity-40"
|
|
1654
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
1655
|
+
className: "line-through opacity-50",
|
|
1656
|
+
children: item.label
|
|
1657
|
+
})]
|
|
1658
|
+
}, item.id);
|
|
1659
|
+
return /* @__PURE__ */ jsx(LinkComponent, {
|
|
1660
|
+
href: item.href,
|
|
1661
|
+
className: "block",
|
|
1662
|
+
onClick: closeMenus,
|
|
1663
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
1664
|
+
className: cn$25("flex items-center gap-2 rounded-lg text-sm font-medium transition-colors", options.mobile ? "px-4 py-3" : "h-10 px-3", active ? "bg-[var(--dashboard-primary,#37a501)]/12 text-[var(--dashboard-primary,#37a501)]" : "text-[var(--dashboard-text-secondary,#6b7280)] hover:bg-[var(--dashboard-primary,#37a501)]/8 hover:text-[var(--dashboard-text-primary,#2d2d2d)]"),
|
|
1665
|
+
"aria-current": active ? "page" : void 0,
|
|
1666
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
1667
|
+
size: 18,
|
|
1668
|
+
className: "flex-shrink-0"
|
|
1669
|
+
}), /* @__PURE__ */ jsx("span", { children: item.label })]
|
|
1670
|
+
})
|
|
1671
|
+
}, item.id);
|
|
1672
|
+
};
|
|
1673
|
+
const renderDropdown = (group, options = {}) => {
|
|
1674
|
+
const Icon = group.icon;
|
|
1675
|
+
const groupActive = isItemActive(group);
|
|
1676
|
+
const isOpen = openDropdownId === group.id;
|
|
1677
|
+
if (options.mobile) return /* @__PURE__ */ jsxs("div", {
|
|
1678
|
+
className: "space-y-1",
|
|
1679
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
1680
|
+
className: "flex items-center gap-2 px-4 py-2 text-xs font-semibold uppercase tracking-wider text-[var(--dashboard-text-secondary,#6b7280)]",
|
|
1681
|
+
children: [/* @__PURE__ */ jsx(Icon, { size: 16 }), group.label]
|
|
1682
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
1683
|
+
className: "ml-3 space-y-1 border-l border-[var(--dashboard-text-secondary,#6b7280)]/20 pl-3",
|
|
1684
|
+
children: group.children.map((child) => {
|
|
1685
|
+
const active = currentPath === child.href;
|
|
1686
|
+
return child.disabled ? /* @__PURE__ */ jsxs("span", {
|
|
1687
|
+
className: "flex items-center gap-2 rounded-lg px-4 py-2.5 text-sm font-medium cursor-not-allowed text-[var(--dashboard-text-secondary,#6b7280)]/40",
|
|
1688
|
+
title: "Em breve",
|
|
1689
|
+
children: [/* @__PURE__ */ jsx(child.icon, {
|
|
1690
|
+
size: 16,
|
|
1691
|
+
className: "flex-shrink-0 opacity-40"
|
|
1692
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
1693
|
+
className: "line-through opacity-50",
|
|
1694
|
+
children: child.label
|
|
1695
|
+
})]
|
|
1696
|
+
}, child.id) : /* @__PURE__ */ jsx(LinkComponent, {
|
|
1697
|
+
href: child.href,
|
|
1698
|
+
className: "block",
|
|
1699
|
+
onClick: closeMenus,
|
|
1700
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
1701
|
+
className: cn$25("flex items-center gap-2 rounded-lg px-4 py-2.5 text-sm font-medium transition-colors", active ? "bg-[var(--dashboard-primary,#37a501)]/12 text-[var(--dashboard-primary,#37a501)]" : "text-[var(--dashboard-text-secondary,#6b7280)] hover:bg-[var(--dashboard-primary,#37a501)]/8 hover:text-[var(--dashboard-text-primary,#2d2d2d)]"),
|
|
1702
|
+
children: [/* @__PURE__ */ jsx(child.icon, {
|
|
1703
|
+
size: 16,
|
|
1704
|
+
className: "flex-shrink-0"
|
|
1705
|
+
}), /* @__PURE__ */ jsx("span", { children: child.label })]
|
|
1706
|
+
})
|
|
1707
|
+
}, child.id);
|
|
1708
|
+
})
|
|
1709
|
+
})]
|
|
1710
|
+
}, group.id);
|
|
1711
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1712
|
+
className: "relative",
|
|
1713
|
+
ref: isOpen ? dropdownRef : void 0,
|
|
1714
|
+
children: [/* @__PURE__ */ jsxs("button", {
|
|
1715
|
+
type: "button",
|
|
1716
|
+
onClick: () => setOpenDropdownId((prev) => prev === group.id ? null : group.id),
|
|
1717
|
+
className: cn$25("flex items-center gap-1.5 rounded-lg h-10 px-3 text-sm font-medium transition-colors", groupActive ? "bg-[var(--dashboard-primary,#37a501)]/12 text-[var(--dashboard-primary,#37a501)]" : "text-[var(--dashboard-text-secondary,#6b7280)] hover:bg-[var(--dashboard-primary,#37a501)]/8 hover:text-[var(--dashboard-text-primary,#2d2d2d)]"),
|
|
1718
|
+
"aria-expanded": isOpen,
|
|
1719
|
+
children: [
|
|
1720
|
+
/* @__PURE__ */ jsx(Icon, {
|
|
1721
|
+
size: 18,
|
|
1722
|
+
className: "flex-shrink-0"
|
|
1723
|
+
}),
|
|
1724
|
+
/* @__PURE__ */ jsx("span", { children: group.label }),
|
|
1725
|
+
/* @__PURE__ */ jsx(ChevronDown, {
|
|
1726
|
+
size: 14,
|
|
1727
|
+
className: cn$25("flex-shrink-0 transition-transform", isOpen && "rotate-180")
|
|
1728
|
+
})
|
|
1729
|
+
]
|
|
1730
|
+
}), isOpen && /* @__PURE__ */ jsx("div", {
|
|
1731
|
+
className: "absolute left-1/2 top-[calc(100%+0.5rem)] z-50 w-max min-w-full max-w-[24rem] -translate-x-1/2 rounded-xl border border-[var(--dashboard-text-secondary,#6b7280)]/20 bg-[var(--dashboard-surface,#ffffff)] p-1.5 shadow-xl",
|
|
1732
|
+
children: group.children.map((child) => {
|
|
1733
|
+
const active = currentPath === child.href;
|
|
1734
|
+
return child.disabled ? /* @__PURE__ */ jsxs("span", {
|
|
1735
|
+
className: "flex cursor-not-allowed items-center gap-2 rounded-lg px-3 py-2 text-sm text-[var(--dashboard-text-secondary,#6b7280)]/40",
|
|
1736
|
+
title: "Em breve",
|
|
1737
|
+
children: [/* @__PURE__ */ jsx(child.icon, {
|
|
1738
|
+
size: 16,
|
|
1739
|
+
className: "flex-shrink-0 opacity-40"
|
|
1740
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
1741
|
+
className: "whitespace-nowrap line-through opacity-50",
|
|
1742
|
+
children: child.label
|
|
1743
|
+
})]
|
|
1744
|
+
}, child.id) : /* @__PURE__ */ jsx(LinkComponent, {
|
|
1745
|
+
href: child.href,
|
|
1746
|
+
className: "block",
|
|
1747
|
+
onClick: () => setOpenDropdownId(null),
|
|
1748
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
1749
|
+
className: cn$25("flex items-center gap-2 rounded-lg px-3 py-2 text-sm transition-colors", active ? "bg-[var(--dashboard-primary,#37a501)]/10 text-[var(--dashboard-primary,#37a501)] font-semibold" : "text-[var(--dashboard-text-primary,#2d2d2d)]/80 hover:bg-[var(--dashboard-primary,#37a501)]/8 hover:text-[var(--dashboard-text-primary,#2d2d2d)]"),
|
|
1750
|
+
children: [
|
|
1751
|
+
/* @__PURE__ */ jsx(child.icon, {
|
|
1752
|
+
size: 16,
|
|
1753
|
+
className: "flex-shrink-0"
|
|
1754
|
+
}),
|
|
1755
|
+
/* @__PURE__ */ jsx("span", {
|
|
1756
|
+
className: "whitespace-nowrap",
|
|
1757
|
+
children: child.label
|
|
1758
|
+
}),
|
|
1759
|
+
active && /* @__PURE__ */ jsx("span", { className: "ml-auto h-1.5 w-1.5 rounded-full bg-[var(--dashboard-primary,#37a501)]" })
|
|
1760
|
+
]
|
|
1761
|
+
})
|
|
1762
|
+
}, child.id);
|
|
1763
|
+
})
|
|
1764
|
+
})]
|
|
1765
|
+
}, group.id);
|
|
1766
|
+
};
|
|
1767
|
+
const renderNavItem = (item, options = {}) => {
|
|
1768
|
+
if (isGroup(item)) return renderDropdown(item, options);
|
|
1769
|
+
return renderNavLink(item, options);
|
|
1770
|
+
};
|
|
1771
|
+
const desktopOffset = typeof desktopOffsetLeft === "number" ? `${desktopOffsetLeft}px` : desktopOffsetLeft;
|
|
1772
|
+
const userEstablishments = establishments.length > 0 ? establishments : user?.subtitle ? [{
|
|
1773
|
+
id: "current",
|
|
1774
|
+
label: user.subtitle,
|
|
1775
|
+
active: true
|
|
1776
|
+
}] : [];
|
|
1777
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1778
|
+
/* @__PURE__ */ jsx("div", {
|
|
1779
|
+
"aria-hidden": "true",
|
|
1780
|
+
className: "pointer-events-none fixed inset-x-0 top-0 z-30 h-2 bg-[var(--dashboard-background,#f2f2f2)]"
|
|
1781
|
+
}),
|
|
1782
|
+
/* @__PURE__ */ jsx("div", {
|
|
1783
|
+
"aria-hidden": "true",
|
|
1784
|
+
className: "pointer-events-none fixed left-[var(--dashboard-page-gutter,0px)] right-[var(--dashboard-page-gutter,0px)] top-2 z-30 h-5 bg-[var(--dashboard-background,#f2f2f2)] transition-[left,right] duration-[400ms] ease-[cubic-bezier(0.4,0,0.2,1)] xl:left-[calc(var(--dashboard-header-offset-left,0px)+var(--dashboard-page-gutter,0px))]",
|
|
1785
|
+
style: { "--dashboard-header-offset-left": desktopOffset }
|
|
1786
|
+
}),
|
|
1787
|
+
/* @__PURE__ */ jsx("div", {
|
|
1788
|
+
"aria-hidden": "true",
|
|
1789
|
+
className: "pointer-events-none fixed left-[var(--dashboard-page-gutter,0px)] top-2 z-30 h-14 w-5 bg-[var(--dashboard-background,#f2f2f2)] transition-[left] duration-[400ms] ease-[cubic-bezier(0.4,0,0.2,1)] xl:left-[calc(var(--dashboard-header-offset-left,0px)+var(--dashboard-page-gutter,0px))]",
|
|
1790
|
+
style: { "--dashboard-header-offset-left": desktopOffset }
|
|
1791
|
+
}),
|
|
1792
|
+
/* @__PURE__ */ jsx("div", {
|
|
1793
|
+
"aria-hidden": "true",
|
|
1794
|
+
className: "pointer-events-none fixed right-[var(--dashboard-page-gutter,0px)] top-2 z-30 h-14 w-5 bg-[var(--dashboard-background,#f2f2f2)] transition-[right] duration-[400ms] ease-[cubic-bezier(0.4,0,0.2,1)]"
|
|
1795
|
+
}),
|
|
1796
|
+
/* @__PURE__ */ jsx("div", {
|
|
1797
|
+
"aria-hidden": "true",
|
|
1798
|
+
className: "pointer-events-none fixed left-[var(--dashboard-page-gutter,0px)] right-[var(--dashboard-page-gutter,0px)] top-2 z-30 h-20 rounded-2xl bg-[var(--dashboard-background,#f2f2f2)] transition-[left,right] duration-[400ms] ease-[cubic-bezier(0.4,0,0.2,1)] xl:left-[calc(var(--dashboard-header-offset-left,0px)+var(--dashboard-page-gutter,0px))]",
|
|
1799
|
+
style: { "--dashboard-header-offset-left": desktopOffset }
|
|
1800
|
+
}),
|
|
1801
|
+
/* @__PURE__ */ jsxs("header", {
|
|
1802
|
+
className: cn$25("fixed left-[var(--dashboard-page-gutter,0px)] right-[var(--dashboard-page-gutter,0px)] top-2 z-40 rounded-2xl border border-[var(--dashboard-text-secondary,#6b7280)]/15 bg-[var(--dashboard-surface,#ffffff)] text-[var(--dashboard-text-primary,#2d2d2d)] shadow-sm transition-[left,right] duration-[400ms] ease-[cubic-bezier(0.4,0,0.2,1)] xl:left-[calc(var(--dashboard-header-offset-left,0px)+var(--dashboard-page-gutter,0px))]", className),
|
|
1803
|
+
style: { "--dashboard-header-offset-left": desktopOffset },
|
|
1804
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
1805
|
+
className: "flex h-20 items-center gap-4 px-4 sm:px-5 xl:grid xl:grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)]",
|
|
1806
|
+
children: [
|
|
1807
|
+
/* @__PURE__ */ jsx("div", {
|
|
1808
|
+
className: "flex min-w-0 flex-1 items-center gap-4 lg:flex-none xl:col-start-1 xl:justify-self-start",
|
|
1809
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
1810
|
+
className: "flex min-w-0 items-center",
|
|
1811
|
+
children: logo
|
|
1812
|
+
})
|
|
1813
|
+
}),
|
|
1814
|
+
/* @__PURE__ */ jsx("nav", {
|
|
1815
|
+
className: "hidden min-w-0 items-center justify-center gap-1 xl:col-start-2 xl:flex",
|
|
1816
|
+
"aria-label": "Navegacao principal",
|
|
1817
|
+
children: menuItems.map((item) => renderNavItem(item))
|
|
1818
|
+
}),
|
|
1819
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1820
|
+
className: "hidden items-center gap-3 xl:col-start-3 xl:flex xl:justify-self-end",
|
|
1821
|
+
children: [actions, user && /* @__PURE__ */ jsxs("div", {
|
|
1822
|
+
className: "relative w-[260px]",
|
|
1823
|
+
ref: userMenuRef,
|
|
1824
|
+
children: [/* @__PURE__ */ jsxs("button", {
|
|
1825
|
+
type: "button",
|
|
1826
|
+
onClick: () => setIsUserMenuOpen((open) => !open),
|
|
1827
|
+
className: "flex h-11 w-full items-center gap-3 rounded-lg bg-[var(--dashboard-background,#f2f2f2)] px-3 text-left transition-colors hover:bg-[var(--dashboard-primary,#37a501)]/8",
|
|
1828
|
+
"aria-expanded": isUserMenuOpen,
|
|
1829
|
+
children: [
|
|
1830
|
+
/* @__PURE__ */ jsx("div", {
|
|
1831
|
+
className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-[var(--dashboard-primary,#37a501)]/12 text-[var(--dashboard-primary,#37a501)]",
|
|
1832
|
+
children: /* @__PURE__ */ jsx(User, { size: 16 })
|
|
1833
|
+
}),
|
|
1834
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1835
|
+
className: "min-w-0 flex-1",
|
|
1836
|
+
children: [user.subtitle && /* @__PURE__ */ jsx("p", {
|
|
1837
|
+
className: "truncate text-[11px] leading-4 text-[var(--dashboard-text-secondary,#6b7280)]",
|
|
1838
|
+
children: user.subtitle
|
|
1839
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
1840
|
+
className: "truncate text-sm font-medium leading-4",
|
|
1841
|
+
children: user.name
|
|
1842
|
+
})]
|
|
1843
|
+
}),
|
|
1844
|
+
/* @__PURE__ */ jsx(ChevronDown, {
|
|
1845
|
+
size: 16,
|
|
1846
|
+
className: cn$25("ml-auto flex-shrink-0 transition-transform", isUserMenuOpen && "rotate-180")
|
|
1847
|
+
})
|
|
1848
|
+
]
|
|
1849
|
+
}), isUserMenuOpen && /* @__PURE__ */ jsxs("div", {
|
|
1850
|
+
className: "absolute right-0 top-[calc(100%+0.5rem)] w-full rounded-lg border border-[var(--dashboard-text-secondary,#6b7280)]/20 bg-[var(--dashboard-surface,#ffffff)] p-2 text-[var(--dashboard-text-primary,#2d2d2d)] shadow-xl",
|
|
1851
|
+
children: [
|
|
1852
|
+
/* @__PURE__ */ jsxs("button", {
|
|
1853
|
+
type: "button",
|
|
1854
|
+
onClick: () => {
|
|
1855
|
+
setIsUserMenuOpen(false);
|
|
1856
|
+
onUserClick?.();
|
|
1857
|
+
},
|
|
1858
|
+
className: "flex w-full items-center gap-3 rounded-lg px-3 py-3 text-left transition-colors hover:bg-[var(--dashboard-primary,#37a501)]/8",
|
|
1859
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
1860
|
+
className: "flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-full bg-[var(--dashboard-primary,#37a501)]/12 text-[var(--dashboard-primary,#37a501)]",
|
|
1861
|
+
children: /* @__PURE__ */ jsx(User, { size: 17 })
|
|
1862
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
1863
|
+
className: "min-w-0",
|
|
1864
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
1865
|
+
className: "truncate text-sm font-semibold",
|
|
1866
|
+
children: user.name
|
|
1867
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
1868
|
+
className: "truncate text-xs text-[var(--dashboard-text-secondary,#6b7280)]",
|
|
1869
|
+
children: user.email
|
|
1870
|
+
})]
|
|
1871
|
+
})]
|
|
1872
|
+
}),
|
|
1873
|
+
userEstablishments.length > 0 && /* @__PURE__ */ jsxs("div", {
|
|
1874
|
+
className: "mt-1 border-t border-[var(--dashboard-text-secondary,#6b7280)]/15 pt-2",
|
|
1875
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
1876
|
+
className: "px-3 pb-1 text-[11px] font-semibold uppercase tracking-wide text-[var(--dashboard-text-secondary,#6b7280)]",
|
|
1877
|
+
children: establishmentsLabel
|
|
1878
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
1879
|
+
className: "space-y-1",
|
|
1880
|
+
children: userEstablishments.map((establishment) => {
|
|
1881
|
+
const isDisabled = establishment.disabled || !onEstablishmentChange || establishment.active;
|
|
1882
|
+
return /* @__PURE__ */ jsxs("button", {
|
|
1883
|
+
type: "button",
|
|
1884
|
+
onClick: () => {
|
|
1885
|
+
if (isDisabled) return;
|
|
1886
|
+
setIsUserMenuOpen(false);
|
|
1887
|
+
onEstablishmentChange?.(establishment.id);
|
|
1888
|
+
},
|
|
1889
|
+
disabled: isDisabled,
|
|
1890
|
+
className: cn$25("flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-left transition-colors", establishment.active ? "bg-[var(--dashboard-primary,#37a501)]/10 text-[var(--dashboard-primary,#37a501)]" : "hover:bg-[var(--dashboard-primary,#37a501)]/8", isDisabled ? establishment.active ? "cursor-default" : "cursor-not-allowed opacity-60" : "cursor-pointer"),
|
|
1891
|
+
children: [
|
|
1892
|
+
/* @__PURE__ */ jsx("div", {
|
|
1893
|
+
className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-[var(--dashboard-primary,#37a501)]/12 text-[var(--dashboard-primary,#37a501)]",
|
|
1894
|
+
children: /* @__PURE__ */ jsx(Building2, { size: 15 })
|
|
1895
|
+
}),
|
|
1896
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1897
|
+
className: "min-w-0 flex-1",
|
|
1898
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
1899
|
+
className: "truncate text-sm font-semibold",
|
|
1900
|
+
children: establishment.label
|
|
1901
|
+
}), establishment.description && /* @__PURE__ */ jsx("p", {
|
|
1902
|
+
className: "truncate text-xs text-[var(--dashboard-text-secondary,#6b7280)]",
|
|
1903
|
+
children: establishment.description
|
|
1904
|
+
})]
|
|
1905
|
+
}),
|
|
1906
|
+
establishment.active && /* @__PURE__ */ jsx(Check, {
|
|
1907
|
+
size: 16,
|
|
1908
|
+
className: "flex-shrink-0"
|
|
1909
|
+
})
|
|
1910
|
+
]
|
|
1911
|
+
}, establishment.id);
|
|
1912
|
+
})
|
|
1913
|
+
})]
|
|
1914
|
+
}),
|
|
1915
|
+
onLogout && /* @__PURE__ */ jsxs("button", {
|
|
1916
|
+
type: "button",
|
|
1917
|
+
onClick: () => {
|
|
1918
|
+
setIsUserMenuOpen(false);
|
|
1919
|
+
onLogout();
|
|
1920
|
+
},
|
|
1921
|
+
className: "mt-1 flex w-full items-center gap-3 rounded-lg px-3 py-3 text-sm font-medium transition-colors hover:bg-[var(--dashboard-primary,#37a501)]/8",
|
|
1922
|
+
children: [/* @__PURE__ */ jsx(LogOut, { size: 18 }), logoutLabel]
|
|
1923
|
+
})
|
|
1924
|
+
]
|
|
1925
|
+
})]
|
|
1926
|
+
})]
|
|
1927
|
+
}),
|
|
1928
|
+
/* @__PURE__ */ jsx("button", {
|
|
1929
|
+
type: "button",
|
|
1930
|
+
onClick: () => setIsMobileMenuOpen((open) => !open),
|
|
1931
|
+
className: "inline-flex h-10 w-10 items-center justify-center rounded-lg bg-[var(--dashboard-primary,#37a501)]/10 text-[var(--dashboard-primary,#37a501)] transition-colors hover:bg-[var(--dashboard-primary,#37a501)]/15 xl:hidden",
|
|
1932
|
+
"aria-label": menuLabel,
|
|
1933
|
+
"aria-expanded": isMobileMenuOpen,
|
|
1934
|
+
children: isMobileMenuOpen ? /* @__PURE__ */ jsx(X, { size: 22 }) : /* @__PURE__ */ jsx(Menu, { size: 22 })
|
|
1935
|
+
})
|
|
1936
|
+
]
|
|
1937
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
1938
|
+
className: cn$25("xl:hidden overflow-hidden border-t border-[var(--dashboard-text-secondary,#6b7280)]/20 bg-[var(--dashboard-surface,#ffffff)] shadow-lg transition-[max-height] duration-200", isMobileMenuOpen ? "max-h-[calc(100vh-4rem)]" : "max-h-0"),
|
|
1939
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
1940
|
+
className: "max-h-[calc(100vh-4rem)] overflow-y-auto px-4 py-3",
|
|
1941
|
+
children: [/* @__PURE__ */ jsx("nav", {
|
|
1942
|
+
className: "space-y-1",
|
|
1943
|
+
"aria-label": "Navegacao principal",
|
|
1944
|
+
children: menuItems.map((item) => renderNavItem(item, { mobile: true }))
|
|
1945
|
+
}), (user || actions || onLogout) && /* @__PURE__ */ jsxs("div", {
|
|
1946
|
+
className: "mt-3 space-y-2 border-t border-[var(--dashboard-text-secondary,#6b7280)]/20 pt-3",
|
|
1947
|
+
children: [
|
|
1948
|
+
actions,
|
|
1949
|
+
user && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("button", {
|
|
1950
|
+
type: "button",
|
|
1951
|
+
onClick: () => {
|
|
1952
|
+
closeMenus();
|
|
1953
|
+
onUserClick?.();
|
|
1954
|
+
},
|
|
1955
|
+
className: "flex w-full items-center gap-3 rounded-lg bg-[var(--dashboard-background,#f2f2f2)] px-4 py-3 text-left transition-colors hover:bg-[var(--dashboard-primary,#37a501)]/8",
|
|
1956
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
1957
|
+
className: "flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-full bg-[var(--dashboard-primary,#37a501)]/12 text-[var(--dashboard-primary,#37a501)]",
|
|
1958
|
+
children: /* @__PURE__ */ jsx(User, { size: 17 })
|
|
1959
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
1960
|
+
className: "min-w-0",
|
|
1961
|
+
children: [
|
|
1962
|
+
user.subtitle && /* @__PURE__ */ jsx("p", {
|
|
1963
|
+
className: "truncate text-xs text-[var(--dashboard-text-secondary,#6b7280)]",
|
|
1964
|
+
children: user.subtitle
|
|
1965
|
+
}),
|
|
1966
|
+
/* @__PURE__ */ jsx("p", {
|
|
1967
|
+
className: "truncate text-sm font-semibold",
|
|
1968
|
+
children: user.name
|
|
1969
|
+
}),
|
|
1970
|
+
/* @__PURE__ */ jsx("p", {
|
|
1971
|
+
className: "truncate text-xs text-[var(--dashboard-text-secondary,#6b7280)]",
|
|
1972
|
+
children: user.email
|
|
1973
|
+
})
|
|
1974
|
+
]
|
|
1975
|
+
})]
|
|
1976
|
+
}), userEstablishments.length > 0 && /* @__PURE__ */ jsxs("div", {
|
|
1977
|
+
className: "space-y-1",
|
|
1978
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
1979
|
+
className: "px-4 pt-2 text-[11px] font-semibold uppercase tracking-wide text-[var(--dashboard-text-secondary,#6b7280)]",
|
|
1980
|
+
children: establishmentsLabel
|
|
1981
|
+
}), userEstablishments.map((establishment) => {
|
|
1982
|
+
const isDisabled = establishment.disabled || !onEstablishmentChange || establishment.active;
|
|
1983
|
+
return /* @__PURE__ */ jsxs("button", {
|
|
1984
|
+
type: "button",
|
|
1985
|
+
onClick: () => {
|
|
1986
|
+
if (isDisabled) return;
|
|
1987
|
+
closeMenus();
|
|
1988
|
+
onEstablishmentChange?.(establishment.id);
|
|
1989
|
+
},
|
|
1990
|
+
disabled: isDisabled,
|
|
1991
|
+
className: cn$25("flex w-full items-center gap-3 rounded-lg px-4 py-3 text-left transition-colors", establishment.active ? "bg-[var(--dashboard-primary,#37a501)]/10 text-[var(--dashboard-primary,#37a501)]" : "hover:bg-[var(--dashboard-primary,#37a501)]/8", isDisabled ? establishment.active ? "cursor-default" : "cursor-not-allowed opacity-60" : "cursor-pointer"),
|
|
1992
|
+
children: [
|
|
1993
|
+
/* @__PURE__ */ jsx("div", {
|
|
1994
|
+
className: "flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-[var(--dashboard-primary,#37a501)]/12 text-[var(--dashboard-primary,#37a501)]",
|
|
1995
|
+
children: /* @__PURE__ */ jsx(Building2, { size: 15 })
|
|
1996
|
+
}),
|
|
1997
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1998
|
+
className: "min-w-0 flex-1",
|
|
1999
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
2000
|
+
className: "truncate text-sm font-semibold",
|
|
2001
|
+
children: establishment.label
|
|
2002
|
+
}), establishment.description && /* @__PURE__ */ jsx("p", {
|
|
2003
|
+
className: "truncate text-xs text-[var(--dashboard-text-secondary,#6b7280)]",
|
|
2004
|
+
children: establishment.description
|
|
2005
|
+
})]
|
|
2006
|
+
}),
|
|
2007
|
+
establishment.active && /* @__PURE__ */ jsx(Check, {
|
|
2008
|
+
size: 16,
|
|
2009
|
+
className: "flex-shrink-0"
|
|
2010
|
+
})
|
|
2011
|
+
]
|
|
2012
|
+
}, establishment.id);
|
|
2013
|
+
})]
|
|
2014
|
+
})] }),
|
|
2015
|
+
onLogout && /* @__PURE__ */ jsxs("button", {
|
|
2016
|
+
type: "button",
|
|
2017
|
+
onClick: () => {
|
|
2018
|
+
closeMenus();
|
|
2019
|
+
onLogout();
|
|
2020
|
+
},
|
|
2021
|
+
className: "flex w-full items-center gap-3 rounded-lg px-4 py-3 text-sm font-medium transition-colors hover:bg-[var(--dashboard-primary,#37a501)]/8",
|
|
2022
|
+
children: [/* @__PURE__ */ jsx(LogOut, { size: 18 }), logoutLabel]
|
|
2023
|
+
})
|
|
2024
|
+
]
|
|
2025
|
+
})]
|
|
2026
|
+
})
|
|
2027
|
+
})]
|
|
2028
|
+
})
|
|
2029
|
+
] });
|
|
1442
2030
|
}
|
|
1443
2031
|
|
|
1444
2032
|
//#endregion
|
|
@@ -1502,16 +2090,23 @@ const trendConfigs = {
|
|
|
1502
2090
|
color: "text-[var(--dashboard-text-secondary,#64748B)] bg-[var(--dashboard-text-secondary,#64748B)]/8"
|
|
1503
2091
|
}
|
|
1504
2092
|
};
|
|
1505
|
-
function KPICard({ title, value, variation, trend, format = "number", benchmark, isLoading, className }) {
|
|
2093
|
+
function KPICard({ title, value, variation, trend, format = "number", benchmark, icon, isLoading, className }) {
|
|
1506
2094
|
if (isLoading) return /* @__PURE__ */ jsx(KPICardSkeleton, { className });
|
|
1507
2095
|
const trendConfig = trendConfigs[trend];
|
|
1508
2096
|
return /* @__PURE__ */ jsxs("div", {
|
|
1509
2097
|
className: cn$23("h-full w-full bg-[var(--dashboard-surface,#ffffff)] rounded-xl p-6 border border-[var(--dashboard-text-secondary,#64748B)]/12 transition-all duration-200 ease-out dashboard-shadow-sm hover:dashboard-shadow-md flex flex-col", className),
|
|
1510
2098
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
1511
|
-
className: "flex justify-between items-start mb-4",
|
|
1512
|
-
children: [/* @__PURE__ */
|
|
1513
|
-
className: "
|
|
1514
|
-
children:
|
|
2099
|
+
className: "flex justify-between items-start mb-4 gap-2",
|
|
2100
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
2101
|
+
className: "flex items-center gap-2 min-w-0",
|
|
2102
|
+
children: [icon && /* @__PURE__ */ jsx("span", {
|
|
2103
|
+
className: "shrink-0 text-[var(--dashboard-text-secondary,#64748B)]",
|
|
2104
|
+
"aria-hidden": "true",
|
|
2105
|
+
children: icon
|
|
2106
|
+
}), /* @__PURE__ */ jsx("h3", {
|
|
2107
|
+
className: "text-xs font-semibold uppercase tracking-wider text-[var(--dashboard-text-secondary,#64748B)] whitespace-nowrap truncate",
|
|
2108
|
+
children: title
|
|
2109
|
+
})]
|
|
1515
2110
|
}), benchmark && /* @__PURE__ */ jsx("span", {
|
|
1516
2111
|
className: "text-xs text-[var(--dashboard-text-secondary,#64748B)]/50 ml-2 whitespace-nowrap flex-shrink-0",
|
|
1517
2112
|
title: "Benchmark de referência",
|
|
@@ -1548,43 +2143,55 @@ function KPICardSkeleton({ className }) {
|
|
|
1548
2143
|
//#endregion
|
|
1549
2144
|
//#region src/components/PageLayout/index.tsx
|
|
1550
2145
|
const cn$22 = (...classes) => classes.filter(Boolean).join(" ");
|
|
1551
|
-
function PageLayout({ title, description, headerActions, children, contentPadding = true, sidebar, sidebarCollapsed = false, sidebarWidth = 280, sidebarCollapsedWidth = 109, className }) {
|
|
2146
|
+
function PageLayout({ title, description, headerActions, appHeader, children, contentPadding = true, sidebar, sidebarCollapsed = false, sidebarWidth = 280, sidebarCollapsedWidth = 109, className }) {
|
|
1552
2147
|
const marginLeft = sidebar ? sidebarCollapsed ? `max(0px, ${sidebarCollapsedWidth}px)` : `max(0px, ${sidebarWidth}px)` : "0px";
|
|
2148
|
+
const mainTopPadding = appHeader ? "pt-24" : sidebar ? "pt-16 xl:pt-0" : "pt-0";
|
|
2149
|
+
const layoutContainer = "mx-[var(--dashboard-page-gutter)]";
|
|
1553
2150
|
return /* @__PURE__ */ jsxs("div", {
|
|
1554
|
-
className: cn$22("min-h-screen bg-[var(--dashboard-background,#f2f2f2)]", className),
|
|
1555
|
-
children: [
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
2151
|
+
className: cn$22("min-h-screen bg-[var(--dashboard-background,#f2f2f2)] [--dashboard-page-gutter:1.5rem] sm:[--dashboard-page-gutter:2rem] lg:[--dashboard-page-gutter:2.5rem] xl:[--dashboard-page-gutter:3rem]", className),
|
|
2152
|
+
children: [
|
|
2153
|
+
appHeader,
|
|
2154
|
+
sidebar,
|
|
2155
|
+
/* @__PURE__ */ jsxs("main", {
|
|
2156
|
+
className: mainTopPadding,
|
|
2157
|
+
style: {
|
|
2158
|
+
marginLeft,
|
|
2159
|
+
transition: "margin-left 400ms cubic-bezier(0.4, 0, 0.2, 1)"
|
|
2160
|
+
},
|
|
2161
|
+
children: [
|
|
2162
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
1563
2163
|
@media (max-width: 1279px) {
|
|
1564
2164
|
main {
|
|
1565
2165
|
margin-left: 0 !important;
|
|
1566
2166
|
}
|
|
1567
2167
|
}
|
|
1568
2168
|
` }),
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
2169
|
+
/* @__PURE__ */ jsx("div", {
|
|
2170
|
+
className: cn$22(layoutContainer, "-mt-10 rounded-b-2xl border-b border-[var(--dashboard-text-secondary,#6b7280)]/20 bg-[var(--dashboard-surface,#ffffff)] px-7 pb-7 pt-16 sm:px-10 lg:px-12"),
|
|
2171
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
2172
|
+
className: "flex flex-col gap-5 lg:flex-row lg:items-end lg:justify-between",
|
|
2173
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
2174
|
+
className: "min-w-0",
|
|
2175
|
+
children: [/* @__PURE__ */ jsx("h1", {
|
|
2176
|
+
className: "text-2xl font-bold text-[var(--dashboard-text-primary,#2d2d2d)] sm:text-3xl",
|
|
2177
|
+
children: title
|
|
2178
|
+
}), description && /* @__PURE__ */ jsx("p", {
|
|
2179
|
+
className: "mt-2 text-sm font-medium text-[var(--dashboard-text-secondary,#6b7280)] sm:text-base",
|
|
2180
|
+
children: description
|
|
2181
|
+
})]
|
|
2182
|
+
}), headerActions && /* @__PURE__ */ jsx("div", {
|
|
2183
|
+
className: "flex max-w-full justify-start lg:justify-end",
|
|
2184
|
+
children: headerActions
|
|
2185
|
+
})]
|
|
2186
|
+
})
|
|
2187
|
+
}),
|
|
2188
|
+
/* @__PURE__ */ jsx("div", {
|
|
2189
|
+
className: contentPadding ? cn$22(layoutContainer, "py-6") : "",
|
|
2190
|
+
children
|
|
2191
|
+
})
|
|
2192
|
+
]
|
|
2193
|
+
})
|
|
2194
|
+
]
|
|
1588
2195
|
});
|
|
1589
2196
|
}
|
|
1590
2197
|
|
|
@@ -2108,18 +2715,236 @@ function ProgressBarList({ items, title, titleIcon, color, valueLabel = "itens",
|
|
|
2108
2715
|
//#region src/components/MetricPanel/index.tsx
|
|
2109
2716
|
Chart.register(CategoryScale, LinearScale, PointElement, LineElement, Title$1, Tooltip$1, Legend, Filler);
|
|
2110
2717
|
const cn$16 = (...classes) => classes.filter(Boolean).join(" ");
|
|
2111
|
-
function
|
|
2718
|
+
function formatMetricValue(value, format) {
|
|
2719
|
+
switch (format) {
|
|
2720
|
+
case "currency": return new Intl.NumberFormat("pt-BR", {
|
|
2721
|
+
style: "currency",
|
|
2722
|
+
currency: "BRL"
|
|
2723
|
+
}).format(value);
|
|
2724
|
+
case "percentage": return `${value.toFixed(2)}%`;
|
|
2725
|
+
case "rating": return value.toFixed(2);
|
|
2726
|
+
default: return new Intl.NumberFormat("pt-BR").format(Math.round(value));
|
|
2727
|
+
}
|
|
2728
|
+
}
|
|
2729
|
+
function calculateVariation(current, previous) {
|
|
2730
|
+
if (previous === 0) return 0;
|
|
2731
|
+
return (current - previous) / previous * 100;
|
|
2732
|
+
}
|
|
2733
|
+
function escapeHtml(value) {
|
|
2734
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
2735
|
+
}
|
|
2736
|
+
function getTooltipDateInfo(label) {
|
|
2737
|
+
const dayNames = [
|
|
2738
|
+
"Domingo",
|
|
2739
|
+
"Segunda",
|
|
2740
|
+
"Terca",
|
|
2741
|
+
"Quarta",
|
|
2742
|
+
"Quinta",
|
|
2743
|
+
"Sexta",
|
|
2744
|
+
"Sabado"
|
|
2745
|
+
];
|
|
2746
|
+
const [day, month] = label.split("/").map(Number);
|
|
2747
|
+
if (!day || !month) return {
|
|
2748
|
+
dayName: "",
|
|
2749
|
+
previousDate: ""
|
|
2750
|
+
};
|
|
2751
|
+
const date = new Date((/* @__PURE__ */ new Date()).getFullYear(), month - 1, day);
|
|
2752
|
+
const previousDate = new Date(date);
|
|
2753
|
+
previousDate.setDate(previousDate.getDate() - 7);
|
|
2754
|
+
return {
|
|
2755
|
+
dayName: dayNames[date.getDay()],
|
|
2756
|
+
previousDate: `${String(previousDate.getDate()).padStart(2, "0")}/${String(previousDate.getMonth() + 1).padStart(2, "0")}`
|
|
2757
|
+
};
|
|
2758
|
+
}
|
|
2759
|
+
function MetricPanel({ title, titleIcon: TitleIcon, metrics, chartData, color, secondaryColor, onActionClick, actionLabel, tooltipConfig, isLoading = false, className }) {
|
|
2112
2760
|
const [selectedMetricKey, setSelectedMetricKey] = useState(metrics[0]?.key);
|
|
2113
2761
|
const [isMobile, setIsMobile] = useState(false);
|
|
2762
|
+
const hideTooltipTimeoutRef = useRef(null);
|
|
2763
|
+
const isTooltipHoveredRef = useRef(false);
|
|
2114
2764
|
useEffect(() => {
|
|
2115
2765
|
const check = () => setIsMobile(window.innerWidth < 768);
|
|
2116
2766
|
check();
|
|
2117
2767
|
window.addEventListener("resize", check);
|
|
2118
|
-
return () =>
|
|
2768
|
+
return () => {
|
|
2769
|
+
window.removeEventListener("resize", check);
|
|
2770
|
+
if (hideTooltipTimeoutRef.current) clearTimeout(hideTooltipTimeoutRef.current);
|
|
2771
|
+
};
|
|
2119
2772
|
}, []);
|
|
2120
2773
|
const currentMetric = metrics.find((m) => m.key === selectedMetricKey) || metrics[0];
|
|
2121
2774
|
const primaryColor = color || (typeof document !== "undefined" ? getComputedStyle(document.documentElement).getPropertyValue("--dashboard-primary").trim() : "") || "#37a501";
|
|
2122
2775
|
const secColor = secondaryColor || `${primaryColor}66`;
|
|
2776
|
+
const renderExternalTooltip = (context) => {
|
|
2777
|
+
const { chart, tooltip } = context;
|
|
2778
|
+
const parent = chart.canvas.parentElement;
|
|
2779
|
+
if (!parent) return;
|
|
2780
|
+
let tooltipEl = parent.querySelector(":scope > .metric-panel-chart-tooltip");
|
|
2781
|
+
if (!tooltipEl) {
|
|
2782
|
+
tooltipEl = document.createElement("div");
|
|
2783
|
+
tooltipEl.className = "metric-panel-chart-tooltip";
|
|
2784
|
+
tooltipEl.style.position = "absolute";
|
|
2785
|
+
tooltipEl.style.pointerEvents = "auto";
|
|
2786
|
+
tooltipEl.style.transition = "opacity 0.2s ease";
|
|
2787
|
+
tooltipEl.style.zIndex = "100";
|
|
2788
|
+
tooltipEl.style.opacity = "0";
|
|
2789
|
+
const createdTooltipEl = tooltipEl;
|
|
2790
|
+
createdTooltipEl.addEventListener("mouseenter", () => {
|
|
2791
|
+
isTooltipHoveredRef.current = true;
|
|
2792
|
+
if (hideTooltipTimeoutRef.current) {
|
|
2793
|
+
clearTimeout(hideTooltipTimeoutRef.current);
|
|
2794
|
+
hideTooltipTimeoutRef.current = null;
|
|
2795
|
+
}
|
|
2796
|
+
});
|
|
2797
|
+
createdTooltipEl.addEventListener("mouseleave", () => {
|
|
2798
|
+
isTooltipHoveredRef.current = false;
|
|
2799
|
+
createdTooltipEl.style.opacity = "0";
|
|
2800
|
+
});
|
|
2801
|
+
parent.appendChild(createdTooltipEl);
|
|
2802
|
+
}
|
|
2803
|
+
if (hideTooltipTimeoutRef.current) {
|
|
2804
|
+
clearTimeout(hideTooltipTimeoutRef.current);
|
|
2805
|
+
hideTooltipTimeoutRef.current = null;
|
|
2806
|
+
}
|
|
2807
|
+
if (tooltip.opacity === 0) {
|
|
2808
|
+
hideTooltipTimeoutRef.current = setTimeout(() => {
|
|
2809
|
+
if (!isTooltipHoveredRef.current && tooltipEl) tooltipEl.style.opacity = "0";
|
|
2810
|
+
}, 300);
|
|
2811
|
+
return;
|
|
2812
|
+
}
|
|
2813
|
+
const dataPoint = tooltip.dataPoints?.find((point) => point.datasetIndex === 0);
|
|
2814
|
+
if (!dataPoint) {
|
|
2815
|
+
tooltipEl.style.opacity = "0";
|
|
2816
|
+
return;
|
|
2817
|
+
}
|
|
2818
|
+
const dataIndex = dataPoint.dataIndex;
|
|
2819
|
+
const label = dataPoint.label;
|
|
2820
|
+
const currentValue = typeof dataPoint.parsed.y === "number" ? dataPoint.parsed.y : 0;
|
|
2821
|
+
const previousValue = chartData.metrics[currentMetric.key]?.previousPeriod[dataIndex] || 0;
|
|
2822
|
+
const variation = calculateVariation(currentValue, previousValue);
|
|
2823
|
+
const formattedValue = formatMetricValue(currentValue, currentMetric.format);
|
|
2824
|
+
const formattedPrevious = formatMetricValue(previousValue, currentMetric.format);
|
|
2825
|
+
const { dayName, previousDate } = getTooltipDateInfo(label);
|
|
2826
|
+
const metricUnit = currentMetric.unit || "";
|
|
2827
|
+
const isButtonDisabled = currentValue === 0;
|
|
2828
|
+
const safeLabel = escapeHtml(label);
|
|
2829
|
+
const safeDayName = escapeHtml(dayName);
|
|
2830
|
+
const safePreviousDate = escapeHtml(previousDate);
|
|
2831
|
+
const safeMetricUnit = escapeHtml(metricUnit);
|
|
2832
|
+
const variationSign = variation > 0 ? "+" : "";
|
|
2833
|
+
const variationIcon = variation >= 0 ? "▲" : "▼";
|
|
2834
|
+
const variationColor = variation >= 0 ? "var(--dashboard-status-success,#10B981)" : "var(--dashboard-status-danger,#EF4444)";
|
|
2835
|
+
if (tooltipConfig?.customContent) tooltipEl.innerHTML = tooltipConfig.customContent({
|
|
2836
|
+
value: currentValue,
|
|
2837
|
+
previousValue,
|
|
2838
|
+
variation,
|
|
2839
|
+
date: label,
|
|
2840
|
+
dayName,
|
|
2841
|
+
previousDate,
|
|
2842
|
+
formattedValue,
|
|
2843
|
+
formattedPrevious,
|
|
2844
|
+
metricUnit
|
|
2845
|
+
});
|
|
2846
|
+
else tooltipEl.innerHTML = `
|
|
2847
|
+
<div style="
|
|
2848
|
+
background: var(--dashboard-surface,#ffffff);
|
|
2849
|
+
border-radius: 8px;
|
|
2850
|
+
box-shadow: 0 8px 20px rgba(15, 23, 42, 0.14);
|
|
2851
|
+
border: 1px solid rgba(93, 114, 128, 0.2);
|
|
2852
|
+
color: var(--dashboard-text-primary,#2d2d2d);
|
|
2853
|
+
padding: 12px;
|
|
2854
|
+
min-width: 220px;
|
|
2855
|
+
max-width: 250px;
|
|
2856
|
+
font-family: inherit;
|
|
2857
|
+
">
|
|
2858
|
+
<div style="
|
|
2859
|
+
font-size: 11px;
|
|
2860
|
+
font-weight: 500;
|
|
2861
|
+
color: var(--dashboard-text-secondary,#6b7280);
|
|
2862
|
+
margin-bottom: 8px;
|
|
2863
|
+
">
|
|
2864
|
+
${safeDayName ? `${safeDayName} ` : ""}${safeLabel}
|
|
2865
|
+
</div>
|
|
2866
|
+
<div style="
|
|
2867
|
+
display: flex;
|
|
2868
|
+
align-items: baseline;
|
|
2869
|
+
gap: 6px;
|
|
2870
|
+
margin-bottom: 10px;
|
|
2871
|
+
">
|
|
2872
|
+
<div style="
|
|
2873
|
+
font-size: 22px;
|
|
2874
|
+
font-weight: 700;
|
|
2875
|
+
color: ${primaryColor};
|
|
2876
|
+
line-height: 1;
|
|
2877
|
+
">
|
|
2878
|
+
${escapeHtml(formattedValue)}${safeMetricUnit ? ` ${safeMetricUnit}` : ""}
|
|
2879
|
+
</div>
|
|
2880
|
+
<div style="
|
|
2881
|
+
display: flex;
|
|
2882
|
+
align-items: center;
|
|
2883
|
+
gap: 3px;
|
|
2884
|
+
color: ${variationColor};
|
|
2885
|
+
font-size: 13px;
|
|
2886
|
+
font-weight: 600;
|
|
2887
|
+
">
|
|
2888
|
+
<span style="font-size: 10px;">${variationIcon}</span>
|
|
2889
|
+
<span>${variationSign}${Math.abs(variation).toFixed(2)}%</span>
|
|
2890
|
+
</div>
|
|
2891
|
+
</div>
|
|
2892
|
+
<div style="
|
|
2893
|
+
font-size: 11px;
|
|
2894
|
+
color: var(--dashboard-text-secondary,#6b7280);
|
|
2895
|
+
line-height: 1.35;
|
|
2896
|
+
margin-bottom: ${tooltipConfig?.showButton ? "10px" : "0"};
|
|
2897
|
+
padding-bottom: ${tooltipConfig?.showButton ? "10px" : "0"};
|
|
2898
|
+
border-bottom: ${tooltipConfig?.showButton ? "1px solid rgba(93, 114, 128, 0.2)" : "none"};
|
|
2899
|
+
">
|
|
2900
|
+
em relacao aos <strong style="color: var(--dashboard-text-primary,#2d2d2d);">${escapeHtml(formattedPrevious)}${safeMetricUnit ? ` ${safeMetricUnit}` : ""}</strong>${safePreviousDate ? ` do dia <strong style="color: var(--dashboard-text-primary,#2d2d2d);">${safePreviousDate}</strong>` : ""}
|
|
2901
|
+
</div>
|
|
2902
|
+
${tooltipConfig?.showButton && tooltipConfig.buttonLabel ? `
|
|
2903
|
+
<button type="button" data-tooltip-action ${isButtonDisabled ? "disabled" : ""} style="
|
|
2904
|
+
width: 100%;
|
|
2905
|
+
padding: 8px 12px;
|
|
2906
|
+
background: ${isButtonDisabled ? "rgba(93, 114, 128, 0.08)" : "var(--dashboard-surface,#ffffff)"};
|
|
2907
|
+
color: ${isButtonDisabled ? "var(--dashboard-text-secondary,#6b7280)" : primaryColor};
|
|
2908
|
+
border: 2px solid ${isButtonDisabled ? "rgba(93, 114, 128, 0.2)" : primaryColor};
|
|
2909
|
+
border-radius: 6px;
|
|
2910
|
+
font-size: 13px;
|
|
2911
|
+
font-weight: 600;
|
|
2912
|
+
font-family: inherit;
|
|
2913
|
+
cursor: ${isButtonDisabled ? "not-allowed" : "pointer"};
|
|
2914
|
+
opacity: ${isButtonDisabled ? "0.65" : "1"};
|
|
2915
|
+
">
|
|
2916
|
+
${escapeHtml(tooltipConfig.buttonLabel)}
|
|
2917
|
+
</button>
|
|
2918
|
+
` : ""}
|
|
2919
|
+
</div>
|
|
2920
|
+
`;
|
|
2921
|
+
const actionButton = tooltipEl.querySelector("[data-tooltip-action]");
|
|
2922
|
+
if (actionButton && !isButtonDisabled) {
|
|
2923
|
+
actionButton.onclick = () => tooltipConfig?.onButtonClick?.(dataIndex, label);
|
|
2924
|
+
actionButton.onmouseenter = () => {
|
|
2925
|
+
actionButton.style.background = primaryColor;
|
|
2926
|
+
actionButton.style.color = "#ffffff";
|
|
2927
|
+
};
|
|
2928
|
+
actionButton.onmouseleave = () => {
|
|
2929
|
+
actionButton.style.background = "var(--dashboard-surface,#ffffff)";
|
|
2930
|
+
actionButton.style.color = primaryColor;
|
|
2931
|
+
};
|
|
2932
|
+
}
|
|
2933
|
+
const tooltipWidth = 250;
|
|
2934
|
+
const tooltipHeight = tooltipConfig?.showButton ? 180 : 140;
|
|
2935
|
+
const offsetX = 15;
|
|
2936
|
+
const centerY = Math.max(0, (chart.height - tooltipHeight) / 2);
|
|
2937
|
+
const isNearRightEdge = tooltip.caretX > chart.width - tooltipWidth - offsetX;
|
|
2938
|
+
tooltipEl.style.opacity = "1";
|
|
2939
|
+
tooltipEl.style.top = `${centerY}px`;
|
|
2940
|
+
if (isNearRightEdge) {
|
|
2941
|
+
tooltipEl.style.left = "auto";
|
|
2942
|
+
tooltipEl.style.right = `${chart.width - tooltip.caretX + offsetX}px`;
|
|
2943
|
+
} else {
|
|
2944
|
+
tooltipEl.style.left = `${tooltip.caretX + offsetX}px`;
|
|
2945
|
+
tooltipEl.style.right = "auto";
|
|
2946
|
+
}
|
|
2947
|
+
};
|
|
2123
2948
|
const data = {
|
|
2124
2949
|
labels: chartData.labels,
|
|
2125
2950
|
datasets: [{
|
|
@@ -2171,14 +2996,18 @@ function MetricPanel({ title, titleIcon: TitleIcon, metrics, chartData, color, s
|
|
|
2171
2996
|
color: "var(--dashboard-text-secondary, #6b7280)"
|
|
2172
2997
|
}
|
|
2173
2998
|
},
|
|
2174
|
-
tooltip: {
|
|
2999
|
+
tooltip: { ...tooltipConfig ? {
|
|
3000
|
+
enabled: false,
|
|
3001
|
+
position: "nearest",
|
|
3002
|
+
external: tooltipConfig.enabled ? renderExternalTooltip : void 0
|
|
3003
|
+
} : {
|
|
2175
3004
|
backgroundColor: "rgba(45, 45, 45, 0.95)",
|
|
2176
3005
|
titleColor: "#fff",
|
|
2177
3006
|
bodyColor: "#fff",
|
|
2178
3007
|
borderColor: primaryColor,
|
|
2179
3008
|
borderWidth: 1,
|
|
2180
3009
|
padding: 12
|
|
2181
|
-
}
|
|
3010
|
+
} }
|
|
2182
3011
|
},
|
|
2183
3012
|
scales: {
|
|
2184
3013
|
x: {
|
|
@@ -3664,13 +4493,15 @@ function FileUpload({ accept, maxSize, multiple = false, onUpload, onRemove, pre
|
|
|
3664
4493
|
const cn$7 = (...classes) => classes.filter(Boolean).join(" ");
|
|
3665
4494
|
function Tooltip({ content, position = "top", delay = 200, children, className, maxWidth = 240 }) {
|
|
3666
4495
|
const [visible, setVisible] = useState(false);
|
|
4496
|
+
const [positioned, setPositioned] = useState(false);
|
|
3667
4497
|
const [coords, setCoords] = useState({
|
|
3668
4498
|
top: 0,
|
|
3669
4499
|
left: 0
|
|
3670
4500
|
});
|
|
4501
|
+
const [actualPosition, setActualPosition] = useState(position);
|
|
3671
4502
|
const triggerRef = useRef(null);
|
|
3672
4503
|
const tooltipRef = useRef(null);
|
|
3673
|
-
const timeoutRef = useRef();
|
|
4504
|
+
const timeoutRef = useRef(null);
|
|
3674
4505
|
const idRef = useRef(`tooltip-${Math.random().toString(36).slice(2, 9)}`);
|
|
3675
4506
|
const calculatePosition = useCallback(() => {
|
|
3676
4507
|
if (!triggerRef.current || !tooltipRef.current) return;
|
|
@@ -3679,6 +4510,7 @@ function Tooltip({ content, position = "top", delay = 200, children, className,
|
|
|
3679
4510
|
const gap = 8;
|
|
3680
4511
|
let top = 0;
|
|
3681
4512
|
let left = 0;
|
|
4513
|
+
let resolvedPosition = position;
|
|
3682
4514
|
switch (position) {
|
|
3683
4515
|
case "top":
|
|
3684
4516
|
top = trigger.top - tooltip.height - gap;
|
|
@@ -3697,31 +4529,65 @@ function Tooltip({ content, position = "top", delay = 200, children, className,
|
|
|
3697
4529
|
left = trigger.right + gap;
|
|
3698
4530
|
break;
|
|
3699
4531
|
}
|
|
4532
|
+
if (position === "top" && top < 8) {
|
|
4533
|
+
top = trigger.bottom + gap;
|
|
4534
|
+
resolvedPosition = "bottom";
|
|
4535
|
+
} else if (position === "bottom" && top + tooltip.height > window.innerHeight - 8) {
|
|
4536
|
+
top = trigger.top - tooltip.height - gap;
|
|
4537
|
+
resolvedPosition = "top";
|
|
4538
|
+
}
|
|
3700
4539
|
left = Math.max(8, Math.min(left, window.innerWidth - tooltip.width - 8));
|
|
3701
4540
|
top = Math.max(8, Math.min(top, window.innerHeight - tooltip.height - 8));
|
|
3702
4541
|
setCoords({
|
|
3703
4542
|
top,
|
|
3704
4543
|
left
|
|
3705
4544
|
});
|
|
4545
|
+
setActualPosition(resolvedPosition);
|
|
4546
|
+
setPositioned(true);
|
|
3706
4547
|
}, [position]);
|
|
3707
4548
|
const show = useCallback(() => {
|
|
3708
4549
|
timeoutRef.current = setTimeout(() => {
|
|
3709
4550
|
setVisible(true);
|
|
4551
|
+
setPositioned(false);
|
|
3710
4552
|
}, delay);
|
|
3711
4553
|
}, [delay]);
|
|
3712
4554
|
const hide = useCallback(() => {
|
|
3713
4555
|
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
3714
4556
|
setVisible(false);
|
|
4557
|
+
setPositioned(false);
|
|
3715
4558
|
}, []);
|
|
3716
4559
|
useEffect(() => {
|
|
3717
|
-
if (visible) requestAnimationFrame(
|
|
4560
|
+
if (visible) requestAnimationFrame(() => {
|
|
4561
|
+
requestAnimationFrame(calculatePosition);
|
|
4562
|
+
});
|
|
3718
4563
|
}, [visible, calculatePosition]);
|
|
3719
4564
|
useEffect(() => {
|
|
3720
4565
|
return () => {
|
|
3721
4566
|
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
3722
4567
|
};
|
|
3723
4568
|
}, []);
|
|
3724
|
-
|
|
4569
|
+
let trigger;
|
|
4570
|
+
if (isValidElement(children)) trigger = cloneElement(children, {
|
|
4571
|
+
ref: triggerRef,
|
|
4572
|
+
onMouseEnter: (e) => {
|
|
4573
|
+
show();
|
|
4574
|
+
children.props?.onMouseEnter?.(e);
|
|
4575
|
+
},
|
|
4576
|
+
onMouseLeave: (e) => {
|
|
4577
|
+
hide();
|
|
4578
|
+
children.props?.onMouseLeave?.(e);
|
|
4579
|
+
},
|
|
4580
|
+
onFocus: (e) => {
|
|
4581
|
+
show();
|
|
4582
|
+
children.props?.onFocus?.(e);
|
|
4583
|
+
},
|
|
4584
|
+
onBlur: (e) => {
|
|
4585
|
+
hide();
|
|
4586
|
+
children.props?.onBlur?.(e);
|
|
4587
|
+
},
|
|
4588
|
+
"aria-describedby": visible ? idRef.current : void 0
|
|
4589
|
+
});
|
|
4590
|
+
else trigger = /* @__PURE__ */ jsx("span", {
|
|
3725
4591
|
ref: triggerRef,
|
|
3726
4592
|
onMouseEnter: show,
|
|
3727
4593
|
onMouseLeave: hide,
|
|
@@ -3730,20 +4596,85 @@ function Tooltip({ content, position = "top", delay = 200, children, className,
|
|
|
3730
4596
|
"aria-describedby": visible ? idRef.current : void 0,
|
|
3731
4597
|
className: "inline-flex",
|
|
3732
4598
|
children
|
|
3733
|
-
})
|
|
4599
|
+
});
|
|
4600
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [trigger, visible && typeof document !== "undefined" && createPortal(/* @__PURE__ */ jsxs("div", {
|
|
3734
4601
|
ref: tooltipRef,
|
|
3735
4602
|
id: idRef.current,
|
|
3736
4603
|
role: "tooltip",
|
|
3737
|
-
className: cn$7("fixed z-[10002] rounded-md px-3 py-2 text-xs font-medium", "bg-[var(--dashboard-
|
|
4604
|
+
className: cn$7("fixed z-[10002] rounded-md px-3 py-2 text-xs font-medium", "bg-[var(--dashboard-tooltip-bg,#1a1a1a)] text-[var(--dashboard-tooltip-text,#ffffff)]", "shadow-lg pointer-events-none", positioned && "dashboard-animate-fade-in", className),
|
|
3738
4605
|
style: {
|
|
3739
4606
|
top: coords.top,
|
|
3740
4607
|
left: coords.left,
|
|
3741
|
-
maxWidth
|
|
4608
|
+
maxWidth,
|
|
4609
|
+
opacity: positioned ? 1 : 0
|
|
3742
4610
|
},
|
|
3743
|
-
children: content
|
|
4611
|
+
children: [content, /* @__PURE__ */ jsx("span", { className: cn$7("absolute w-0 h-0 border-[5px]", {
|
|
4612
|
+
top: "left-1/2 -translate-x-1/2 top-full border-t-[var(--dashboard-tooltip-bg,#1a1a1a)] border-x-transparent border-b-transparent",
|
|
4613
|
+
bottom: "left-1/2 -translate-x-1/2 bottom-full border-b-[var(--dashboard-tooltip-bg,#1a1a1a)] border-x-transparent border-t-transparent",
|
|
4614
|
+
left: "top-1/2 -translate-y-1/2 left-full border-l-[var(--dashboard-tooltip-bg,#1a1a1a)] border-y-transparent border-r-transparent",
|
|
4615
|
+
right: "top-1/2 -translate-y-1/2 right-full border-r-[var(--dashboard-tooltip-bg,#1a1a1a)] border-y-transparent border-l-transparent"
|
|
4616
|
+
}[actualPosition]) })]
|
|
3744
4617
|
}), document.body)] });
|
|
3745
4618
|
}
|
|
3746
4619
|
|
|
4620
|
+
//#endregion
|
|
4621
|
+
//#region src/components/InfoTooltip/index.tsx
|
|
4622
|
+
function InfoTooltip({ content, term, size = 14, position = "top", maxWidth = 280, className }) {
|
|
4623
|
+
return /* @__PURE__ */ jsx(Tooltip, {
|
|
4624
|
+
content: term ? /* @__PURE__ */ jsxs("span", {
|
|
4625
|
+
className: "text-xs leading-relaxed",
|
|
4626
|
+
children: [
|
|
4627
|
+
/* @__PURE__ */ jsx("strong", { children: term }),
|
|
4628
|
+
" — ",
|
|
4629
|
+
content
|
|
4630
|
+
]
|
|
4631
|
+
}) : /* @__PURE__ */ jsx("span", {
|
|
4632
|
+
className: "text-xs leading-relaxed",
|
|
4633
|
+
children: content
|
|
4634
|
+
}),
|
|
4635
|
+
position,
|
|
4636
|
+
maxWidth,
|
|
4637
|
+
children: /* @__PURE__ */ jsx("button", {
|
|
4638
|
+
type: "button",
|
|
4639
|
+
tabIndex: 0,
|
|
4640
|
+
"aria-label": term ? `Informação sobre ${term}` : "Mais informações",
|
|
4641
|
+
className: [
|
|
4642
|
+
"inline-flex items-center justify-center rounded-full",
|
|
4643
|
+
"text-[var(--dashboard-text-secondary,#6b7280)]",
|
|
4644
|
+
"hover:text-[var(--dashboard-text-primary,#2d2d2d)]",
|
|
4645
|
+
"hover:bg-[var(--dashboard-text-secondary,#6b7280)]/10",
|
|
4646
|
+
"transition-colors duration-150 cursor-help",
|
|
4647
|
+
"focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--dashboard-primary,#2563EB)]/40",
|
|
4648
|
+
className
|
|
4649
|
+
].filter(Boolean).join(" "),
|
|
4650
|
+
style: {
|
|
4651
|
+
width: size + 6,
|
|
4652
|
+
height: size + 6
|
|
4653
|
+
},
|
|
4654
|
+
children: /* @__PURE__ */ jsxs("svg", {
|
|
4655
|
+
width: size,
|
|
4656
|
+
height: size,
|
|
4657
|
+
viewBox: "0 0 24 24",
|
|
4658
|
+
fill: "none",
|
|
4659
|
+
stroke: "currentColor",
|
|
4660
|
+
strokeWidth: "2",
|
|
4661
|
+
strokeLinecap: "round",
|
|
4662
|
+
strokeLinejoin: "round",
|
|
4663
|
+
"aria-hidden": "true",
|
|
4664
|
+
children: [
|
|
4665
|
+
/* @__PURE__ */ jsx("circle", {
|
|
4666
|
+
cx: "12",
|
|
4667
|
+
cy: "12",
|
|
4668
|
+
r: "10"
|
|
4669
|
+
}),
|
|
4670
|
+
/* @__PURE__ */ jsx("path", { d: "M12 16v-4" }),
|
|
4671
|
+
/* @__PURE__ */ jsx("path", { d: "M12 8h.01" })
|
|
4672
|
+
]
|
|
4673
|
+
})
|
|
4674
|
+
})
|
|
4675
|
+
});
|
|
4676
|
+
}
|
|
4677
|
+
|
|
3747
4678
|
//#endregion
|
|
3748
4679
|
//#region src/components/Breadcrumb/index.tsx
|
|
3749
4680
|
const cn$6 = (...classes) => classes.filter(Boolean).join(" ");
|
|
@@ -4260,7 +5191,7 @@ const defaultColorMap = {
|
|
|
4260
5191
|
};
|
|
4261
5192
|
const sizeClasses = {
|
|
4262
5193
|
sm: "px-2 py-0.5 text-xs",
|
|
4263
|
-
md: "px-2.5 py-1 text-
|
|
5194
|
+
md: "px-2.5 py-1 text-sm",
|
|
4264
5195
|
lg: "px-3 py-1 text-sm"
|
|
4265
5196
|
};
|
|
4266
5197
|
const dotSizeClasses = {
|
|
@@ -4309,7 +5240,9 @@ const defaultConfig = {
|
|
|
4309
5240
|
statusDanger: "#DC2626",
|
|
4310
5241
|
statusWarning: "#D97706",
|
|
4311
5242
|
statusInfo: "#2563EB",
|
|
4312
|
-
statusNeutral: "#64748B"
|
|
5243
|
+
statusNeutral: "#64748B",
|
|
5244
|
+
tooltipBg: "#1a1a1a",
|
|
5245
|
+
tooltipText: "#ffffff"
|
|
4313
5246
|
},
|
|
4314
5247
|
components: {
|
|
4315
5248
|
modal: {
|
|
@@ -4523,6 +5456,8 @@ function CSSVarsInjector({ config }) {
|
|
|
4523
5456
|
root.style.setProperty("--dashboard-status-warning", colors.statusWarning);
|
|
4524
5457
|
root.style.setProperty("--dashboard-status-info", colors.statusInfo);
|
|
4525
5458
|
root.style.setProperty("--dashboard-status-neutral", colors.statusNeutral);
|
|
5459
|
+
root.style.setProperty("--dashboard-tooltip-bg", colors.tooltipBg);
|
|
5460
|
+
root.style.setProperty("--dashboard-tooltip-text", colors.tooltipText);
|
|
4526
5461
|
}, [config]);
|
|
4527
5462
|
return null;
|
|
4528
5463
|
}
|
|
@@ -4535,5 +5470,50 @@ function DashboardProvider({ config: configOverrides, children }) {
|
|
|
4535
5470
|
}
|
|
4536
5471
|
|
|
4537
5472
|
//#endregion
|
|
4538
|
-
|
|
5473
|
+
//#region src/config/sizes.ts
|
|
5474
|
+
const componentSizes = {
|
|
5475
|
+
sm: {
|
|
5476
|
+
height: "h-8",
|
|
5477
|
+
paddingX: "px-3",
|
|
5478
|
+
paddingY: "py-0",
|
|
5479
|
+
font: "text-xs"
|
|
5480
|
+
},
|
|
5481
|
+
md: {
|
|
5482
|
+
height: "h-9",
|
|
5483
|
+
paddingX: "px-4",
|
|
5484
|
+
paddingY: "py-0",
|
|
5485
|
+
font: "text-sm"
|
|
5486
|
+
},
|
|
5487
|
+
lg: {
|
|
5488
|
+
height: "h-10",
|
|
5489
|
+
paddingX: "px-6",
|
|
5490
|
+
paddingY: "py-0",
|
|
5491
|
+
font: "text-base"
|
|
5492
|
+
}
|
|
5493
|
+
};
|
|
5494
|
+
const badgeSizes = {
|
|
5495
|
+
sm: {
|
|
5496
|
+
padding: "px-2 py-0.5",
|
|
5497
|
+
font: "text-xs"
|
|
5498
|
+
},
|
|
5499
|
+
md: {
|
|
5500
|
+
padding: "px-3 py-1",
|
|
5501
|
+
font: "text-sm"
|
|
5502
|
+
},
|
|
5503
|
+
lg: {
|
|
5504
|
+
padding: "px-3 py-1",
|
|
5505
|
+
font: "text-sm"
|
|
5506
|
+
}
|
|
5507
|
+
};
|
|
5508
|
+
const modalSizes = {
|
|
5509
|
+
sm: "max-w-sm",
|
|
5510
|
+
md: "max-w-md",
|
|
5511
|
+
lg: "max-w-lg",
|
|
5512
|
+
xl: "max-w-2xl",
|
|
5513
|
+
"2xl": "max-w-4xl",
|
|
5514
|
+
"3xl": "max-w-screen-xl"
|
|
5515
|
+
};
|
|
5516
|
+
|
|
5517
|
+
//#endregion
|
|
5518
|
+
export { Alert, AuthLayout, BadgeStatus, Breadcrumb, Button, Callout, Card, Checkbox, CodeBlock, CodeInput, Combobox, ComparisonLineChart, DashboardProvider, DataGrid, DatePicker, DateRangePicker, DoughnutChart, Dropdown, EmptyState, FileUpload, FilterBar, FormField, Header, HorizontalBarChart, InfoTooltip, Input, KPICard, Loading, LoadingProvider, MetricPanel, Modal, NotificationsProvider, PageLayout, Pagination, ProgressBarList, Sidebar, Skeleton, StatusBadge, Stepper, Table, TableBody, TableEmpty, TableHeader, TableSkeleton, Tabs, ThemeProvider, ThemeSwitcher, Title, Toast, ToggleSwitch, Tooltip, TreeView, VerticalBarChart, badgeSizes, componentSizes, createColumnHelper, createConfig, defaultConfig, modalSizes, useConfig, useLoading, useNotifications, useTheme };
|
|
4539
5519
|
//# sourceMappingURL=index.mjs.map
|