@pattern-stack/frontend-patterns 0.0.1 → 0.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 (153) hide show
  1. package/README.md +6 -6
  2. package/package.json +3 -5
  3. package/src/App.css +0 -42
  4. package/src/App.tsx +0 -54
  5. package/src/__tests__/README.md +0 -221
  6. package/src/__tests__/atoms/hooks/simple-hooks.test.ts +0 -44
  7. package/src/__tests__/atoms/ui/button.test.tsx +0 -68
  8. package/src/__tests__/atoms/utils/simple.test.ts +0 -18
  9. package/src/__tests__/atoms/utils/utils.test.ts +0 -77
  10. package/src/__tests__/features/auth/simple-auth.test.tsx +0 -40
  11. package/src/__tests__/molecules/layout/simple-layout.test.tsx +0 -81
  12. package/src/__tests__/organisms/showcase/simple-showcase.test.tsx +0 -167
  13. package/src/__tests__/setup.ts +0 -51
  14. package/src/__tests__/utils.tsx +0 -123
  15. package/src/atoms/composed/Accordion/Accordion.tsx +0 -271
  16. package/src/atoms/composed/Accordion/index.ts +0 -1
  17. package/src/atoms/composed/Alert/Alert.tsx +0 -132
  18. package/src/atoms/composed/Alert/index.ts +0 -1
  19. package/src/atoms/composed/Breadcrumb/Breadcrumb.tsx +0 -83
  20. package/src/atoms/composed/Breadcrumb/index.ts +0 -1
  21. package/src/atoms/composed/Chart/Chart.tsx +0 -425
  22. package/src/atoms/composed/Chart/index.ts +0 -2
  23. package/src/atoms/composed/ColorSwatch/ColorSwatch.tsx +0 -72
  24. package/src/atoms/composed/ColorSwatch/index.ts +0 -1
  25. package/src/atoms/composed/DarkModeToggle.tsx +0 -66
  26. package/src/atoms/composed/DataBadge/DataBadge.tsx +0 -81
  27. package/src/atoms/composed/DataBadge/index.ts +0 -1
  28. package/src/atoms/composed/DataTable/DataTable.tsx +0 -394
  29. package/src/atoms/composed/DataTable/TableCellWithTooltip.tsx +0 -41
  30. package/src/atoms/composed/DataTable/index.ts +0 -2
  31. package/src/atoms/composed/DateTimePicker/DateTimePicker.tsx +0 -611
  32. package/src/atoms/composed/DateTimePicker/index.ts +0 -2
  33. package/src/atoms/composed/DetailedCard/DetailedCard.tsx +0 -181
  34. package/src/atoms/composed/DetailedCard/index.ts +0 -2
  35. package/src/atoms/composed/EmptyState/EmptyState.tsx +0 -90
  36. package/src/atoms/composed/EmptyState/index.ts +0 -1
  37. package/src/atoms/composed/FileUpload/FileUpload.tsx +0 -477
  38. package/src/atoms/composed/FileUpload/index.ts +0 -2
  39. package/src/atoms/composed/FormField/FormField.tsx +0 -92
  40. package/src/atoms/composed/FormField/index.ts +0 -1
  41. package/src/atoms/composed/GlobalSearch/GlobalSearch.tsx +0 -37
  42. package/src/atoms/composed/GlobalSearch/index.ts +0 -1
  43. package/src/atoms/composed/IconBadge/IconBadge.tsx +0 -95
  44. package/src/atoms/composed/IconBadge/index.ts +0 -2
  45. package/src/atoms/composed/Modal/Modal.tsx +0 -223
  46. package/src/atoms/composed/Modal/index.ts +0 -2
  47. package/src/atoms/composed/PaletteSwitcher.tsx +0 -386
  48. package/src/atoms/composed/ProgressBar/ProgressBar.tsx +0 -116
  49. package/src/atoms/composed/ProgressBar/index.ts +0 -1
  50. package/src/atoms/composed/StatCard/StatCard.tsx +0 -219
  51. package/src/atoms/composed/StatCard/index.ts +0 -1
  52. package/src/atoms/composed/StyleGuide.tsx +0 -717
  53. package/src/atoms/composed/Toast/Toast.tsx +0 -219
  54. package/src/atoms/composed/Toast/index.ts +0 -1
  55. package/src/atoms/composed/Tooltip/Tooltip.tsx +0 -213
  56. package/src/atoms/composed/Tooltip/index.ts +0 -1
  57. package/src/atoms/composed/UserAvatar/UserAvatar.tsx +0 -139
  58. package/src/atoms/composed/UserAvatar/index.ts +0 -1
  59. package/src/atoms/composed/UserMenu/UserMenu.tsx +0 -16
  60. package/src/atoms/composed/UserMenu/index.ts +0 -1
  61. package/src/atoms/composed/index.ts +0 -29
  62. package/src/atoms/hooks/useApi.ts +0 -80
  63. package/src/atoms/hooks/useHealth.ts +0 -17
  64. package/src/atoms/index.ts +0 -13
  65. package/src/atoms/services/api/client.ts +0 -134
  66. package/src/atoms/services/auth-service.ts +0 -248
  67. package/src/atoms/services/health.ts +0 -15
  68. package/src/atoms/services/index.ts +0 -3
  69. package/src/atoms/shared/config/constants.ts +0 -17
  70. package/src/atoms/shared/config/dashboard-sizes.ts +0 -111
  71. package/src/atoms/shared/config/environment.ts +0 -10
  72. package/src/atoms/shared/index.ts +0 -4
  73. package/src/atoms/shared/styles/color-palettes.css +0 -566
  74. package/src/atoms/types/auth.ts +0 -62
  75. package/src/atoms/types/generated.ts +0 -1469
  76. package/src/atoms/types/index.ts +0 -4
  77. package/src/atoms/types/loading.ts +0 -28
  78. package/src/atoms/ui/Badge.tsx +0 -30
  79. package/src/atoms/ui/ErrorBoundary.tsx +0 -59
  80. package/src/atoms/ui/Select.tsx +0 -53
  81. package/src/atoms/ui/Switch.tsx +0 -42
  82. package/src/atoms/ui/Tabs.tsx +0 -118
  83. package/src/atoms/ui/avatar.tsx +0 -48
  84. package/src/atoms/ui/button.tsx +0 -70
  85. package/src/atoms/ui/card.tsx +0 -76
  86. package/src/atoms/ui/dropdown-menu.tsx +0 -199
  87. package/src/atoms/ui/index.ts +0 -39
  88. package/src/atoms/ui/input.tsx +0 -23
  89. package/src/atoms/ui/label.tsx +0 -23
  90. package/src/atoms/ui/skeleton.tsx +0 -13
  91. package/src/atoms/ui/spinner.tsx +0 -49
  92. package/src/atoms/ui/table.tsx +0 -116
  93. package/src/atoms/utils/animations.ts +0 -135
  94. package/src/atoms/utils/tooltip-helpers.ts +0 -140
  95. package/src/atoms/utils/utils.ts +0 -9
  96. package/src/features/auth/components/LoginForm.tsx +0 -168
  97. package/src/features/auth/components/LogoutButton.tsx +0 -19
  98. package/src/features/auth/components/ProtectedRoute.tsx +0 -60
  99. package/src/features/auth/components/index.ts +0 -4
  100. package/src/features/auth/hooks/index.ts +0 -2
  101. package/src/features/auth/hooks/useAuth.tsx +0 -205
  102. package/src/features/auth/hooks/usePermissions.ts +0 -35
  103. package/src/features/auth/index.ts +0 -2
  104. package/src/features/index.ts +0 -2
  105. package/src/index.css +0 -704
  106. package/src/index.ts +0 -13
  107. package/src/main.tsx +0 -48
  108. package/src/molecules/.gitkeep +0 -0
  109. package/src/molecules/forms/FormGroup.tsx +0 -75
  110. package/src/molecules/forms/SearchInput.tsx +0 -259
  111. package/src/molecules/forms/index.ts +0 -4
  112. package/src/molecules/index.ts +0 -4
  113. package/src/molecules/layout/AppHeader/AppHeader.tsx +0 -42
  114. package/src/molecules/layout/AppHeader/index.ts +0 -1
  115. package/src/molecules/layout/AppLayout.tsx +0 -29
  116. package/src/molecules/layout/PageTemplate.tsx +0 -87
  117. package/src/molecules/layout/SectionHeader/SectionHeader.tsx +0 -87
  118. package/src/molecules/layout/SectionHeader/index.ts +0 -1
  119. package/src/molecules/layout/ShowcaseSection.tsx +0 -57
  120. package/src/molecules/layout/Sidebar.tsx +0 -144
  121. package/src/molecules/layout/SidebarButton/SidebarButton.tsx +0 -99
  122. package/src/molecules/layout/SidebarButton/index.ts +0 -1
  123. package/src/molecules/layout/SidebarContext.tsx +0 -31
  124. package/src/molecules/layout/index.ts +0 -7
  125. package/src/molecules/navigation/NavMenu.tsx +0 -188
  126. package/src/molecules/navigation/Pagination.tsx +0 -172
  127. package/src/molecules/navigation/index.ts +0 -4
  128. package/src/organisms/index.ts +0 -5
  129. package/src/organisms/showcase/ComponentShowcasePage.tsx +0 -2496
  130. package/src/organisms/showcase/index.ts +0 -1
  131. package/src/pages/AdminShowcase/AdminCRUDShowcase.tsx +0 -242
  132. package/src/pages/AdminShowcase/AdminDashboardShowcase.tsx +0 -171
  133. package/src/pages/AdminShowcase/AdminDetailShowcase.tsx +0 -385
  134. package/src/pages/AdminShowcase/index.tsx +0 -3
  135. package/src/pages/ComponentShowcase/BadgesShowcase.tsx +0 -188
  136. package/src/pages/ComponentShowcase/CardsShowcase.tsx +0 -392
  137. package/src/pages/ComponentShowcase/PalettesShowcase.tsx +0 -207
  138. package/src/pages/ComponentShowcase/StatesShowcase.tsx +0 -485
  139. package/src/pages/ComponentShowcase/TablesShowcase.tsx +0 -134
  140. package/src/pages/ComponentShowcase/TypographyShowcase.tsx +0 -255
  141. package/src/pages/ComponentShowcase/index.tsx +0 -188
  142. package/src/pages/index.ts +0 -2
  143. package/src/templates/AuthTemplate.tsx +0 -216
  144. package/src/templates/ComponentShowcaseTemplate.tsx +0 -173
  145. package/src/templates/DashboardTemplate.tsx +0 -232
  146. package/src/templates/DataTemplate.tsx +0 -319
  147. package/src/templates/admin/AdminCRUDTemplate.tsx +0 -630
  148. package/src/templates/admin/AdminDashboardTemplate.tsx +0 -351
  149. package/src/templates/admin/AdminDetailTemplate.tsx +0 -563
  150. package/src/templates/admin/index.ts +0 -29
  151. package/src/templates/factory.tsx +0 -169
  152. package/src/templates/index.ts +0 -37
  153. package/src/vite-env.d.ts +0 -1
