@umituz/web-design-system 3.1.22 → 4.0.2
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/README.md +137 -469
- package/dist/styles.css +2 -0
- package/package.json +31 -31
- package/src/__tests__/cn.test.ts +24 -0
- package/src/__tests__/components.smoke.test.tsx +78 -0
- package/src/__tests__/styles.contract.test.ts +60 -0
- package/src/domain/tokens/index.ts +8 -49
- package/src/index.ts +8 -10
- package/src/infrastructure/constants/component.constants.ts +3 -17
- package/src/infrastructure/constants/index.ts +4 -2
- package/src/infrastructure/constants/timing.constants.ts +46 -0
- package/src/infrastructure/utils/calculation.utils.ts +74 -0
- package/src/infrastructure/utils/cn.util.ts +1 -1
- package/src/infrastructure/utils/index.ts +12 -0
- package/src/presentation/atoms/IconButton.tsx +55 -0
- package/src/presentation/atoms/Progress.tsx +2 -1
- package/src/presentation/atoms/Spinner.tsx +1 -1
- package/src/presentation/atoms/Switch.tsx +2 -2
- package/src/presentation/atoms/Text.tsx +15 -13
- package/src/presentation/atoms/Tooltip.tsx +2 -1
- package/src/presentation/atoms/index.ts +3 -0
- package/src/presentation/hooks/index.ts +0 -3
- package/src/presentation/hooks/useClickOutside.ts +16 -10
- package/src/presentation/hooks/useClipboard.ts +30 -12
- package/src/presentation/hooks/useDebounce.ts +9 -11
- package/src/presentation/hooks/useLocalStorage.ts +32 -20
- package/src/presentation/hooks/useMediaQuery.ts +20 -15
- package/src/presentation/hooks/useScrollLock.ts +40 -12
- package/src/presentation/hooks/useToggle.ts +8 -6
- package/src/presentation/molecules/ActiveFilterTags.tsx +19 -18
- package/src/presentation/molecules/Avatar.tsx +1 -1
- package/src/presentation/molecules/CodeBlock.tsx +50 -48
- package/src/presentation/molecules/InputGroup.tsx +1 -1
- package/src/presentation/molecules/ListItem.tsx +40 -29
- package/src/presentation/molecules/Select.tsx +1 -1
- package/src/presentation/molecules/Toggle.tsx +4 -4
- package/src/presentation/molecules/index.ts +0 -3
- package/src/presentation/organisms/Alert.tsx +1 -1
- package/src/presentation/organisms/DataTable.tsx +26 -15
- package/src/presentation/organisms/Dialog.tsx +1 -1
- package/src/presentation/organisms/DropdownMenu.tsx +2 -2
- package/src/presentation/organisms/HoverCard.tsx +1 -1
- package/src/presentation/organisms/LoadingState.tsx +1 -5
- package/src/presentation/organisms/Popover.tsx +1 -1
- package/src/presentation/organisms/StatCard.tsx +2 -2
- package/src/presentation/organisms/Table.tsx +2 -2
- package/src/presentation/organisms/index.ts +0 -60
- package/src/styles/compile.css +18 -0
- package/src/styles/theme.css +131 -0
- package/src/domain/tokens/animation.tokens.ts +0 -87
- package/src/domain/tokens/color.tokens.ts +0 -95
- package/src/domain/tokens/radius.tokens.ts +0 -27
- package/src/domain/tokens/shadow.tokens.ts +0 -25
- package/src/domain/tokens/spacing.tokens.ts +0 -65
- package/src/domain/tokens/typography.tokens.ts +0 -74
- package/src/infrastructure/error/ErrorBoundary.tsx +0 -258
- package/src/infrastructure/error/ErrorDisplay.tsx +0 -346
- package/src/infrastructure/error/SuspenseWrapper.tsx +0 -133
- package/src/infrastructure/error/index.ts +0 -5
- package/src/infrastructure/performance/index.ts +0 -92
- package/src/infrastructure/performance/useLazyLoading.ts +0 -342
- package/src/infrastructure/performance/useMemoryOptimization.ts +0 -293
- package/src/infrastructure/performance/usePerformanceMonitor.ts +0 -158
- package/src/infrastructure/security/index.ts +0 -10
- package/src/infrastructure/security/security-config.ts +0 -171
- package/src/infrastructure/security/useFormValidation.ts +0 -216
- package/src/infrastructure/security/validation.ts +0 -246
- package/src/presentation/hooks/useLanguage.ts +0 -109
- package/src/presentation/molecules/Breadcrumb.tsx +0 -54
- package/src/presentation/organisms/AlertDialog.tsx +0 -181
- package/src/presentation/organisms/Calendar.tsx +0 -79
- package/src/presentation/organisms/Comments.tsx +0 -103
- package/src/presentation/organisms/ConfirmDialog.tsx +0 -97
- package/src/presentation/organisms/FilterBar.tsx +0 -244
- package/src/presentation/organisms/FilterSidebar.tsx +0 -172
- package/src/presentation/organisms/Footer.tsx +0 -86
- package/src/presentation/organisms/FormModal.tsx +0 -126
- package/src/presentation/organisms/Grid.tsx +0 -128
- package/src/presentation/organisms/ImageLightbox.tsx +0 -252
- package/src/presentation/organisms/MainNavbar.tsx +0 -320
- package/src/presentation/organisms/Modal.tsx +0 -173
- package/src/presentation/organisms/Navbar.tsx +0 -75
- package/src/presentation/organisms/NewsletterSignup.tsx +0 -165
- package/src/presentation/organisms/QuickActionCard.tsx +0 -93
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { useState, useMemo } from 'react';
|
|
7
|
+
import { ArrowDown, ArrowUp, ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from 'lucide-react';
|
|
7
8
|
import { cn } from '../../infrastructure/utils';
|
|
8
9
|
import {
|
|
9
10
|
Table,
|
|
@@ -16,8 +17,12 @@ import {
|
|
|
16
17
|
TableCaption,
|
|
17
18
|
} from './Table';
|
|
18
19
|
import { Button } from '../atoms/Button';
|
|
19
|
-
import {
|
|
20
|
-
|
|
20
|
+
import {
|
|
21
|
+
computeTotalPages,
|
|
22
|
+
clampPageNumber,
|
|
23
|
+
computePageBounds,
|
|
24
|
+
} from '../../infrastructure/utils/calculation.utils';
|
|
25
|
+
import type { BaseProps } from '../../domain/types';
|
|
21
26
|
import type { MediumSizes } from '../../infrastructure/constants';
|
|
22
27
|
|
|
23
28
|
export interface Column<T> {
|
|
@@ -34,7 +39,6 @@ export interface DataTableProps<T> extends BaseProps {
|
|
|
34
39
|
columns: Column<T>[];
|
|
35
40
|
caption?: string;
|
|
36
41
|
size?: MediumSizes;
|
|
37
|
-
variant?: ColorVariant;
|
|
38
42
|
sortable?: boolean;
|
|
39
43
|
paginated?: boolean;
|
|
40
44
|
pageSize?: number;
|
|
@@ -45,13 +49,12 @@ export interface DataTableProps<T> extends BaseProps {
|
|
|
45
49
|
onRowClick?: (row: T) => void;
|
|
46
50
|
}
|
|
47
51
|
|
|
48
|
-
export function DataTable<T
|
|
52
|
+
export function DataTable<T>({
|
|
49
53
|
className,
|
|
50
54
|
data,
|
|
51
55
|
columns,
|
|
52
56
|
caption,
|
|
53
57
|
size = 'md',
|
|
54
|
-
variant = 'primary',
|
|
55
58
|
sortable = false,
|
|
56
59
|
paginated = false,
|
|
57
60
|
pageSize = 10,
|
|
@@ -100,7 +103,9 @@ export function DataTable<T extends Record<string, unknown>>({
|
|
|
100
103
|
return sortedData.slice(start, end);
|
|
101
104
|
}, [sortedData, currentPage, paginated, pageSize]);
|
|
102
105
|
|
|
103
|
-
const totalPages =
|
|
106
|
+
const totalPages = computeTotalPages(data.length, pageSize);
|
|
107
|
+
const safePage = clampPageNumber(currentPage, totalPages);
|
|
108
|
+
const pageBounds = computePageBounds(currentPage, pageSize, data.length);
|
|
104
109
|
|
|
105
110
|
const renderCell = (row: T, column: Column<T>) => {
|
|
106
111
|
if (column.cell) {
|
|
@@ -154,7 +159,13 @@ export function DataTable<T extends Record<string, unknown>>({
|
|
|
154
159
|
<div className="flex items-center gap-2">
|
|
155
160
|
{column.header}
|
|
156
161
|
{column.sortable && sortable && sortColumn === column.id && (
|
|
157
|
-
<span className="text-xs">
|
|
162
|
+
<span className="text-xs">
|
|
163
|
+
{sortDirection === 'asc' ? (
|
|
164
|
+
<ArrowUp className="h-3 w-3" aria-hidden="true" />
|
|
165
|
+
) : (
|
|
166
|
+
<ArrowDown className="h-3 w-3" aria-hidden="true" />
|
|
167
|
+
)}
|
|
168
|
+
</span>
|
|
158
169
|
)}
|
|
159
170
|
</div>
|
|
160
171
|
</TableHead>
|
|
@@ -185,33 +196,33 @@ export function DataTable<T extends Record<string, unknown>>({
|
|
|
185
196
|
<TableCell colSpan={columns.length}>
|
|
186
197
|
<div className="flex items-center justify-between">
|
|
187
198
|
<p className={cn('text-muted-foreground', sizeStyles[size])}>
|
|
188
|
-
Showing {
|
|
199
|
+
Showing {pageBounds.startIndex} to {pageBounds.endIndex} of {data.length} results
|
|
189
200
|
</p>
|
|
190
201
|
<div className="flex items-center gap-2">
|
|
191
202
|
<Button
|
|
192
203
|
size="sm"
|
|
193
204
|
variant="outline"
|
|
194
205
|
onClick={() => setCurrentPage(1)}
|
|
195
|
-
disabled={
|
|
206
|
+
disabled={safePage === 1}
|
|
196
207
|
>
|
|
197
208
|
<ChevronsLeft className="h-4 w-4" />
|
|
198
209
|
</Button>
|
|
199
210
|
<Button
|
|
200
211
|
size="sm"
|
|
201
212
|
variant="outline"
|
|
202
|
-
onClick={() => setCurrentPage((p) =>
|
|
203
|
-
disabled={
|
|
213
|
+
onClick={() => setCurrentPage((p) => clampPageNumber(p - 1, totalPages))}
|
|
214
|
+
disabled={safePage === 1}
|
|
204
215
|
>
|
|
205
216
|
<ChevronLeft className="h-4 w-4" />
|
|
206
217
|
</Button>
|
|
207
218
|
<span className={cn('text-sm font-medium', sizeStyles[size])}>
|
|
208
|
-
Page {
|
|
219
|
+
Page {safePage} of {totalPages}
|
|
209
220
|
</span>
|
|
210
221
|
<Button
|
|
211
222
|
size="sm"
|
|
212
223
|
variant="outline"
|
|
213
|
-
onClick={() => setCurrentPage((p) =>
|
|
214
|
-
disabled={
|
|
224
|
+
onClick={() => setCurrentPage((p) => clampPageNumber(p + 1, totalPages))}
|
|
225
|
+
disabled={safePage === totalPages}
|
|
215
226
|
>
|
|
216
227
|
<ChevronRight className="h-4 w-4" />
|
|
217
228
|
</Button>
|
|
@@ -219,7 +230,7 @@ export function DataTable<T extends Record<string, unknown>>({
|
|
|
219
230
|
size="sm"
|
|
220
231
|
variant="outline"
|
|
221
232
|
onClick={() => setCurrentPage(totalPages)}
|
|
222
|
-
disabled={
|
|
233
|
+
disabled={safePage === totalPages}
|
|
223
234
|
>
|
|
224
235
|
<ChevronsRight className="h-4 w-4" />
|
|
225
236
|
</Button>
|
|
@@ -40,7 +40,7 @@ const DialogContent = React.forwardRef<
|
|
|
40
40
|
<DialogPrimitive.Content
|
|
41
41
|
ref={ref}
|
|
42
42
|
className={cn(
|
|
43
|
-
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
|
|
43
|
+
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
|
|
44
44
|
className
|
|
45
45
|
)}
|
|
46
46
|
{...props}
|
|
@@ -49,7 +49,7 @@ const DropdownMenuSubContent = React.forwardRef<
|
|
|
49
49
|
<DropdownMenuPrimitive.SubContent
|
|
50
50
|
ref={ref}
|
|
51
51
|
className={cn(
|
|
52
|
-
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
|
52
|
+
'z-50 min-w-[8rem] overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
|
53
53
|
className
|
|
54
54
|
)}
|
|
55
55
|
{...props}
|
|
@@ -67,7 +67,7 @@ const DropdownMenuContent = React.forwardRef<
|
|
|
67
67
|
collisionPadding={collisionPadding}
|
|
68
68
|
sideOffset={sideOffset}
|
|
69
69
|
className={cn(
|
|
70
|
-
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md',
|
|
70
|
+
'z-50 min-w-[8rem] overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md',
|
|
71
71
|
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
|
72
72
|
className
|
|
73
73
|
)}
|
|
@@ -20,7 +20,7 @@ const HoverCardContent = React.forwardRef<
|
|
|
20
20
|
align={align}
|
|
21
21
|
sideOffset={sideOffset}
|
|
22
22
|
className={cn(
|
|
23
|
-
'z-50 w-64 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
|
23
|
+
'z-50 w-64 rounded-md border border-border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
|
24
24
|
className
|
|
25
25
|
)}
|
|
26
26
|
{...props}
|
|
@@ -46,11 +46,7 @@ export const LoadingState = forwardRef<HTMLDivElement, LoadingStateProps>(
|
|
|
46
46
|
{[0, 1, 2].map((i) => (
|
|
47
47
|
<div
|
|
48
48
|
key={i}
|
|
49
|
-
className=
|
|
50
|
-
'w-2 h-2 bg-primary rounded-full animate-bounce',
|
|
51
|
-
'w-1.5 h-1.5 sm:w-2 sm:h-2',
|
|
52
|
-
'lg:w-2.5 h-2.5'
|
|
53
|
-
)}
|
|
49
|
+
className="h-1.5 w-1.5 animate-bounce rounded-full bg-primary sm:h-2 sm:w-2 lg:h-2.5 lg:w-2.5"
|
|
54
50
|
style={{ animationDelay: `${i * 0.15}s` }}
|
|
55
51
|
/>
|
|
56
52
|
))}
|
|
@@ -21,7 +21,7 @@ const PopoverContent = React.forwardRef<
|
|
|
21
21
|
align={align}
|
|
22
22
|
sideOffset={sideOffset}
|
|
23
23
|
className={cn(
|
|
24
|
-
'z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
|
24
|
+
'z-50 w-72 rounded-md border border-border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
|
|
25
25
|
className
|
|
26
26
|
)}
|
|
27
27
|
{...props}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* StatCard Component (Organism)
|
|
3
3
|
* @description Enhanced metric card with progress bar and target tracking (Responsive)
|
|
4
|
-
* Combines functionality of KPICard and StatsCard from main app
|
|
5
4
|
*/
|
|
6
5
|
|
|
7
6
|
import { forwardRef, type ComponentType } from 'react';
|
|
@@ -9,6 +8,7 @@ import { cn, getSpacing, getIconSize, getContainerSize, getTextSize, getSpaceY,
|
|
|
9
8
|
import { Card, CardContent } from './Card';
|
|
10
9
|
import { Progress } from '../atoms';
|
|
11
10
|
import { ArrowUpRight, ArrowDownRight } from 'lucide-react';
|
|
11
|
+
import { formatTrendMagnitude } from '../../infrastructure/utils/calculation.utils';
|
|
12
12
|
import type { BaseProps, SizeVariant } from '../../domain/types';
|
|
13
13
|
|
|
14
14
|
export interface StatCardProps extends BaseProps {
|
|
@@ -44,7 +44,7 @@ export const StatCard = forwardRef<HTMLDivElement, StatCardProps>(
|
|
|
44
44
|
target,
|
|
45
45
|
size = 'md',
|
|
46
46
|
variant = 'default',
|
|
47
|
-
trendValueFormatter = (v) =>
|
|
47
|
+
trendValueFormatter = (v) => formatTrendMagnitude(v),
|
|
48
48
|
onClick,
|
|
49
49
|
changeLabel,
|
|
50
50
|
responsiveLayout = true,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @description Data table component
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { forwardRef, type HTMLAttributes } from 'react';
|
|
6
|
+
import { forwardRef, type HTMLAttributes, type TdHTMLAttributes } from 'react';
|
|
7
7
|
import React from 'react';
|
|
8
8
|
import { cn } from '../../infrastructure/utils';
|
|
9
9
|
import type { BaseProps } from '../../domain/types';
|
|
@@ -93,7 +93,7 @@ export const TableHead = React.memo(forwardRef<HTMLTableCellElement, HTMLAttribu
|
|
|
93
93
|
|
|
94
94
|
TableHead.displayName = 'TableHead';
|
|
95
95
|
|
|
96
|
-
export const TableCell = React.memo(forwardRef<HTMLTableCellElement,
|
|
96
|
+
export const TableCell = React.memo(forwardRef<HTMLTableCellElement, TdHTMLAttributes<HTMLTableCellElement>>(
|
|
97
97
|
({ className, ...props }, ref) => (
|
|
98
98
|
<td
|
|
99
99
|
ref={ref}
|
|
@@ -10,12 +10,6 @@ export type { CardProps } from './Card';
|
|
|
10
10
|
export { Alert, AlertTitle, AlertDescription } from './Alert';
|
|
11
11
|
export type { AlertProps } from './Alert';
|
|
12
12
|
|
|
13
|
-
export { Modal, ModalHeader, ModalTitle, ModalDescription, ModalContent, ModalFooter } from './Modal';
|
|
14
|
-
export type { ModalProps } from './Modal';
|
|
15
|
-
|
|
16
|
-
export { Navbar, NavbarBrand, NavbarLinks, NavbarActions } from './Navbar';
|
|
17
|
-
export type { NavbarProps } from './Navbar';
|
|
18
|
-
|
|
19
13
|
export {
|
|
20
14
|
Table,
|
|
21
15
|
TableHeader,
|
|
@@ -68,15 +62,9 @@ export {
|
|
|
68
62
|
SheetTrigger,
|
|
69
63
|
} from './Sheet';
|
|
70
64
|
|
|
71
|
-
export { Footer } from './Footer';
|
|
72
|
-
export type { FooterProps } from './Footer';
|
|
73
|
-
|
|
74
65
|
export { MetricCard } from './MetricCard';
|
|
75
66
|
export type { MetricCardProps } from './MetricCard';
|
|
76
67
|
|
|
77
|
-
export { QuickActionCard } from './QuickActionCard';
|
|
78
|
-
export type { QuickActionCardProps } from './QuickActionCard';
|
|
79
|
-
|
|
80
68
|
export { EmptyState } from './EmptyState';
|
|
81
69
|
export type { EmptyStateProps } from './EmptyState';
|
|
82
70
|
|
|
@@ -89,32 +77,6 @@ export type { DataTableProps, Column } from './DataTable';
|
|
|
89
77
|
export { StatCard } from './StatCard';
|
|
90
78
|
export type { StatCardProps } from './StatCard';
|
|
91
79
|
|
|
92
|
-
export { FormModal } from './FormModal';
|
|
93
|
-
export type { FormModalProps } from './FormModal';
|
|
94
|
-
|
|
95
|
-
export { Grid, GridItem } from './Grid';
|
|
96
|
-
export type { GridProps, GridItemProps } from './Grid';
|
|
97
|
-
|
|
98
|
-
export { ConfirmDialog } from './ConfirmDialog';
|
|
99
|
-
export type { ConfirmDialogProps } from './ConfirmDialog';
|
|
100
|
-
|
|
101
|
-
export { Calendar } from './Calendar';
|
|
102
|
-
export type { CalendarProps } from './Calendar';
|
|
103
|
-
|
|
104
|
-
export {
|
|
105
|
-
AlertDialog,
|
|
106
|
-
AlertDialogPortal,
|
|
107
|
-
AlertDialogOverlay,
|
|
108
|
-
AlertDialogTrigger,
|
|
109
|
-
AlertDialogContent,
|
|
110
|
-
AlertDialogHeader,
|
|
111
|
-
AlertDialogFooter,
|
|
112
|
-
AlertDialogTitle,
|
|
113
|
-
AlertDialogDescription,
|
|
114
|
-
AlertDialogAction,
|
|
115
|
-
AlertDialogCancel,
|
|
116
|
-
} from './AlertDialog';
|
|
117
|
-
|
|
118
80
|
export {
|
|
119
81
|
DropdownMenu,
|
|
120
82
|
DropdownMenuTrigger,
|
|
@@ -134,25 +96,3 @@ export {
|
|
|
134
96
|
} from './DropdownMenu';
|
|
135
97
|
|
|
136
98
|
export { ToggleGroup, ToggleGroupItem } from './ToggleGroup';
|
|
137
|
-
|
|
138
|
-
// NEW: Media & Content Components
|
|
139
|
-
export { ImageLightbox } from './ImageLightbox';
|
|
140
|
-
export type { ImageLightboxProps, ImageLightboxImage } from './ImageLightbox';
|
|
141
|
-
|
|
142
|
-
// NEW: Content & Engagement Components
|
|
143
|
-
export { NewsletterSignup } from './NewsletterSignup';
|
|
144
|
-
export type { NewsletterSignupProps } from './NewsletterSignup';
|
|
145
|
-
|
|
146
|
-
export { Comments } from './Comments';
|
|
147
|
-
export type { CommentsProps, GiscusConfig } from './Comments';
|
|
148
|
-
|
|
149
|
-
// NEW: Filter Components
|
|
150
|
-
export { FilterBar } from './FilterBar';
|
|
151
|
-
export type { FilterBarProps, Category, SortOption } from './FilterBar';
|
|
152
|
-
|
|
153
|
-
export { FilterSidebar } from './FilterSidebar';
|
|
154
|
-
export type { FilterSidebarProps } from './FilterSidebar';
|
|
155
|
-
|
|
156
|
-
// NEW: Navigation Components
|
|
157
|
-
export { MainNavbar } from './MainNavbar';
|
|
158
|
-
export type { MainNavbarProps, NavItem, MainNavbarLanguage } from './MainNavbar';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @umituz/web-design-system — Tailwind v4 compile entry
|
|
3
|
+
*
|
|
4
|
+
* Input for the build step (`npm run build`) that produces
|
|
5
|
+
* `dist/styles.css`: Tailwind + animations + the theme layer, with the
|
|
6
|
+
* component source scanned for utility classes.
|
|
7
|
+
*
|
|
8
|
+
* Vanilla hosts import the precompiled output:
|
|
9
|
+
* @import "@umituz/web-design-system/styles.css";
|
|
10
|
+
*
|
|
11
|
+
* Tailwind v4 hosts compile this package's source themselves instead
|
|
12
|
+
* (see README) and must NOT also import the precompiled stylesheet.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
@import "tailwindcss";
|
|
16
|
+
@import "tw-animate-css";
|
|
17
|
+
@import "./theme.css";
|
|
18
|
+
@source "../src";
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @umituz/web-design-system — theme layer (Tailwind v4 `@theme`)
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for colors, radii, fonts and shadows. Component
|
|
5
|
+
* classes are semantic (`bg-primary`, `text-muted-foreground`, …) and bind
|
|
6
|
+
* to the `--color-*` variables defined here, so hosts restyle the whole
|
|
7
|
+
* package by overriding variables — no Tailwind rebuild required.
|
|
8
|
+
*
|
|
9
|
+
* The default palette mirrors @umituz/web-dashboard's tokens.css, so
|
|
10
|
+
* dashboard adoption is visually regression-free.
|
|
11
|
+
*
|
|
12
|
+
* Dark mode: add `data-theme="dark"` or `class="dark"` on any ancestor
|
|
13
|
+
* (typically <html>). The package never switches themes on its own.
|
|
14
|
+
*
|
|
15
|
+
* Tailwind v4 hosts that compile the package source themselves
|
|
16
|
+
* (`@source "../node_modules/@umituz/web-design-system/src"`) import this
|
|
17
|
+
* file; vanilla hosts import the precompiled `dist/styles.css`.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
@theme {
|
|
21
|
+
/* Surfaces & text */
|
|
22
|
+
--color-background: #f8fafc;
|
|
23
|
+
--color-foreground: #0f172a;
|
|
24
|
+
--color-card: #ffffff;
|
|
25
|
+
--color-card-foreground: #0f172a;
|
|
26
|
+
--color-popover: #ffffff;
|
|
27
|
+
--color-popover-foreground: #0f172a;
|
|
28
|
+
|
|
29
|
+
/* Brand */
|
|
30
|
+
--color-primary: #2563eb;
|
|
31
|
+
--color-primary-foreground: #ffffff;
|
|
32
|
+
--color-secondary: #8b5cf6;
|
|
33
|
+
--color-secondary-foreground: #ffffff;
|
|
34
|
+
|
|
35
|
+
/* Neutral */
|
|
36
|
+
--color-muted: #f1f5f9;
|
|
37
|
+
--color-muted-foreground: #64748b;
|
|
38
|
+
--color-accent: #f1f5f9;
|
|
39
|
+
--color-accent-foreground: #0f172a;
|
|
40
|
+
--color-border: #e2e8f0;
|
|
41
|
+
--color-input: #e2e8f0;
|
|
42
|
+
|
|
43
|
+
/* Semantic */
|
|
44
|
+
--color-destructive: #dc2626;
|
|
45
|
+
--color-destructive-foreground: #ffffff;
|
|
46
|
+
--color-success: #16a34a;
|
|
47
|
+
--color-success-foreground: #ffffff;
|
|
48
|
+
--color-warning: #d97706;
|
|
49
|
+
--color-warning-foreground: #ffffff;
|
|
50
|
+
--color-info: #2563eb;
|
|
51
|
+
--color-info-foreground: #ffffff;
|
|
52
|
+
|
|
53
|
+
/* Focus */
|
|
54
|
+
--color-ring: rgba(37, 99, 235, 0.45);
|
|
55
|
+
|
|
56
|
+
/* Radii (dashboard scale) */
|
|
57
|
+
--radius-sm: 6px;
|
|
58
|
+
--radius-md: 8px;
|
|
59
|
+
--radius-lg: 12px;
|
|
60
|
+
--radius-xl: 16px;
|
|
61
|
+
|
|
62
|
+
/* Typography */
|
|
63
|
+
--font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
|
|
64
|
+
"Helvetica Neue", Arial, "Noto Sans", sans-serif;
|
|
65
|
+
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
|
66
|
+
"Liberation Mono", "Courier New", monospace;
|
|
67
|
+
|
|
68
|
+
/* Elevation (dashboard scale) */
|
|
69
|
+
--shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.06);
|
|
70
|
+
--shadow-md: 0 4px 12px rgba(15, 23, 42, 0.08);
|
|
71
|
+
--shadow-lg: 0 12px 32px rgba(15, 23, 42, 0.14);
|
|
72
|
+
|
|
73
|
+
/* Accordion (Radix --radix-accordion-content-height driven) */
|
|
74
|
+
--animate-accordion-down: accordion-down 0.2s ease-out;
|
|
75
|
+
--animate-accordion-up: accordion-up 0.2s ease-out;
|
|
76
|
+
|
|
77
|
+
@keyframes accordion-down {
|
|
78
|
+
from {
|
|
79
|
+
height: 0;
|
|
80
|
+
}
|
|
81
|
+
to {
|
|
82
|
+
height: var(--radix-accordion-content-height);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
@keyframes accordion-up {
|
|
87
|
+
from {
|
|
88
|
+
height: var(--radix-accordion-content-height);
|
|
89
|
+
}
|
|
90
|
+
to {
|
|
91
|
+
height: 0;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
[data-theme="dark"],
|
|
97
|
+
.dark {
|
|
98
|
+
--color-background: #0b1120;
|
|
99
|
+
--color-foreground: #f1f5f9;
|
|
100
|
+
--color-card: #111827;
|
|
101
|
+
--color-card-foreground: #f1f5f9;
|
|
102
|
+
--color-popover: #111827;
|
|
103
|
+
--color-popover-foreground: #f1f5f9;
|
|
104
|
+
|
|
105
|
+
--color-primary: #3b82f6;
|
|
106
|
+
--color-primary-foreground: #ffffff;
|
|
107
|
+
--color-secondary: #a78bfa;
|
|
108
|
+
--color-secondary-foreground: #ffffff;
|
|
109
|
+
|
|
110
|
+
--color-muted: #1e293b;
|
|
111
|
+
--color-muted-foreground: #94a3b8;
|
|
112
|
+
--color-accent: #1e293b;
|
|
113
|
+
--color-accent-foreground: #f1f5f9;
|
|
114
|
+
--color-border: #1f2a3c;
|
|
115
|
+
--color-input: #1f2a3c;
|
|
116
|
+
|
|
117
|
+
--color-destructive: #ef4444;
|
|
118
|
+
--color-destructive-foreground: #ffffff;
|
|
119
|
+
--color-success: #22c55e;
|
|
120
|
+
--color-success-foreground: #ffffff;
|
|
121
|
+
--color-warning: #f59e0b;
|
|
122
|
+
--color-warning-foreground: #ffffff;
|
|
123
|
+
--color-info: #3b82f6;
|
|
124
|
+
--color-info-foreground: #ffffff;
|
|
125
|
+
|
|
126
|
+
--color-ring: rgba(96, 165, 250, 0.5);
|
|
127
|
+
|
|
128
|
+
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
|
|
129
|
+
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.45);
|
|
130
|
+
--shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.55);
|
|
131
|
+
}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Animation Tokens
|
|
3
|
-
* @description Animation durations, easings, and keyframes
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export type DurationToken =
|
|
7
|
-
| 'instant'
|
|
8
|
-
| 'fast'
|
|
9
|
-
| 'normal'
|
|
10
|
-
| 'slow'
|
|
11
|
-
| 'slower';
|
|
12
|
-
|
|
13
|
-
export type EasingToken =
|
|
14
|
-
| 'linear'
|
|
15
|
-
| 'ease'
|
|
16
|
-
| 'easeIn'
|
|
17
|
-
| 'easeOut'
|
|
18
|
-
| 'easeInOut'
|
|
19
|
-
| 'bounce'
|
|
20
|
-
| 'elastic';
|
|
21
|
-
|
|
22
|
-
export const durations: Record<DurationToken, string> = {
|
|
23
|
-
instant: '150ms',
|
|
24
|
-
fast: '200ms',
|
|
25
|
-
normal: '300ms',
|
|
26
|
-
slow: '500ms',
|
|
27
|
-
slower: '700ms',
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
export const easings: Record<EasingToken, string> = {
|
|
31
|
-
linear: 'linear',
|
|
32
|
-
ease: 'cubic-bezier(0.4, 0, 0.2, 1)',
|
|
33
|
-
easeIn: 'cubic-bezier(0.4, 0, 1, 1)',
|
|
34
|
-
easeOut: 'cubic-bezier(0, 0, 0.2, 1)',
|
|
35
|
-
easeInOut: 'cubic-bezier(0.4, 0, 0.2, 1)',
|
|
36
|
-
bounce: 'cubic-bezier(0.68, -0.55, 0.265, 1.55)',
|
|
37
|
-
elastic: 'cubic-bezier(0.87, 0, 0.13, 1)',
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
export const animations = {
|
|
41
|
-
fade: 'fade 300ms ease-out',
|
|
42
|
-
slide: 'slide 300ms ease-out',
|
|
43
|
-
scale: 'scale 200ms ease-out',
|
|
44
|
-
spin: 'spin 1s linear infinite',
|
|
45
|
-
ping: 'ping 1s cubic-bezier(0, 0, 0.2, 1) infinite',
|
|
46
|
-
pulse: 'pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite',
|
|
47
|
-
bounce: 'bounce 1s infinite',
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
export const keyframes = {
|
|
51
|
-
fade: {
|
|
52
|
-
from: { opacity: '0' },
|
|
53
|
-
to: { opacity: '1' },
|
|
54
|
-
},
|
|
55
|
-
slide: {
|
|
56
|
-
from: { transform: 'translateY(-10px)', opacity: '0' },
|
|
57
|
-
to: { transform: 'translateY(0)', opacity: '1' },
|
|
58
|
-
},
|
|
59
|
-
scale: {
|
|
60
|
-
from: { transform: 'scale(0.95)', opacity: '0' },
|
|
61
|
-
to: { transform: 'scale(1)', opacity: '1' },
|
|
62
|
-
},
|
|
63
|
-
spin: {
|
|
64
|
-
from: { transform: 'rotate(0deg)' },
|
|
65
|
-
to: { transform: 'rotate(360deg)' },
|
|
66
|
-
},
|
|
67
|
-
ping: {
|
|
68
|
-
'75%, 100%': {
|
|
69
|
-
transform: 'scale(2)',
|
|
70
|
-
opacity: '0',
|
|
71
|
-
},
|
|
72
|
-
},
|
|
73
|
-
pulse: {
|
|
74
|
-
'0%, 100%': { opacity: '1' },
|
|
75
|
-
'50%': { opacity: '0.5' },
|
|
76
|
-
},
|
|
77
|
-
bounce: {
|
|
78
|
-
'0%, 100%': {
|
|
79
|
-
transform: 'translateY(-25%)',
|
|
80
|
-
animationTimingFunction: 'cubic-bezier(0.8, 0, 1, 1)',
|
|
81
|
-
},
|
|
82
|
-
'50%': {
|
|
83
|
-
transform: 'translateY(0)',
|
|
84
|
-
animationTimingFunction: 'cubic-bezier(0, 0, 0.2, 1)',
|
|
85
|
-
},
|
|
86
|
-
},
|
|
87
|
-
};
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Color Tokens
|
|
3
|
-
* @description Design system color tokens
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export interface ColorTokens {
|
|
7
|
-
// Primary
|
|
8
|
-
primary: string;
|
|
9
|
-
primaryForeground: string;
|
|
10
|
-
|
|
11
|
-
// Secondary
|
|
12
|
-
secondary: string;
|
|
13
|
-
secondaryForeground: string;
|
|
14
|
-
|
|
15
|
-
// Background
|
|
16
|
-
background: string;
|
|
17
|
-
foreground: string;
|
|
18
|
-
|
|
19
|
-
// Surfaces
|
|
20
|
-
card: string;
|
|
21
|
-
cardForeground: string;
|
|
22
|
-
popover: string;
|
|
23
|
-
popoverForeground: string;
|
|
24
|
-
|
|
25
|
-
// Interactive
|
|
26
|
-
muted: string;
|
|
27
|
-
mutedForeground: string;
|
|
28
|
-
accent: string;
|
|
29
|
-
accentForeground: string;
|
|
30
|
-
|
|
31
|
-
// Status
|
|
32
|
-
destructive: string;
|
|
33
|
-
destructiveForeground: string;
|
|
34
|
-
success: string;
|
|
35
|
-
successForeground: string;
|
|
36
|
-
warning: string;
|
|
37
|
-
warningForeground: string;
|
|
38
|
-
|
|
39
|
-
// Borders
|
|
40
|
-
border: string;
|
|
41
|
-
input: string;
|
|
42
|
-
ring: string;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export const lightColorTokens: ColorTokens = {
|
|
46
|
-
primary: 'hsl(187 75% 38%)',
|
|
47
|
-
primaryForeground: 'hsl(0 0% 100%)',
|
|
48
|
-
secondary: 'hsl(215 20% 92%)',
|
|
49
|
-
secondaryForeground: 'hsl(220 20% 12%)',
|
|
50
|
-
background: 'hsl(210 20% 98%)',
|
|
51
|
-
foreground: 'hsl(220 20% 12%)',
|
|
52
|
-
card: 'hsl(0 0% 100%)',
|
|
53
|
-
cardForeground: 'hsl(220 20% 12%)',
|
|
54
|
-
popover: 'hsl(0 0% 100%)',
|
|
55
|
-
popoverForeground: 'hsl(220 20% 12%)',
|
|
56
|
-
muted: 'hsl(220 15% 94%)',
|
|
57
|
-
mutedForeground: 'hsl(215 15% 45%)',
|
|
58
|
-
accent: 'hsl(187 75% 38%)',
|
|
59
|
-
accentForeground: 'hsl(0 0% 100%)',
|
|
60
|
-
destructive: 'hsl(0 72% 51%)',
|
|
61
|
-
destructiveForeground: 'hsl(0 0% 100%)',
|
|
62
|
-
success: 'hsl(152 55% 40%)',
|
|
63
|
-
successForeground: 'hsl(0 0% 100%)',
|
|
64
|
-
warning: 'hsl(38 90% 48%)',
|
|
65
|
-
warningForeground: 'hsl(0 0% 100%)',
|
|
66
|
-
border: 'hsl(220 15% 88%)',
|
|
67
|
-
input: 'hsl(220 15% 88%)',
|
|
68
|
-
ring: 'hsl(187 75% 38%)',
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
export const darkColorTokens: ColorTokens = {
|
|
72
|
-
primary: 'hsl(187 85% 53%)',
|
|
73
|
-
primaryForeground: 'hsl(220 20% 7%)',
|
|
74
|
-
secondary: 'hsl(215 20% 20%)',
|
|
75
|
-
secondaryForeground: 'hsl(210 20% 98%)',
|
|
76
|
-
background: 'hsl(220 20% 7%)',
|
|
77
|
-
foreground: 'hsl(210 20% 92%)',
|
|
78
|
-
card: 'hsl(220 18% 11%)',
|
|
79
|
-
cardForeground: 'hsl(210 20% 92%)',
|
|
80
|
-
popover: 'hsl(220 18% 13%)',
|
|
81
|
-
popoverForeground: 'hsl(210 20% 92%)',
|
|
82
|
-
muted: 'hsl(220 15% 16%)',
|
|
83
|
-
mutedForeground: 'hsl(215 15% 55%)',
|
|
84
|
-
accent: 'hsl(187 85% 53%)',
|
|
85
|
-
accentForeground: 'hsl(220 20% 7%)',
|
|
86
|
-
destructive: 'hsl(0 72% 55%)',
|
|
87
|
-
destructiveForeground: 'hsl(0 0% 100%)',
|
|
88
|
-
success: 'hsl(152 60% 48%)',
|
|
89
|
-
successForeground: 'hsl(0 0% 100%)',
|
|
90
|
-
warning: 'hsl(38 92% 55%)',
|
|
91
|
-
warningForeground: 'hsl(220 20% 7%)',
|
|
92
|
-
border: 'hsl(220 15% 18%)',
|
|
93
|
-
input: 'hsl(220 15% 18%)',
|
|
94
|
-
ring: 'hsl(187 85% 53%)',
|
|
95
|
-
};
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Radius Tokens
|
|
3
|
-
* @description Border radius scale
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export type RadiusToken =
|
|
7
|
-
| 'none'
|
|
8
|
-
| 'sm'
|
|
9
|
-
| 'default'
|
|
10
|
-
| 'md'
|
|
11
|
-
| 'lg'
|
|
12
|
-
| 'xl'
|
|
13
|
-
| '2xl'
|
|
14
|
-
| '3xl'
|
|
15
|
-
| 'full';
|
|
16
|
-
|
|
17
|
-
export const radii: Record<RadiusToken, string> = {
|
|
18
|
-
'none': '0',
|
|
19
|
-
'sm': '0.125rem',
|
|
20
|
-
'default': '0.25rem',
|
|
21
|
-
'md': '0.375rem',
|
|
22
|
-
'lg': '0.5rem',
|
|
23
|
-
'xl': '0.75rem',
|
|
24
|
-
'2xl': '1rem',
|
|
25
|
-
'3xl': '1.5rem',
|
|
26
|
-
'full': '9999px',
|
|
27
|
-
};
|