@evolution-soft/ui 1.0.0 → 1.0.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.
Files changed (78) hide show
  1. package/cli/index.js +386 -0
  2. package/components/button-icon-lottie/index.tsx +46 -0
  3. package/components/fullscreen-mode/index.tsx +82 -0
  4. package/components/header/components/buttons.tsx +102 -0
  5. package/components/header/index.tsx +146 -0
  6. package/components/loading-default/index.tsx +90 -0
  7. package/components/lottie-icon/index.tsx +78 -0
  8. package/components/not-found-default/index.tsx +68 -0
  9. package/components/settings-modal/index.tsx +225 -0
  10. package/components/sidebar/index.tsx +645 -0
  11. package/components/subtitle/index.tsx +60 -0
  12. package/components/theme-transition/index.tsx +142 -0
  13. package/components/title/index.tsx +66 -0
  14. package/components/tooltip-indicator/index.tsx +30 -0
  15. package/components/ui/accordion.tsx +66 -0
  16. package/components/ui/alert-dialog.tsx +157 -0
  17. package/components/ui/alert.tsx +66 -0
  18. package/components/ui/aspect-ratio.tsx +11 -0
  19. package/components/ui/avatar.tsx +53 -0
  20. package/components/ui/badge.tsx +46 -0
  21. package/components/ui/breadcrumb.tsx +109 -0
  22. package/components/ui/button.tsx +58 -0
  23. package/components/ui/calendar.tsx +78 -0
  24. package/components/ui/card.tsx +92 -0
  25. package/components/ui/carousel.tsx +241 -0
  26. package/components/ui/chart.tsx +360 -0
  27. package/components/ui/checkbox.tsx +32 -0
  28. package/components/ui/collapsible.tsx +33 -0
  29. package/components/ui/command.tsx +177 -0
  30. package/components/ui/context-menu.tsx +252 -0
  31. package/components/ui/dialog.tsx +135 -0
  32. package/components/ui/divisor.tsx +9 -0
  33. package/components/ui/drawer.tsx +132 -0
  34. package/components/ui/dropdown-menu.tsx +257 -0
  35. package/components/ui/emoji-picker.tsx +76 -0
  36. package/components/ui/form.tsx +168 -0
  37. package/components/ui/hover-card.tsx +44 -0
  38. package/components/ui/input-mask.tsx +46 -0
  39. package/components/ui/input-otp.tsx +77 -0
  40. package/components/ui/input.tsx +61 -0
  41. package/components/ui/label.tsx +24 -0
  42. package/components/ui/menubar.tsx +276 -0
  43. package/components/ui/multiselect.tsx +105 -0
  44. package/components/ui/navigation-menu.tsx +168 -0
  45. package/components/ui/pagination.tsx +127 -0
  46. package/components/ui/popover.tsx +48 -0
  47. package/components/ui/progress.tsx +31 -0
  48. package/components/ui/radio-group.tsx +45 -0
  49. package/components/ui/resizable.tsx +65 -0
  50. package/components/ui/scroll-area.tsx +58 -0
  51. package/components/ui/searchable-select.tsx +211 -0
  52. package/components/ui/select.tsx +189 -0
  53. package/components/ui/separator.tsx +28 -0
  54. package/components/ui/sheet.tsx +139 -0
  55. package/components/ui/sidebar.tsx +727 -0
  56. package/components/ui/skeleton.tsx +144 -0
  57. package/components/ui/slider.tsx +63 -0
  58. package/components/ui/sonner.tsx +26 -0
  59. package/components/ui/switch.tsx +31 -0
  60. package/components/ui/table.tsx +116 -0
  61. package/components/ui/tabs.tsx +76 -0
  62. package/components/ui/textarea.tsx +18 -0
  63. package/components/ui/theme-toggle.tsx +89 -0
  64. package/components/ui/toggle-group.tsx +73 -0
  65. package/components/ui/toggle.tsx +47 -0
  66. package/components/ui/tooltip.tsx +61 -0
  67. package/components/ui/use-mobile.ts +21 -0
  68. package/components/ui/utils.ts +6 -0
  69. package/contexts/AnimationSettingsContext.tsx +85 -0
  70. package/contexts/AuthContext.tsx +80 -0
  71. package/contexts/ThemeContext.tsx +70 -0
  72. package/hooks/useAnimationSettings.ts +2 -0
  73. package/hooks/usePermissions.ts +4 -0
  74. package/lib/persistentFilters.ts +120 -0
  75. package/lib/utils.ts +2 -0
  76. package/package.json +11 -2
  77. package/stores/theme.ts +30 -0
  78. package/stores/useThemeStore.ts +32 -0