@@ -1,219 +0,0 @@
1
- import React, { useEffect, useState, useCallback } from 'react';
2
- import { X, CheckCircle, AlertTriangle, AlertCircle, Info } from 'lucide-react';
3
- import { cn } from '../../utils/utils';
4
- import { Button } from '../../ui/button';
5
- import { getAnimationClasses, animationPresets } from '../../utils/animations';
6
-
7
- export interface ToastProps {
8
- /** Toast content */
9
- children: React.ReactNode;
10
- /** Toast status type */
11
- status?: 'success' | 'warning' | 'error' | 'info' | 'neutral';
12
- /** Toast title */
13
- title?: string;
14
- /** Auto-dismiss duration in milliseconds */
15
- duration?: number;
16
- /** Whether toast can be dismissed */
17
- dismissible?: boolean;
18
- /** Dismiss handler */
19
- onDismiss?: () => void;
20
- /** Toast position */
21
- position?: 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' | 'top-center' | 'bottom-center';
22
- /** Custom icon */
23
- icon?: React.ReactNode;
24
- /** Hide default icon */
25
- hideIcon?: boolean;
26
- /** Additional CSS classes */
27
- className?: string;
28
- /** Show progress bar for auto-dismiss */
29
- showProgress?: boolean;
30
- }
31
-
32
- const statusIcons = {
33
- success: CheckCircle,
34
- warning: AlertTriangle,
35
- error: AlertCircle,
36
- info: Info,
37
- neutral: Info
38
- };
39
-
40
- export const Toast: React.FC<ToastProps> = ({
41
- children,
42
- status = 'neutral',
43
- title,
44
- duration = 0, // 0 means no auto-dismiss
45
- dismissible = true,
46
- onDismiss,
47
- position = 'top-right',
48
- icon,
49
- hideIcon = false,
50
- className,
51
- showProgress = false
52
- }) => {
53
- const [isVisible, setIsVisible] = useState(true);
54
- const [progress, setProgress] = useState(100);
55
-
56
- const IconComponent = statusIcons[status];
57
- const displayIcon = icon || (!hideIcon && <IconComponent className="w-5 h-5" />);
58
-
59
- const handleDismiss = useCallback(() => {
60
- setIsVisible(false);
61
- setTimeout(() => onDismiss?.(), 300); // Wait for exit animation
62
- }, [onDismiss]);
63
-
64
- useEffect(() => {
65
- if (duration > 0) {
66
- const dismissTimer = setTimeout(handleDismiss, duration);
67
-
68
- if (showProgress) {
69
- const progressInterval = setInterval(() => {
70
- setProgress(prev => {
71
- const decrement = 100 / (duration / 50); // Update every 50ms
72
- return Math.max(prev - decrement, 0);
73
- });
74
- }, 50);
75
-
76
- return () => {
77
- clearTimeout(dismissTimer);
78
- clearInterval(progressInterval);
79
- };
80
- }
81
-
82
- return () => clearTimeout(dismissTimer);
83
- }
84
- }, [duration, showProgress, handleDismiss]);
85
-
86
- const positionClasses = {
87
- 'top-right': 'top-4 right-4',
88
- 'top-left': 'top-4 left-4',
89
- 'bottom-right': 'bottom-4 right-4',
90
- 'bottom-left': 'bottom-4 left-4',
91
- 'top-center': 'top-4 left-1/2 -translate-x-1/2',
92
- 'bottom-center': 'bottom-4 left-1/2 -translate-x-1/2'
93
- };
94
-
95
- const statusClasses = {
96
- success: 'bg-background text-status-success border-status-success/30 shadow-status-success/10',
97
- warning: 'bg-background text-status-warning border-status-warning/30 shadow-status-warning/10',
98
- error: 'bg-background text-status-error border-status-error/30 shadow-status-error/10',
99
- info: 'bg-background text-status-info border-status-info/30 shadow-status-info/10',
100
- neutral: 'bg-background text-foreground border-border shadow-muted/20'
101
- };
102
-
103
- if (!isVisible) {
104
- return null;
105
- }
106
-
107
- return (
108
- <div
109
- className={cn(
110
- 'fixed z-50 w-full max-w-sm',
111
- positionClasses[position]
112
- )}
113
- >
114
- <div
115
- className={cn(
116
- 'rounded-lg border p-4 shadow-lg backdrop-blur-sm',
117
- 'flex items-start gap-3 relative overflow-hidden',
118
- statusClasses[status],
119
- getAnimationClasses(animationPresets.card),
120
- className
121
- )}
122
- role="alert"
123
- data-component-name="Toast"
124
- >
125
- {/* Icon */}
126
- {displayIcon && (
127
- <div className="flex-shrink-0 mt-0.5">
128
- {displayIcon}
129
- </div>
130
- )}
131
-
132
- {/* Content */}
133
- <div className="flex-1 min-w-0">
134
- {title && (
135
- <h4 className="font-semibold mb-1 text-sm">
136
- {title}
137
- </h4>
138
- )}
139
- <div className="text-sm text-current">
140
- {children}
141
- </div>
142
- </div>
143
-
144
- {/* Dismiss button */}
145
- {dismissible && (
146
- <Button
147
- variant="ghost"
148
- size="sm"
149
- onClick={handleDismiss}
150
- className={cn(
151
- 'flex-shrink-0 h-auto p-1 -mt-1 -mr-1',
152
- 'hover:bg-current/10 text-current'
153
- )}
154
- aria-label="Dismiss notification"
155
- >
156
- <X className="w-4 h-4" />
157
- </Button>
158
- )}
159
-
160
- {/* Progress bar */}
161
- {showProgress && duration > 0 && (
162
- <div className="absolute bottom-0 left-0 right-0 h-1 bg-current/10">
163
- <div
164
- className="h-full bg-current/30 transition-all duration-50 ease-linear"
165
- style={{ width: `${progress}%` }}
166
- />
167
- </div>
168
- )}
169
- </div>
170
- </div>
171
- );
172
- };
173
-
174
- // Toast container component for managing multiple toasts
175
- export interface ToastContainerProps {
176
- /** Toast notifications */
177
- toasts: Array<ToastProps & { id: string }>;
178
- /** Container position */
179
- position?: ToastProps['position'];
180
- /** Maximum number of visible toasts */
181
- maxToasts?: number;
182
- /** Additional CSS classes */
183
- className?: string;
184
- }
185
-
186
- export const ToastContainer: React.FC<ToastContainerProps> = ({
187
- toasts,
188
- position = 'top-right',
189
- maxToasts = 5,
190
- className
191
- }) => {
192
- const visibleToasts = toasts.slice(0, maxToasts);
193
-
194
- const positionClasses = {
195
- 'top-right': 'top-4 right-4 flex-col',
196
- 'top-left': 'top-4 left-4 flex-col',
197
- 'bottom-right': 'bottom-4 right-4 flex-col-reverse',
198
- 'bottom-left': 'bottom-4 left-4 flex-col-reverse',
199
- 'top-center': 'top-4 left-1/2 -translate-x-1/2 flex-col',
200
- 'bottom-center': 'bottom-4 left-1/2 -translate-x-1/2 flex-col-reverse'
201
- };
202
-
203
- return (
204
- <div
205
- className={cn(
206
- 'fixed z-50 flex gap-2 pointer-events-none',
207
- positionClasses[position],
208
- className
209
- )}
210
- data-component-name="ToastContainer"
211
- >
212
- {visibleToasts.map(({ id, ...toastProps }) => (
213
- <div key={id} className="pointer-events-auto">
214
- <Toast {...toastProps} position={position} />
215
- </div>
216
- ))}
217
- </div>
218
- );
219
- };
@@ -1 +0,0 @@
1
- export { Toast, ToastContainer, type ToastProps, type ToastContainerProps } from './Toast';
@@ -1,213 +0,0 @@
1
- import React, { useState, useRef, useEffect } from 'react';
2
- import { cn } from '../../utils/utils';
3
- import { getAnimationClasses, animationPresets } from '../../utils/animations';
4
-
5
- export interface TooltipProps {
6
- children: React.ReactNode;
7
- content: React.ReactNode;
8
- position?: 'top' | 'bottom' | 'left' | 'right';
9
- variant?: 'default' | 'info' | 'warning' | 'error';
10
- size?: 'sm' | 'md' | 'lg';
11
- disabled?: boolean;
12
- delay?: number;
13
- offset?: number;
14
- trigger?: 'hover' | 'focus' | 'both';
15
- className?: string;
16
- contentClassName?: string;
17
- }
18
-
19
- export const Tooltip = ({
20
- children,
21
- content,
22
- position = 'top',
23
- variant = 'default',
24
- size = 'md',
25
- disabled = false,
26
- delay = 300,
27
- offset = 8,
28
- trigger = 'both',
29
- className,
30
- contentClassName
31
- }: TooltipProps) => {
32
- const [isVisible, setIsVisible] = useState(false);
33
- const [actualPosition, setActualPosition] = useState(position);
34
- const triggerRef = useRef<HTMLDivElement>(null);
35
- const tooltipRef = useRef<HTMLDivElement>(null);
36
- const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
37
-
38
- const sizeClasses: Record<'sm' | 'md' | 'lg', string> = {
39
- sm: 'px-2 py-1 text-xs max-w-48',
40
- md: 'px-3 py-2 text-sm max-w-64',
41
- lg: 'px-4 py-3 text-base max-w-80',
42
- };
43
-
44
- const variantClasses: Record<'default' | 'info' | 'warning' | 'error', string> = {
45
- default: 'bg-card/95 text-card-foreground border-border/30',
46
- info: 'status-info text-card-foreground border-status-info/30',
47
- warning: 'status-warning text-card-foreground border-status-warning/30',
48
- error: 'status-error text-card-foreground border-status-error/30',
49
- };
50
-
51
- const positionClasses: Record<'top' | 'bottom' | 'left' | 'right', string> = {
52
- top: 'bottom-full left-1/2 transform -translate-x-1/2 mb-2',
53
- bottom: 'top-full left-1/2 transform -translate-x-1/2 mt-2',
54
- left: 'right-full top-1/2 transform -translate-y-1/2 mr-2',
55
- right: 'left-full top-1/2 transform -translate-y-1/2 ml-2',
56
- };
57
-
58
- const arrowClasses: Record<'top' | 'bottom' | 'left' | 'right', string> = {
59
- top: 'top-full left-1/2 transform -translate-x-1/2 border-l-transparent border-r-transparent border-b-transparent',
60
- bottom: 'bottom-full left-1/2 transform -translate-x-1/2 border-l-transparent border-r-transparent border-t-transparent',
61
- left: 'left-full top-1/2 transform -translate-y-1/2 border-t-transparent border-b-transparent border-r-transparent',
62
- right: 'right-full top-1/2 transform -translate-y-1/2 border-t-transparent border-b-transparent border-l-transparent',
63
- };
64
-
65
- const showTooltip = () => {
66
- if (disabled) return;
67
- if (timeoutRef.current) clearTimeout(timeoutRef.current);
68
-
69
- timeoutRef.current = setTimeout(() => {
70
- setIsVisible(true);
71
- requestAnimationFrame(() => {
72
- checkAndAdjustPosition();
73
- });
74
- }, delay);
75
- };
76
-
77
- const hideTooltip = () => {
78
- if (timeoutRef.current) clearTimeout(timeoutRef.current);
79
- setIsVisible(false);
80
- };
81
-
82
- const checkAndAdjustPosition = () => {
83
- if (!triggerRef.current || !tooltipRef.current) return;
84
-
85
- const triggerRect = triggerRef.current.getBoundingClientRect();
86
- const tooltipRect = tooltipRef.current.getBoundingClientRect();
87
- const viewport = {
88
- width: window.innerWidth,
89
- height: window.innerHeight,
90
- };
91
-
92
- let newPosition = position;
93
-
94
- // Check if tooltip goes outside viewport and adjust position
95
- switch (position) {
96
- case 'top':
97
- if (triggerRect.top - tooltipRect.height - offset < 0) {
98
- newPosition = 'bottom';
99
- }
100
- break;
101
- case 'bottom':
102
- if (triggerRect.bottom + tooltipRect.height + offset > viewport.height) {
103
- newPosition = 'top';
104
- }
105
- break;
106
- case 'left':
107
- if (triggerRect.left - tooltipRect.width - offset < 0) {
108
- newPosition = 'right';
109
- }
110
- break;
111
- case 'right':
112
- if (triggerRect.right + tooltipRect.width + offset > viewport.width) {
113
- newPosition = 'left';
114
- }
115
- break;
116
- }
117
-
118
- setActualPosition(newPosition);
119
- };
120
-
121
- useEffect(() => {
122
- return () => {
123
- if (timeoutRef.current) clearTimeout(timeoutRef.current);
124
- };
125
- }, []);
126
-
127
- const triggerProps = {
128
- ...(trigger === 'hover' || trigger === 'both' ? {
129
- onMouseEnter: showTooltip,
130
- onMouseLeave: hideTooltip,
131
- } : {}),
132
- ...(trigger === 'focus' || trigger === 'both' ? {
133
- onFocus: showTooltip,
134
- onBlur: hideTooltip,
135
- } : {}),
136
- };
137
-
138
- const tooltipBaseClasses = cn(
139
- 'absolute z-50 rounded-lg border backdrop-blur-sm shadow-lg pointer-events-none',
140
- 'animate-fade-in transition-all duration-200 ease-out',
141
- sizeClasses[size],
142
- variantClasses[variant],
143
- positionClasses[actualPosition],
144
- getAnimationClasses({
145
- ...animationPresets.subtle,
146
- timing: 'fast'
147
- }),
148
- contentClassName
149
- );
150
-
151
- const arrowBaseClasses = cn(
152
- 'absolute w-0 h-0 border-4',
153
- arrowClasses[actualPosition]
154
- );
155
-
156
- const getArrowColor = () => {
157
- switch (variant) {
158
- case 'info':
159
- return 'border-t-status-info';
160
- case 'warning':
161
- return 'border-t-status-warning';
162
- case 'error':
163
- return 'border-t-status-error';
164
- default:
165
- return 'border-t-card';
166
- }
167
- };
168
-
169
- return (
170
- <div className={cn("relative inline-block", className)}>
171
- <div
172
- ref={triggerRef}
173
- {...triggerProps}
174
- className="cursor-help"
175
- aria-describedby={isVisible ? 'tooltip' : undefined}
176
- data-component-name="TooltipTrigger"
177
- >
178
- {children}
179
- </div>
180
-
181
- {isVisible && !disabled && (
182
- <div
183
- ref={tooltipRef}
184
- id="tooltip"
185
- role="tooltip"
186
- aria-hidden={!isVisible}
187
- className={tooltipBaseClasses}
188
- style={{
189
- marginTop: actualPosition === 'bottom' ? `${offset}px` : actualPosition === 'top' ? `-${offset}px` : '0',
190
- marginLeft: actualPosition === 'right' ? `${offset}px` : actualPosition === 'left' ? `-${offset}px` : '0',
191
- }}
192
- data-component-name="Tooltip"
193
- >
194
- {content}
195
-
196
- {/* Arrow */}
197
- <div
198
- className={cn(
199
- arrowBaseClasses,
200
- getArrowColor()
201
- )}
202
- style={{
203
- borderTopColor: actualPosition === 'bottom' ? 'inherit' : 'transparent',
204
- borderBottomColor: actualPosition === 'top' ? 'inherit' : 'transparent',
205
- borderLeftColor: actualPosition === 'right' ? 'inherit' : 'transparent',
206
- borderRightColor: actualPosition === 'left' ? 'inherit' : 'transparent',
207
- }}
208
- />
209
- </div>
210
- )}
211
- </div>
212
- );
213
- };
@@ -1 +0,0 @@
1
- export * from './Tooltip';
@@ -1,139 +0,0 @@
1
- import React from 'react';
2
- import { User, Settings, LogOut, UserCircle, Moon, Sun } from 'lucide-react';
3
- import {
4
- Avatar,
5
- AvatarFallback,
6
- DropdownMenu,
7
- DropdownMenuTrigger,
8
- DropdownMenuContent,
9
- DropdownMenuItem,
10
- DropdownMenuSeparator,
11
- Button
12
- } from '../../ui';
13
- import { useAuth } from '../../../features/auth';
14
- import { cn } from '../../utils/utils';
15
-
16
- interface UserAvatarProps {
17
- className?: string;
18
- category?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
19
- }
20
-
21
- export const UserAvatar: React.FC<UserAvatarProps> = ({ className, category = 1 }) => {
22
- const { user, logout } = useAuth();
23
- const [isDark, setIsDark] = React.useState(() =>
24
- document.documentElement.classList.contains('dark')
25
- );
26
-
27
- const toggleDarkMode = () => {
28
- const newDarkMode = !isDark;
29
- setIsDark(newDarkMode);
30
-
31
- if (newDarkMode) {
32
- document.documentElement.classList.add('dark');
33
- } else {
34
- document.documentElement.classList.remove('dark');
35
- }
36
- };
37
-
38
- const userInitials = (user as any)?.name
39
- ? (user as any).name.split(' ').map((n: string) => n[0]).join('').toUpperCase().slice(0, 2)
40
- : user?.email?.[0]?.toUpperCase() || 'U';
41
-
42
- const avatarStyles = {
43
- background: `linear-gradient(135deg, hsl(var(--category-${category}) / 0.1), hsl(var(--category-${category}) / 0.2))`,
44
- borderColor: `hsl(var(--category-${category}) / 0.3)`,
45
- color: `hsl(var(--category-${category}))`
46
- };
47
-
48
- const handleLogout = () => {
49
- logout();
50
- };
51
-
52
- return (
53
- <div className={cn("flex items-center", className)}>
54
- <DropdownMenu>
55
- <DropdownMenuTrigger asChild>
56
- <Button variant="ghost" className="relative h-9 w-9 rounded p-0 hover:bg-muted/30 transition-colors">
57
- <Avatar className="h-9 w-9">
58
- <AvatarFallback
59
- className="border font-medium text-sm"
60
- style={avatarStyles}
61
- >
62
- <User className="w-4 h-4" />
63
- </AvatarFallback>
64
- </Avatar>
65
- </Button>
66
- </DropdownMenuTrigger>
67
- <DropdownMenuContent
68
- className="w-56 bg-card/95 backdrop-blur-sm border-border/30"
69
- align="end"
70
- forceMount
71
- >
72
- {/* User Info */}
73
- <div className="flex items-center space-x-3 p-3">
74
- <Avatar className="h-8 w-8">
75
- <AvatarFallback
76
- className="border font-medium text-xs"
77
- style={avatarStyles}
78
- >
79
- {userInitials}
80
- </AvatarFallback>
81
- </Avatar>
82
- <div className="flex flex-col space-y-0.5">
83
- <p className="text-sm font-medium leading-none text-foreground">
84
- {(user as any)?.name || 'Design User'}
85
- </p>
86
- <p className="text-xs leading-none text-muted-foreground">
87
- {user?.email || 'user@design.studio'}
88
- </p>
89
- </div>
90
- </div>
91
-
92
- <DropdownMenuSeparator />
93
-
94
- {/* Dark Mode Toggle */}
95
- <DropdownMenuItem
96
- className="cursor-pointer focus:bg-muted/50"
97
- onClick={toggleDarkMode}
98
- >
99
- {isDark ? (
100
- <Sun className="mr-2 h-4 w-4" />
101
- ) : (
102
- <Moon className="mr-2 h-4 w-4" />
103
- )}
104
- <span>{isDark ? 'Light Mode' : 'Dark Mode'}</span>
105
- </DropdownMenuItem>
106
-
107
- <DropdownMenuSeparator />
108
-
109
- {/* Menu Items */}
110
- <DropdownMenuItem
111
- className="cursor-pointer focus:bg-muted/50"
112
- onClick={() => alert('Profile coming soon!')}
113
- >
114
- <UserCircle className="mr-2 h-4 w-4" />
115
- <span>Profile</span>
116
- </DropdownMenuItem>
117
-
118
- <DropdownMenuItem
119
- className="cursor-pointer focus:bg-muted/50"
120
- onClick={() => alert('Settings coming soon!')}
121
- >
122
- <Settings className="mr-2 h-4 w-4" />
123
- <span>Settings</span>
124
- </DropdownMenuItem>
125
-
126
- <DropdownMenuSeparator />
127
-
128
- <DropdownMenuItem
129
- className="cursor-pointer text-destructive focus:text-destructive focus:bg-destructive/10"
130
- onClick={handleLogout}
131
- >
132
- <LogOut className="mr-2 h-4 w-4" />
133
- <span>Logout</span>
134
- </DropdownMenuItem>
135
- </DropdownMenuContent>
136
- </DropdownMenu>
137
- </div>
138
- );
139
- };
@@ -1 +0,0 @@
1
- export { UserAvatar } from './UserAvatar';
@@ -1,16 +0,0 @@
1
- import React from 'react';
2
- import { UserAvatar } from '../UserAvatar';
3
- import { cn } from '../../utils/utils';
4
-
5
- interface UserMenuProps {
6
- className?: string;
7
- category?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
8
- }
9
-
10
- export const UserMenu: React.FC<UserMenuProps> = ({ className, category }) => {
11
- return (
12
- <div className={cn("flex items-center", className)}>
13
- <UserAvatar category={category} />
14
- </div>
15
- );
16
- };
@@ -1 +0,0 @@
1
- export { UserMenu } from './UserMenu';
@@ -1,29 +0,0 @@
1
- // Business-specific shared components
2
- export { DataBadge } from './DataBadge';
3
- export { StatCard } from './StatCard';
4
- export { DetailedCard } from './DetailedCard';
5
- export { EmptyState } from './EmptyState';
6
- export { ColorSwatch } from './ColorSwatch';
7
- export { IconBadge } from './IconBadge';
8
- export { UserAvatar } from './UserAvatar';
9
- export { UserMenu } from './UserMenu';
10
- export { GlobalSearch } from './GlobalSearch';
11
- export { DataTable } from './DataTable';
12
- export { DateTimePicker } from './DateTimePicker';
13
- export { Chart } from './Chart';
14
- export { Accordion } from './Accordion';
15
- export { Modal } from './Modal';
16
- export { Tooltip } from './Tooltip';
17
- export { FileUpload } from './FileUpload';
18
-
19
- // Moved from molecules - business UI components
20
- export { Alert } from './Alert';
21
- export { Toast, ToastContainer } from './Toast';
22
- export { ProgressBar } from './ProgressBar';
23
- export { FormField } from './FormField';
24
- export { Breadcrumb } from './Breadcrumb';
25
-
26
- // Re-export any remaining components
27
- export { DarkModeToggle } from './DarkModeToggle';
28
- export { PaletteSwitcher } from './PaletteSwitcher';
29
- export { StyleGuide } from './StyleGuide';