@@ -0,0 +1,146 @@
1
+ import React, { type ForwardRefExoticComponent, type RefAttributes } from "react";
2
+
3
+ import { Button } from "@/components/ui/button";
4
+ import { Buttons } from "./components/buttons";
5
+ import { Separator } from "@/components/ui/separator";
6
+ import { Title, type TitleProps } from "../title";
7
+ import { Badge, badgeVariants } from "@/components/ui/badge";
8
+ import { Subtitle, type SubtitleProps } from "../subtitle";
9
+
10
+ import {
11
+ Breadcrumb,
12
+ BreadcrumbList,
13
+ BreadcrumbItem,
14
+ BreadcrumbLink,
15
+ BreadcrumbPage,
16
+ BreadcrumbSeparator
17
+ } from "@/components/ui/breadcrumb";
18
+
19
+ import clsx from "clsx";
20
+
21
+ import type { IconType } from "react-icons";
22
+ import type { IconProps } from "phosphor-react";
23
+ import type { VariantProps } from "class-variance-authority";
24
+
25
+ interface BreadCrumbItem {
26
+ label: string;
27
+ href?: string;
28
+ isCurrentPage?: boolean;
29
+ }
30
+
31
+ interface BreadCrumbProps {
32
+ items: BreadCrumbItem[];
33
+ className?: string;
34
+ }
35
+
36
+ type ButtonProps = React.ComponentProps<typeof Button>;
37
+
38
+ interface HeaderProps {
39
+ title: TitleProps | any;
40
+ subtitle?: SubtitleProps | any;
41
+ icon?: React.ReactNode | ForwardRefExoticComponent<IconProps & RefAttributes<SVGSVGElement>> | IconType;
42
+ lefticon?: React.ReactNode;
43
+ button?: ButtonProps;
44
+ secondButton?: ButtonProps;
45
+ thirdButton?: ButtonProps;
46
+ fourButton?: ButtonProps;
47
+ customItem?: React.ReactNode;
48
+ breadCrumbs?: BreadCrumbProps;
49
+ upperTitle?: boolean;
50
+ badge?: {
51
+ text: string;
52
+ variant?: VariantProps<typeof badgeVariants>['variant'];
53
+ className?: string;
54
+ };
55
+ showSeparator?: boolean;
56
+ headerClassName?: string;
57
+ titleContainerClassName?: string;
58
+ }
59
+ function HeaderBreadcrumb({ items, className }: BreadCrumbProps) {
60
+ return (
61
+ <Breadcrumb className={className}>
62
+ <BreadcrumbList>
63
+ {items.map((item, index) => (
64
+ <React.Fragment key={index}>
65
+ <BreadcrumbItem>
66
+ {item.isCurrentPage ? (
67
+ <BreadcrumbPage>{item.label}</BreadcrumbPage>
68
+ ) : item.href ? (
69
+ <BreadcrumbLink href={item.href}>{item.label}</BreadcrumbLink>
70
+ ) : (
71
+ <span>{item.label}</span>
72
+ )}
73
+ </BreadcrumbItem>
74
+ {index < items.length - 1 && <BreadcrumbSeparator />}
75
+ </React.Fragment>
76
+ ))}
77
+ </BreadcrumbList>
78
+ </Breadcrumb>
79
+ );
80
+ }
81
+
82
+ export function Header(props: HeaderProps) {
83
+ return (
84
+ <>
85
+ <div className={clsx(
86
+ "flex w-full gap-4 items-center justify-center flex-col md:justify-between md:flex-row",
87
+ props.headerClassName
88
+ )}>
89
+ <div
90
+ className={clsx(
91
+ "flex gap-4 flex-col sm:flex-row items-center text-gray-700 dark:text-gray-300",
92
+ { "justify-between w-full": props.lefticon },
93
+ props.titleContainerClassName
94
+ )}
95
+ >
96
+ {props.icon && <>{props.icon}</>}
97
+ <div className="flex gap-4 flex-col sm:flex-row items-center text-gray-700 dark:text-gray-300">
98
+ <div className="flex flex-col items-center text-center md:text-left md:items-start">
99
+ {props.upperTitle && (
100
+ <div className="flex items-center gap-2 mb-1">
101
+ <Title
102
+ {...props.title}
103
+ className={`line-clamp-1 ${props.title.className} `}
104
+ />
105
+ {props.badge && (
106
+ <Badge variant={props.badge.variant} className={props.badge.className}>
107
+ {props.badge.text}
108
+ </Badge>
109
+ )}
110
+ </div>
111
+ )}
112
+ {props.breadCrumbs && (
113
+ <HeaderBreadcrumb {...props.breadCrumbs} />
114
+ )}
115
+ {props.subtitle && <Subtitle {...props.subtitle} />}
116
+ {!props.upperTitle && (
117
+ <div className="flex items-center gap-2">
118
+ <Title
119
+ {...props.title}
120
+ className={`line-clamp-1 ${props.title.className} `}
121
+ />
122
+ {props.badge && (
123
+ <Badge variant={props.badge.variant} className={props.badge.className}>
124
+ {props.badge.text}
125
+ </Badge>
126
+ )}
127
+ </div>
128
+ )}
129
+ </div>
130
+ </div>
131
+ {props.lefticon && <>{props.lefticon}</>}
132
+ </div>
133
+ <Buttons
134
+ customItem={props.customItem}
135
+ button={props.button}
136
+ secondButton={props.secondButton}
137
+ thirdButton={props.thirdButton}
138
+ fourButton={props.fourButton}
139
+ />
140
+ </div>
141
+ {props.showSeparator && (
142
+ <Separator className="my-4" />
143
+ )}
144
+ </>
145
+ );
146
+ }
@@ -0,0 +1,90 @@
1
+ import { Activity } from 'react';
2
+
3
+ interface LoadingDefaultProps {
4
+ loading: boolean;
5
+ error?: boolean;
6
+ text?: string;
7
+ minHeight?: string;
8
+ className?: string;
9
+ rows?: number;
10
+ showAvatar?: boolean;
11
+ showHeader?: boolean;
12
+ }
13
+
14
+ export default function LoadingDefault({
15
+ loading,
16
+ error = false,
17
+ text = "Carregando...",
18
+ minHeight = "350px",
19
+ className = "",
20
+ rows = 3,
21
+ showAvatar = true,
22
+ showHeader = true
23
+ }: LoadingDefaultProps) {
24
+ return (
25
+ <Activity mode={loading && !error ? 'visible' : 'hidden'}>
26
+ <div className={`w-full ${className}`}>
27
+ <div
28
+ className='w-full bg-card border border-border rounded-lg p-6 space-y-4'
29
+ style={{ minHeight }}
30
+ >
31
+ {/* Header Skeleton */}
32
+ {showHeader && (
33
+ <div className="flex items-center space-x-4">
34
+ {showAvatar && (
35
+ <div className="h-12 w-12 bg-muted rounded-full animate-pulse" />
36
+ )}
37
+ <div className="space-y-2 flex-1">
38
+ <div className="h-4 bg-muted rounded animate-pulse w-1/4" />
39
+ <div className="h-3 bg-muted rounded animate-pulse w-1/3" />
40
+ </div>
41
+ </div>
42
+ )}
43
+
44
+ {/* Content Skeleton */}
45
+ <div className="space-y-3">
46
+ {Array.from({ length: rows }).map((_, index) => (
47
+ <div key={index} className="space-y-2">
48
+ <div
49
+ className="h-4 bg-muted rounded animate-pulse"
50
+ style={{
51
+ width: `${Math.random() * 40 + 60}%`,
52
+ animationDelay: `${index * 0.1}s`
53
+ }}
54
+ />
55
+ {index < rows - 1 && (
56
+ <div
57
+ className="h-3 bg-muted/70 rounded animate-pulse"
58
+ style={{
59
+ width: `${Math.random() * 30 + 40}%`,
60
+ animationDelay: `${index * 0.15 + 0.05}s`
61
+ }}
62
+ />
63
+ )}
64
+ </div>
65
+ ))}
66
+ </div>
67
+
68
+ {/* Footer Skeleton */}
69
+ <div className="flex justify-between items-center pt-4">
70
+ <div className="flex space-x-2">
71
+ <div className="h-8 w-16 bg-muted rounded animate-pulse" />
72
+ <div className="h-8 w-16 bg-muted rounded animate-pulse" />
73
+ </div>
74
+ <div className="h-8 w-20 bg-muted rounded animate-pulse" />
75
+ </div>
76
+
77
+ {/* Loading indicator com texto */}
78
+ <div className="flex items-center justify-center gap-3 pt-2">
79
+ <div className="flex space-x-1">
80
+ <div className="w-2 h-2 bg-primary rounded-full animate-bounce" style={{ animationDelay: '0ms' }} />
81
+ <div className="w-2 h-2 bg-primary rounded-full animate-bounce" style={{ animationDelay: '150ms' }} />
82
+ <div className="w-2 h-2 bg-primary rounded-full animate-bounce" style={{ animationDelay: '300ms' }} />
83
+ </div>
84
+ <span className="text-muted-foreground text-sm font-medium">{text}</span>
85
+ </div>
86
+ </div>
87
+ </div>
88
+ </Activity>
89
+ );
90
+ }
@@ -0,0 +1,78 @@
1
+
2
+ import Lottie from "lottie-react";
3
+ import { useEffect, useRef, useState } from "react";
4
+
5
+ interface LottieIconProps {
6
+ lightAnimationData: any;
7
+ darkAnimationData: any;
8
+ className?: string;
9
+ isActive?: boolean;
10
+ shouldPlay?: boolean;
11
+ isDark?: boolean;
12
+ }
13
+
14
+ export const LottieIcon = ({ lightAnimationData, darkAnimationData, className, isActive, shouldPlay = false }: LottieIconProps) => {
15
+ const lottieRef = useRef<any>(null);
16
+ const [key, setKey] = useState(0);
17
+ const [animationsEnabled, setAnimationsEnabled] = useState(true);
18
+
19
+ const [isDark, setIsDark] = useState(false);
20
+
21
+ useEffect(() => {
22
+ const checkDarkMode = () => {
23
+ setIsDark(document.documentElement.classList.contains('dark'));
24
+ };
25
+
26
+ checkDarkMode();
27
+
28
+ const observer = new MutationObserver(checkDarkMode);
29
+ observer.observe(document.documentElement, {
30
+ attributes: true,
31
+ attributeFilter: ['class']
32
+ });
33
+
34
+ return () => observer.disconnect();
35
+ }, []);
36
+
37
+ const animationData = isDark ? darkAnimationData : lightAnimationData;
38
+
39
+ useEffect(() => {
40
+ const checkAnimationSettings = () => {
41
+ const saved = localStorage.getItem('lottie-animations-enabled');
42
+ setAnimationsEnabled(saved !== null ? JSON.parse(saved) : true);
43
+ };
44
+
45
+ checkAnimationSettings();
46
+
47
+ const handleSettingsChange = (event: CustomEvent) => {
48
+ setAnimationsEnabled(event.detail.enabled);
49
+ };
50
+
51
+ window.addEventListener('lottie-settings-changed', handleSettingsChange as EventListener);
52
+
53
+ return () => {
54
+ window.removeEventListener('lottie-settings-changed', handleSettingsChange as EventListener);
55
+ };
56
+ }, []);
57
+
58
+ useEffect(() => {
59
+ if (animationsEnabled && (shouldPlay || isActive)) {
60
+ setKey(prev => prev + 1);
61
+ } else if (lottieRef.current) {
62
+ lottieRef.current.stop();
63
+ }
64
+ }, [shouldPlay, isActive, isDark, animationsEnabled]);
65
+
66
+ return (
67
+ <div className={className}>
68
+ <Lottie
69
+ key={`${key}-${isDark ? 'dark' : 'light'}`}
70
+ lottieRef={lottieRef}
71
+ animationData={animationData}
72
+ loop={false}
73
+ autoplay={animationsEnabled && (shouldPlay || isActive)}
74
+ className="w-full h-full"
75
+ />
76
+ </div>
77
+ );
78
+ };
@@ -0,0 +1,68 @@
1
+ import { Activity } from 'react';
2
+ import { ArrowLeft } from 'lucide-react';
3
+ import { Button } from '@/components/ui/button';
4
+
5
+ import Lottie from 'lottie-react';
6
+ import notFoundData from '@/public/animations/404-error-data.json';
7
+
8
+ interface NotFoundDefaultProps {
9
+ loading: boolean;
10
+ error: boolean;
11
+ title?: string;
12
+ message?: string;
13
+ backButtonText?: string;
14
+ onBack?: () => void;
15
+ minHeight?: string;
16
+ className?: string;
17
+ animationSize?: string;
18
+ }
19
+
20
+ export default function NotFoundDefault({
21
+ loading,
22
+ error,
23
+ title = "Ops! Algo deu errado",
24
+ message = "Não foi possível carregar os dados solicitados",
25
+ backButtonText = "Voltar",
26
+ onBack,
27
+ minHeight = "350px",
28
+ className = "",
29
+ animationSize = "w-[100px] md:w-[280px]"
30
+ }: NotFoundDefaultProps) {
31
+ return (
32
+ <Activity mode={!loading && error ? 'visible' : 'hidden'}>
33
+ <div className={`flex items-center justify-center bg-card w-full rounded-2xl ${className}`}>
34
+ <div
35
+ className='flex flex-col w-full items-center gap-4 bg-card rounded-2xl shadow-lg px-6 py-8 border'
36
+ style={{ minHeight }}
37
+ >
38
+ <Lottie
39
+ animationData={notFoundData}
40
+ className={animationSize}
41
+ />
42
+ <div className='flex flex-col gap-3 justify-center items-center text-center'>
43
+ <div className='space-y-2'>
44
+ <h3 className='text-xl font-semibold text-gray-900 dark:text-gray-200'>
45
+ {title}
46
+ </h3>
47
+ <p className='text-gray-600 dark:text-gray-400 text-sm max-w-xs'>
48
+ {message}
49
+ </p>
50
+ </div>
51
+ {onBack && (
52
+ <div className='flex flex-col sm:flex-row gap-3 justify-center items-center'>
53
+ <Button
54
+ variant="outline"
55
+ onClick={onBack}
56
+ className='flex items-center gap-2 px-4 py-2 border-gray-300 hover:bg-gray-50 transition-colors'
57
+ >
58
+ <ArrowLeft className="h-4 w-4" />
59
+ {backButtonText}
60
+ </Button>
61
+ </div>
62
+ )}
63
+ </div>
64
+ </div>
65
+ </div>
66
+ </Activity>
67
+ );
68
+ }
@@ -0,0 +1,225 @@
1
+ import { useState, useEffect } from 'react';
2
+
3
+ import { Settings } from 'lucide-react';
4
+
5
+ import { Button } from '@/components/ui/button';
6
+ import { Switch } from '@/components/ui/switch';
7
+ import { Label } from '@/components/ui/label';
8
+ import {
9
+ Dialog,
10
+ DialogContent,
11
+ DialogDescription,
12
+ DialogHeader,
13
+ DialogTitle,
14
+ DialogTrigger,
15
+ } from '@/components/ui/dialog';
16
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
17
+
18
+ import Lottie from 'lottie-react';
19
+
20
+ import configAnimated from "@/public/animations/config-animated.json";
21
+ import { PersistentFilters } from '@/lib/persistentFilters';
22
+ import { useAnimationSettings } from '@/hooks/useAnimationSettings';
23
+
24
+ interface SettingsModalProps {
25
+ collapsed?: boolean;
26
+ }
27
+
28
+ export function SettingsModal({ collapsed = false }: SettingsModalProps) {
29
+ const [isOpen, setIsOpen] = useState(false);
30
+ const [dynamicSidebarEnabled, setDynamicSidebarEnabled] = useState(false);
31
+ const [persistentFiltersEnabled, setPersistentFiltersEnabled] = useState(true);
32
+
33
+ // Usar o contexto para as configurações de animação
34
+ const {
35
+ lottieAnimationsEnabled,
36
+ otherLottieAnimationsEnabled,
37
+ setLottieAnimationsEnabled,
38
+ setOtherLottieAnimationsEnabled
39
+ } = useAnimationSettings();
40
+
41
+ useEffect(() => {
42
+ // As configurações de animação agora são gerenciadas pelo contexto
43
+ // Apenas carregamos as outras configurações
44
+ const savedDynamicSidebar = localStorage.getItem('dynamic-sidebar-enabled');
45
+ if (savedDynamicSidebar !== null) {
46
+ setDynamicSidebarEnabled(JSON.parse(savedDynamicSidebar));
47
+ }
48
+
49
+ const savedPersistentFilters = localStorage.getItem('persistent-filters-enabled');
50
+ if (savedPersistentFilters !== null) {
51
+ setPersistentFiltersEnabled(JSON.parse(savedPersistentFilters));
52
+ }
53
+ }, []);
54
+
55
+ // As funções de toggle agora usam o contexto diretamente
56
+ const handleAnimationToggle = (enabled: boolean) => {
57
+ setLottieAnimationsEnabled(enabled);
58
+ };
59
+
60
+ const handleOtherAnimationToggle = (enabled: boolean) => {
61
+ setOtherLottieAnimationsEnabled(enabled);
62
+ };
63
+
64
+ const handleDynamicSidebarToggle = (enabled: boolean) => {
65
+ setDynamicSidebarEnabled(enabled);
66
+ localStorage.setItem('dynamic-sidebar-enabled', JSON.stringify(enabled));
67
+
68
+ window.dispatchEvent(new CustomEvent('dynamic-sidebar-settings-changed', {
69
+ detail: { enabled }
70
+ }));
71
+
72
+ window.dispatchEvent(new CustomEvent('reset-dynamic-sidebar-state'));
73
+
74
+ if (enabled) {
75
+ window.dispatchEvent(new CustomEvent('auto-collapse-sidebar'));
76
+ }
77
+ };
78
+
79
+ const handlePersistentFiltersToggle = (enabled: boolean) => {
80
+ setPersistentFiltersEnabled(enabled);
81
+ localStorage.setItem('persistent-filters-enabled', JSON.stringify(enabled));
82
+
83
+ window.dispatchEvent(new CustomEvent('persistent-filters-settings-changed', {
84
+ detail: { enabled }
85
+ }));
86
+
87
+ if (!enabled) {
88
+ PersistentFilters.clearAllFilters();
89
+ window.dispatchEvent(new CustomEvent('clear-saved-filters'));
90
+ }
91
+ };
92
+
93
+ return (
94
+ <Dialog open={isOpen} onOpenChange={setIsOpen}>
95
+ <DialogTrigger asChild>
96
+ <Button
97
+ variant="outline"
98
+ size="icon"
99
+ className="h-6 w-6 shrink-0 rounded-full hover:bg-accent"
100
+ title="Configurações"
101
+ >
102
+ <Settings className="h-3 w-3" />
103
+ </Button>
104
+ </DialogTrigger>
105
+ <DialogContent className="sm:max-w-106.25 md:max-w-150 lg:max-w-3xl flex">
106
+ <div>
107
+ <DialogHeader>
108
+ <DialogTitle className="flex items-center gap-2">
109
+ <Settings className="h-5 w-5" />
110
+ Configurações
111
+ </DialogTitle>
112
+ <DialogDescription>
113
+ Personalize a experiência do sistema de acordo com suas preferências.
114
+ </DialogDescription>
115
+ </DialogHeader>
116
+
117
+ <div className="space-y-4">
118
+ <Card className='max-h-125 overflow-y-scroll gap-0'>
119
+ <CardHeader className='pb-3 pt-4 dark:bg-slate-800 bg-blue-50 rounded-t-lg'>
120
+ <CardTitle className="text-base font-semibold">Geral</CardTitle>
121
+ <CardDescription className="text-sm">
122
+ Configurações gerais do sistema
123
+ </CardDescription>
124
+ </CardHeader>
125
+
126
+ <CardContent className='pt-4'>
127
+ <div className="space-y-5">
128
+
129
+ <div className="flex items-center justify-between gap-2">
130
+ <div className="space-y-1">
131
+ <Label htmlFor="persistent-filters" className="text-sm font-medium">
132
+ Salvar Filtros
133
+ </Label>
134
+ <p className="text-xs text-muted-foreground">
135
+ Manter filtros salvos entre sessões (busca, paginação, etc.)
136
+ </p>
137
+ </div>
138
+ <Switch
139
+ id="persistent-filters"
140
+ checked={persistentFiltersEnabled}
141
+ onCheckedChange={handlePersistentFiltersToggle}
142
+ />
143
+ </div>
144
+
145
+ <div className="flex items-center justify-between gap-2 pb-4">
146
+ <div className="space-y-1">
147
+ <Label htmlFor="dynamic-sidebar" className="text-sm font-medium">
148
+ Sidebar Dinâmica (Desktop)
149
+ </Label>
150
+ <p className="text-xs text-muted-foreground">
151
+ Expandir sidebar automaticamente ao passar o mouse (apenas desktop)
152
+ </p>
153
+ </div>
154
+ <Switch
155
+ id="dynamic-sidebar"
156
+ checked={dynamicSidebarEnabled}
157
+ onCheckedChange={handleDynamicSidebarToggle}
158
+ />
159
+ </div>
160
+
161
+ </div>
162
+ </CardContent>
163
+
164
+ <CardHeader className='pb-2 pt-2 dark:bg-slate-800 bg-blue-50 '>
165
+ <CardTitle className="text-base font-semibold">Interface</CardTitle>
166
+ <CardDescription className="text-sm">
167
+ Configurações relacionadas à interface do usuário
168
+ </CardDescription>
169
+ </CardHeader>
170
+
171
+ <CardContent className='pt-4'>
172
+ <div className="space-y-5">
173
+ <div className="flex items-center justify-between gap-2">
174
+ <div className="space-y-1">
175
+ <Label htmlFor="lottie-animations" className="text-sm font-medium">
176
+ Animações dos Ícones
177
+ </Label>
178
+ <p className="text-xs text-muted-foreground">
179
+ Ativar/desativar animações Lottie nos ícones do sistema
180
+ </p>
181
+ </div>
182
+ <Switch
183
+ id="lottie-animations"
184
+ checked={lottieAnimationsEnabled}
185
+ onCheckedChange={handleAnimationToggle}
186
+ />
187
+ </div>
188
+
189
+ <div className="flex items-center justify-between gap-2">
190
+ <div className="space-y-1">
191
+ <Label htmlFor="other-lottie-animations" className="text-sm font-medium">
192
+ Outras Animações
193
+ </Label>
194
+ <p className="text-xs text-muted-foreground">
195
+ Ativar/desativar animações Lottie decorativas (páginas, modal)
196
+ </p>
197
+ </div>
198
+ <Switch
199
+ id="other-lottie-animations"
200
+ checked={otherLottieAnimationsEnabled}
201
+ onCheckedChange={handleOtherAnimationToggle}
202
+ />
203
+ </div>
204
+
205
+ </div>
206
+ </CardContent>
207
+ </Card>
208
+
209
+ <div className="text-xs text-muted-foreground text-center">
210
+ As configurações são salvas automaticamente no seu navegador.
211
+ </div>
212
+ </div>
213
+ </div>
214
+ <div className='hidden md:flex justify-center items-center'>
215
+ <Lottie
216
+ animationData={configAnimated}
217
+ loop={otherLottieAnimationsEnabled}
218
+ autoplay={otherLottieAnimationsEnabled}
219
+ className='max-w-125'
220
+ />
221
+ </div>
222
+ </DialogContent>
223
+ </Dialog>
224
+ );
225
+ }