@umituz/web-design-system 5.3.0 → 5.4.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/styles.css +1 -1
- package/package.json +1 -1
- package/src/__tests__/cn.test.ts +0 -3
- package/src/__tests__/component-slots.test.tsx +0 -4
- package/src/__tests__/components.smoke.test.tsx +3 -11
- package/src/__tests__/money.test.tsx +0 -3
- package/src/__tests__/productivity-components.test.tsx +135 -0
- package/src/__tests__/styles.contract.test.ts +0 -13
- package/src/domain/tokens/index.ts +0 -7
- package/src/domain/tokens/responsive-map.tokens.ts +18 -107
- package/src/domain/types/breakpoint.types.ts +9 -13
- package/src/domain/types/component.types.ts +0 -4
- package/src/domain/types/index.ts +0 -5
- package/src/global.d.ts +0 -4
- package/src/index.ts +82 -29
- package/src/infrastructure/constants/breakpoint.constants.ts +0 -31
- package/src/infrastructure/constants/component.constants.ts +0 -4
- package/src/infrastructure/constants/index.ts +0 -5
- package/src/infrastructure/constants/size-variant.constants.ts +0 -33
- package/src/infrastructure/constants/spacing.constants.ts +34 -63
- package/src/infrastructure/constants/timing.constants.ts +0 -18
- package/src/infrastructure/constants/typography.constants.ts +22 -54
- package/src/infrastructure/utils/calculation.utils.ts +0 -9
- package/src/infrastructure/utils/cn.util.ts +0 -18
- package/src/infrastructure/utils/hash.util.ts +0 -5
- package/src/infrastructure/utils/index.ts +0 -5
- package/src/infrastructure/utils/money.utils.ts +0 -7
- package/src/infrastructure/utils/responsive.utils.ts +0 -66
- package/src/presentation/atoms/AspectRatio.tsx +0 -10
- package/src/presentation/atoms/Badge.tsx +0 -5
- package/src/presentation/atoms/BatteryPill.tsx +0 -5
- package/src/presentation/atoms/Button.tsx +0 -2
- package/src/presentation/atoms/Checkbox.tsx +0 -4
- package/src/presentation/atoms/CopyButton.tsx +93 -0
- package/src/presentation/atoms/Divider.tsx +0 -4
- package/src/presentation/atoms/HeatmapStrip.tsx +0 -10
- package/src/presentation/atoms/Hide.tsx +0 -24
- package/src/presentation/atoms/Icon.tsx +0 -4
- package/src/presentation/atoms/IconButton.tsx +0 -4
- package/src/presentation/atoms/Input.tsx +0 -4
- package/src/presentation/atoms/Kbd.tsx +0 -4
- package/src/presentation/atoms/Label.tsx +0 -4
- package/src/presentation/atoms/Link.tsx +0 -4
- package/src/presentation/atoms/Money.tsx +0 -6
- package/src/presentation/atoms/Progress.tsx +0 -6
- package/src/presentation/atoms/Radio.tsx +0 -4
- package/src/presentation/atoms/Separator.tsx +0 -4
- package/src/presentation/atoms/Show.tsx +0 -24
- package/src/presentation/atoms/Skeleton.tsx +0 -4
- package/src/presentation/atoms/Slider.tsx +0 -4
- package/src/presentation/atoms/Sparkline.tsx +0 -4
- package/src/presentation/atoms/Spinner.tsx +0 -4
- package/src/presentation/atoms/StatusDot.tsx +79 -0
- package/src/presentation/atoms/Switch.tsx +0 -4
- package/src/presentation/atoms/Text.tsx +0 -4
- package/src/presentation/atoms/Textarea.tsx +0 -4
- package/src/presentation/atoms/Toggle.tsx +0 -4
- package/src/presentation/atoms/Tooltip.tsx +0 -4
- package/src/presentation/atoms/index.ts +9 -9
- package/src/presentation/hooks/index.ts +0 -5
- package/src/presentation/hooks/useClickOutside.ts +0 -6
- package/src/presentation/hooks/useClipboard.ts +0 -4
- package/src/presentation/hooks/useDebounce.ts +0 -8
- package/src/presentation/hooks/useKeyboard.ts +0 -6
- package/src/presentation/hooks/useLocalStorage.ts +0 -4
- package/src/presentation/hooks/useMediaQuery.ts +0 -37
- package/src/presentation/hooks/useScrollLock.ts +0 -5
- package/src/presentation/hooks/useTheme.ts +9 -13
- package/src/presentation/hooks/useToggle.ts +0 -4
- package/src/presentation/molecules/ActiveFilterTags.tsx +0 -4
- package/src/presentation/molecules/Avatar.tsx +0 -5
- package/src/presentation/molecules/BookmarkButton.tsx +0 -15
- package/src/presentation/molecules/CheckboxGroup.tsx +0 -4
- package/src/presentation/molecules/Chip.tsx +0 -5
- package/src/presentation/molecules/CodeBlock.tsx +0 -5
- package/src/presentation/molecules/ConfirmButton.tsx +125 -0
- package/src/presentation/molecules/Field.tsx +0 -7
- package/src/presentation/molecules/FormField.tsx +1 -5
- package/src/presentation/molecules/InputGroup.tsx +0 -4
- package/src/presentation/molecules/ListItem.tsx +0 -4
- package/src/presentation/molecules/OptionTile.tsx +0 -10
- package/src/presentation/molecules/PasswordInput.tsx +43 -0
- package/src/presentation/molecules/RadioGroup.tsx +0 -4
- package/src/presentation/molecules/RatingStars.tsx +0 -8
- package/src/presentation/molecules/ScrollArea.tsx +0 -4
- package/src/presentation/molecules/SearchBox.tsx +0 -4
- package/src/presentation/molecules/SearchInput.tsx +110 -0
- package/src/presentation/molecules/Select.tsx +0 -4
- package/src/presentation/molecules/StatPill.tsx +0 -5
- package/src/presentation/molecules/TagInput.tsx +0 -7
- package/src/presentation/molecules/Textarea.tsx +0 -4
- package/src/presentation/molecules/Toggle.tsx +0 -4
- package/src/presentation/molecules/Toolbar.tsx +36 -0
- package/src/presentation/molecules/index.ts +25 -8
- package/src/presentation/organisms/Accordion.tsx +0 -4
- package/src/presentation/organisms/Alert.tsx +0 -4
- package/src/presentation/organisms/AvatarStack.tsx +0 -5
- package/src/presentation/organisms/Breadcrumb.tsx +0 -7
- package/src/presentation/organisms/Card.tsx +0 -6
- package/src/presentation/organisms/Checklist.tsx +0 -4
- package/src/presentation/organisms/Collapsible.tsx +0 -4
- package/src/presentation/organisms/ConfirmDialog.tsx +0 -8
- package/src/presentation/organisms/CoverArt.tsx +0 -9
- package/src/presentation/organisms/DataTable.tsx +0 -8
- package/src/presentation/organisms/DateRangePicker.tsx +0 -9
- package/src/presentation/organisms/DescriptionList.tsx +113 -0
- package/src/presentation/organisms/Dialog.tsx +0 -4
- package/src/presentation/organisms/Drawer.tsx +0 -6
- package/src/presentation/organisms/DropdownMenu.tsx +0 -4
- package/src/presentation/organisms/ErrorBoundary.tsx +0 -12
- package/src/presentation/organisms/FileUploader.tsx +0 -9
- package/src/presentation/organisms/FilterPopover.tsx +0 -8
- package/src/presentation/organisms/FormModal.tsx +0 -5
- package/src/presentation/organisms/HoverCard.tsx +0 -4
- package/src/presentation/organisms/KeyValueList.tsx +0 -4
- package/src/presentation/organisms/KpiCard.tsx +0 -6
- package/src/presentation/organisms/Lightbox.tsx +0 -7
- package/src/presentation/organisms/LoadingState.tsx +0 -4
- package/src/presentation/organisms/MapPreview.tsx +0 -9
- package/src/presentation/organisms/MetricCard.tsx +1 -5
- package/src/presentation/organisms/Modal.tsx +0 -4
- package/src/presentation/organisms/PhotoGallery.tsx +0 -9
- package/src/presentation/organisms/PlanPicker.tsx +0 -5
- package/src/presentation/organisms/Popover.tsx +0 -4
- package/src/presentation/organisms/Sheet.tsx +0 -4
- package/src/presentation/organisms/StatCard.tsx +0 -5
- package/src/presentation/organisms/StatsGrid.tsx +110 -0
- package/src/presentation/organisms/StatusBadge.tsx +0 -12
- package/src/presentation/organisms/Stepper.tsx +0 -5
- package/src/presentation/organisms/Table.tsx +0 -4
- package/src/presentation/organisms/Tabs.tsx +0 -7
- package/src/presentation/organisms/Timeline.tsx +0 -8
- package/src/presentation/organisms/Toaster.tsx +0 -9
- package/src/presentation/organisms/ToggleGroup.tsx +0 -4
- package/src/presentation/organisms/index.ts +10 -11
- package/src/presentation/templates/CrudPageTemplate.tsx +69 -0
- package/src/presentation/templates/Form.tsx +0 -4
- package/src/presentation/templates/List.tsx +0 -4
- package/src/presentation/templates/PageHeader.tsx +0 -4
- package/src/presentation/templates/PageLayout.tsx +0 -4
- package/src/presentation/templates/ProjectSkeleton.tsx +0 -4
- package/src/presentation/templates/ResponsiveContainer.tsx +0 -43
- package/src/presentation/templates/Section.tsx +0 -4
- package/src/presentation/templates/SettingsLayout.tsx +102 -0
- package/src/presentation/templates/index.ts +7 -6
- package/src/styles/app.css +0 -18
- package/src/styles/bridge.css +0 -34
- package/src/styles/compile.css +0 -13
- package/src/styles/source.css +0 -12
- package/src/styles/theme.css +0 -27
|
@@ -1,20 +1,11 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MapPreview Component (Organism)
|
|
3
|
-
* @description Static map stand-in drawn with a contour motif — a neutral
|
|
4
|
-
* placeholder for locations until a real GIS integration exists. Colors
|
|
5
|
-
* come from the semantic tokens, so it adapts to every host theme.
|
|
6
|
-
*/
|
|
7
1
|
|
|
8
2
|
import { MapPin } from 'lucide-react';
|
|
9
3
|
|
|
10
4
|
export interface MapPreviewProps {
|
|
11
|
-
/** Location caption, e.g. "Torba, Bodrum". */
|
|
12
5
|
label: string;
|
|
13
6
|
coordinates?: { lat: number; lng: number };
|
|
14
7
|
height?: number;
|
|
15
|
-
/** Secondary caption line, e.g. an integration note. */
|
|
16
8
|
hint?: string;
|
|
17
|
-
/** Degrees formatting for the coordinate readout; defaults to 4 decimals. */
|
|
18
9
|
formatCoordinate?: (value: number) => string;
|
|
19
10
|
}
|
|
20
11
|
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MetricCard Component (Organism)
|
|
3
|
-
* @description Card component for displaying metrics and statistics with trend indicators (Responsive)
|
|
4
|
-
*/
|
|
5
1
|
|
|
6
2
|
import { forwardRef } from 'react';
|
|
7
3
|
import { cn, getSpacing, getIconSize, getTextSize, getGap } from '../../infrastructure/utils';
|
|
@@ -21,7 +17,7 @@ export interface MetricCardProps extends BaseProps {
|
|
|
21
17
|
variant?: ColorVariant;
|
|
22
18
|
trendValueFormatter?: (value: number) => string;
|
|
23
19
|
onClick?: () => void;
|
|
24
|
-
responsiveLayout?: boolean;
|
|
20
|
+
responsiveLayout?: boolean;
|
|
25
21
|
}
|
|
26
22
|
|
|
27
23
|
const trendColors: Record<ColorVariant, { positive: string; negative: string; bg: string }> = {
|
|
@@ -1,20 +1,11 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PhotoGallery Component (Organism)
|
|
3
|
-
* @description Placeholder photo gallery — renders tinted tiles with a
|
|
4
|
-
* caption bar for photos that have no storage backend yet. When a host
|
|
5
|
-
* wires real image URLs it can render them inside the same tile frame.
|
|
6
|
-
*/
|
|
7
1
|
|
|
8
2
|
import { Image as ImageIcon, ImageOff } from 'lucide-react';
|
|
9
3
|
import { cn } from '../../infrastructure/utils';
|
|
10
4
|
|
|
11
5
|
export interface PhotoTile {
|
|
12
6
|
id: string;
|
|
13
|
-
/** Primary caption, e.g. the photo title. */
|
|
14
7
|
label?: string;
|
|
15
|
-
/** Secondary caption line, e.g. a kind tag or a date. */
|
|
16
8
|
meta?: string;
|
|
17
|
-
/** Optional image URL — rendered in place of the placeholder mark. */
|
|
18
9
|
src?: string;
|
|
19
10
|
}
|
|
20
11
|
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PlanPicker Component (Organism)
|
|
3
|
-
* @description Pricing plan card group with an optional billing cycle switch;
|
|
4
|
-
* money stays caller-computed — price and features are plain nodes
|
|
5
|
-
*/
|
|
6
1
|
|
|
7
2
|
import type { KeyboardEvent, ReactNode } from 'react';
|
|
8
3
|
import { Check } from 'lucide-react';
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* StatCard Component (Organism)
|
|
3
|
-
* @description Enhanced metric card with progress bar and target tracking (Responsive)
|
|
4
|
-
*/
|
|
5
1
|
|
|
6
2
|
import { forwardRef, type ComponentType } from 'react';
|
|
7
3
|
import { cn, getSpacing, getIconSize, getContainerSize, getTextSize, getSpaceY, getGap } from '../../infrastructure/utils';
|
|
@@ -20,7 +16,6 @@ export interface StatCardProps extends BaseProps {
|
|
|
20
16
|
value: number;
|
|
21
17
|
label?: string;
|
|
22
18
|
};
|
|
23
|
-
/** Secondary context line rendered under the title. */
|
|
24
19
|
meta?: string;
|
|
25
20
|
target?: {
|
|
26
21
|
value: string;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Card } from './Card';
|
|
3
|
+
import { Skeleton } from '../atoms/Skeleton';
|
|
4
|
+
import { TrendingUp, TrendingDown, Minus } from 'lucide-react';
|
|
5
|
+
import { cn } from '../../infrastructure/utils';
|
|
6
|
+
|
|
7
|
+
export interface StatItem {
|
|
8
|
+
id?: string;
|
|
9
|
+
title: string;
|
|
10
|
+
value: string | number;
|
|
11
|
+
change?: string;
|
|
12
|
+
trend?: 'up' | 'down' | 'neutral';
|
|
13
|
+
icon?: React.ReactNode;
|
|
14
|
+
description?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface StatsGridProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
18
|
+
stats: StatItem[];
|
|
19
|
+
columns?: 2 | 3 | 4;
|
|
20
|
+
loading?: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const colStyles = {
|
|
24
|
+
2: 'grid-cols-1 sm:grid-cols-2',
|
|
25
|
+
3: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-3',
|
|
26
|
+
4: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-4',
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const StatsGrid = React.forwardRef<HTMLDivElement, StatsGridProps>(
|
|
30
|
+
({ stats, columns = 4, loading = false, className, ...props }, ref) => {
|
|
31
|
+
if (loading) {
|
|
32
|
+
return (
|
|
33
|
+
<div
|
|
34
|
+
ref={ref}
|
|
35
|
+
className={cn('grid gap-4 w-full', colStyles[columns], className)}
|
|
36
|
+
{...props}
|
|
37
|
+
>
|
|
38
|
+
{Array.from({ length: columns }).map((_, i) => (
|
|
39
|
+
<Card key={i} className="p-5 flex flex-col gap-3">
|
|
40
|
+
<Skeleton className="h-4 w-24" />
|
|
41
|
+
<Skeleton className="h-8 w-32" />
|
|
42
|
+
<Skeleton className="h-3 w-40" />
|
|
43
|
+
</Card>
|
|
44
|
+
))}
|
|
45
|
+
</div>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<div
|
|
51
|
+
ref={ref}
|
|
52
|
+
className={cn('grid gap-4 w-full', colStyles[columns], className)}
|
|
53
|
+
{...props}
|
|
54
|
+
>
|
|
55
|
+
{stats.map((stat, idx) => {
|
|
56
|
+
const isUp = stat.trend === 'up';
|
|
57
|
+
const isDown = stat.trend === 'down';
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<Card
|
|
61
|
+
key={stat.id ?? idx}
|
|
62
|
+
className="p-5 flex flex-col justify-between transition-shadow hover:shadow-md"
|
|
63
|
+
>
|
|
64
|
+
<div className="flex items-start justify-between gap-2">
|
|
65
|
+
<span className="text-sm font-medium text-muted-foreground truncate">
|
|
66
|
+
{stat.title}
|
|
67
|
+
</span>
|
|
68
|
+
{stat.icon && (
|
|
69
|
+
<div className="size-9 rounded-lg bg-accent/60 flex items-center justify-center text-foreground shrink-0 [&_svg]:size-4">
|
|
70
|
+
{stat.icon}
|
|
71
|
+
</div>
|
|
72
|
+
)}
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
<div className="mt-3 flex items-baseline justify-between gap-2">
|
|
76
|
+
<div className="text-2xl font-bold tracking-tight text-foreground">
|
|
77
|
+
{stat.value}
|
|
78
|
+
</div>
|
|
79
|
+
|
|
80
|
+
{stat.change && (
|
|
81
|
+
<span
|
|
82
|
+
className={cn(
|
|
83
|
+
'inline-flex items-center gap-1 text-xs font-semibold px-2 py-0.5 rounded-full',
|
|
84
|
+
isUp && 'bg-emerald-500/10 text-emerald-600 dark:text-emerald-400',
|
|
85
|
+
isDown && 'bg-rose-500/10 text-rose-600 dark:text-rose-400',
|
|
86
|
+
!isUp && !isDown && 'bg-accent text-muted-foreground'
|
|
87
|
+
)}
|
|
88
|
+
>
|
|
89
|
+
{isUp && <TrendingUp className="size-3" />}
|
|
90
|
+
{isDown && <TrendingDown className="size-3" />}
|
|
91
|
+
{!isUp && !isDown && <Minus className="size-3" />}
|
|
92
|
+
<span>{stat.change}</span>
|
|
93
|
+
</span>
|
|
94
|
+
)}
|
|
95
|
+
</div>
|
|
96
|
+
|
|
97
|
+
{stat.description && (
|
|
98
|
+
<p className="mt-2 text-xs text-muted-foreground line-clamp-1">
|
|
99
|
+
{stat.description}
|
|
100
|
+
</p>
|
|
101
|
+
)}
|
|
102
|
+
</Card>
|
|
103
|
+
);
|
|
104
|
+
})}
|
|
105
|
+
</div>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
StatsGrid.displayName = 'StatsGrid';
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* StatusBadge Component (Organism)
|
|
3
|
-
* @description Vocab-driven status badge — resolves a raw value against a
|
|
4
|
-
* status map (label + tone), falling back to a neutral badge with the
|
|
5
|
-
* raw value as its label.
|
|
6
|
-
*/
|
|
7
1
|
|
|
8
2
|
import type { ReactNode } from 'react';
|
|
9
3
|
import { Badge } from '../atoms/Badge';
|
|
@@ -17,11 +11,6 @@ export interface StatusEntry {
|
|
|
17
11
|
|
|
18
12
|
export type StatusVocab = Record<string, StatusEntry>;
|
|
19
13
|
|
|
20
|
-
/**
|
|
21
|
-
* Status vocab fabric — build a vocab from a domain label map (raw value →
|
|
22
|
-
* display label) plus an optional tone table (raw value → badge tone).
|
|
23
|
-
* Entries without a tone render neutral.
|
|
24
|
-
*/
|
|
25
14
|
export function statusVocab(
|
|
26
15
|
labels: Record<string, string>,
|
|
27
16
|
tones: Record<string, BadgeVariant> = {},
|
|
@@ -36,7 +25,6 @@ export function statusVocab(
|
|
|
36
25
|
export interface StatusBadgeProps {
|
|
37
26
|
vocab: StatusVocab;
|
|
38
27
|
value: string;
|
|
39
|
-
/** Render text in place of the vocab entry's label (tone still comes from the vocab). */
|
|
40
28
|
label?: ReactNode;
|
|
41
29
|
dot?: boolean;
|
|
42
30
|
mono?: boolean;
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Stepper Component (Organism)
|
|
3
|
-
* @description Horizontal or vertical step indicator with derived status,
|
|
4
|
-
* optional click navigation and per-step override/lock control
|
|
5
|
-
*/
|
|
6
1
|
|
|
7
2
|
import type { ReactNode } from 'react';
|
|
8
3
|
import { Check } from 'lucide-react';
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tabs Component (Organism)
|
|
3
|
-
* @description Tabbed interface
|
|
4
|
-
*/
|
|
5
1
|
|
|
6
2
|
import { useRef, useState, useCallback, type KeyboardEvent, type ReactNode, type HTMLAttributes } from 'react';
|
|
7
3
|
import { cn } from '../../infrastructure/utils';
|
|
@@ -23,7 +19,6 @@ export interface TabsProps extends HTMLAttributes<HTMLDivElement>, BaseProps {
|
|
|
23
19
|
variant?: 'default' | 'pills' | 'underline';
|
|
24
20
|
ariaLabel?: string;
|
|
25
21
|
panelId?: string;
|
|
26
|
-
/** Render only the tab list (e.g. URL-driven tabs whose content lives elsewhere). */
|
|
27
22
|
showPanel?: boolean;
|
|
28
23
|
}
|
|
29
24
|
|
|
@@ -95,7 +90,6 @@ export function Tabs({ tabs, defaultValue, value, onValueChange, variant = 'defa
|
|
|
95
90
|
|
|
96
91
|
return (
|
|
97
92
|
<div className={cn('w-full', className)} {...props}>
|
|
98
|
-
{/* Tab List */}
|
|
99
93
|
<div
|
|
100
94
|
ref={listRef}
|
|
101
95
|
role="tablist"
|
|
@@ -138,7 +132,6 @@ export function Tabs({ tabs, defaultValue, value, onValueChange, variant = 'defa
|
|
|
138
132
|
})}
|
|
139
133
|
</div>
|
|
140
134
|
|
|
141
|
-
{/* Tab Content */}
|
|
142
135
|
{showPanel && (
|
|
143
136
|
<div
|
|
144
137
|
role="tabpanel"
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Timeline Component (Organism)
|
|
3
|
-
* @description Vertical activity timeline: meta line, title, optional body, tone dot
|
|
4
|
-
*/
|
|
5
1
|
|
|
6
2
|
import { forwardRef } from 'react';
|
|
7
3
|
import type { HTMLAttributes, ReactNode } from 'react';
|
|
@@ -11,21 +7,17 @@ import type { BaseProps } from '../../domain/types';
|
|
|
11
7
|
export type TimelineTone = 'primary' | 'success' | 'warning' | 'destructive' | 'info' | 'neutral' | 'violet';
|
|
12
8
|
|
|
13
9
|
export interface TimelineItem {
|
|
14
|
-
/** ISO timestamp rendered as the meta line unless `meta` overrides it. */
|
|
15
10
|
at: string;
|
|
16
11
|
title: ReactNode;
|
|
17
12
|
body?: ReactNode;
|
|
18
13
|
tone?: TimelineTone;
|
|
19
14
|
meta?: ReactNode;
|
|
20
|
-
/** Replaces the tone dot with an icon, tinted by `tone` (or muted when omitted). */
|
|
21
15
|
icon?: ReactNode;
|
|
22
|
-
/** Replaces the tone dot with an avatar (e.g. the acting user); takes precedence over `icon`. */
|
|
23
16
|
avatar?: ReactNode;
|
|
24
17
|
}
|
|
25
18
|
|
|
26
19
|
export interface TimelineProps extends HTMLAttributes<HTMLOListElement>, BaseProps {
|
|
27
20
|
items: TimelineItem[];
|
|
28
|
-
/** Render newest first (default) instead of the given order. */
|
|
29
21
|
newestFirst?: boolean;
|
|
30
22
|
}
|
|
31
23
|
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Toaster Component (Organism)
|
|
3
|
-
* @description Toast notification system. ToastProvider wraps the app root
|
|
4
|
-
* ONCE and renders the viewport (bottom-right stack, max 4, auto-dismiss
|
|
5
|
-
* 4.2 s); pages fire toasts via useToast()({ kind, title, description }).
|
|
6
|
-
*/
|
|
7
1
|
|
|
8
2
|
import { createContext, useCallback, useContext, useMemo, useRef, useState } from 'react';
|
|
9
3
|
import type { ReactNode } from 'react';
|
|
@@ -24,10 +18,8 @@ export interface ToastShorthandOptions {
|
|
|
24
18
|
}
|
|
25
19
|
|
|
26
20
|
interface ToastApi {
|
|
27
|
-
/** Fire a toast — after every mutating action is the fleet idiom. */
|
|
28
21
|
toast: {
|
|
29
22
|
(t: ToastOptions): void;
|
|
30
|
-
/** Shorthand call: toast('Saved', { tone: 'success', message: '…' }). */
|
|
31
23
|
(title: string, options?: ToastShorthandOptions): void;
|
|
32
24
|
};
|
|
33
25
|
}
|
|
@@ -38,7 +30,6 @@ interface ToastEntry extends ToastOptions {
|
|
|
38
30
|
|
|
39
31
|
const ToastContext = createContext<ToastApi>({ toast: () => {} });
|
|
40
32
|
|
|
41
|
-
/** Consume from any page below the provider: const { toast } = useToast(); */
|
|
42
33
|
export function useToast(): ToastApi {
|
|
43
34
|
return useContext(ToastContext);
|
|
44
35
|
}
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Organisms Export
|
|
3
|
-
* @description Organism components - complex UI combinations
|
|
4
|
-
* Subpath: @umituz/web-design-system/organisms
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
1
|
export { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from './Card';
|
|
8
2
|
export type { CardProps, CardHeaderProps } from './Card';
|
|
9
3
|
|
|
@@ -18,7 +12,7 @@ export {
|
|
|
18
12
|
TableRow,
|
|
19
13
|
TableHead,
|
|
20
14
|
TableCell,
|
|
21
|
-
TableCaption
|
|
15
|
+
TableCaption,
|
|
22
16
|
} from './Table';
|
|
23
17
|
export type { TableProps } from './Table';
|
|
24
18
|
|
|
@@ -41,10 +35,10 @@ export {
|
|
|
41
35
|
} from './Dialog';
|
|
42
36
|
|
|
43
37
|
export { CommandPalette } from './CommandPalette';
|
|
38
|
+
export type { CommandPaletteProps, CommandGroup, CommandItem } from './CommandPalette';
|
|
44
39
|
|
|
45
40
|
export { ErrorBoundary } from './ErrorBoundary';
|
|
46
41
|
export type { ErrorBoundaryProps } from './ErrorBoundary';
|
|
47
|
-
export type { CommandPaletteProps, CommandGroup, CommandItem } from './CommandPalette';
|
|
48
42
|
|
|
49
43
|
export { Breadcrumbs } from './Breadcrumb';
|
|
50
44
|
export type { BreadcrumbsProps, BreadcrumbItem } from './Breadcrumb';
|
|
@@ -117,7 +111,7 @@ export {
|
|
|
117
111
|
export { ToggleGroup, ToggleGroupItem } from './ToggleGroup';
|
|
118
112
|
|
|
119
113
|
export { ToastProvider, useToast } from './Toaster';
|
|
120
|
-
export type { ToastKind, ToastOptions } from './Toaster';
|
|
114
|
+
export type { ToastKind, ToastOptions, ToastShorthandOptions } from './Toaster';
|
|
121
115
|
|
|
122
116
|
export { KeyValueList } from './KeyValueList';
|
|
123
117
|
export type { KeyValueListProps, KeyValueItem } from './KeyValueList';
|
|
@@ -154,8 +148,6 @@ export type { PhotoGalleryProps, PhotoTile } from './PhotoGallery';
|
|
|
154
148
|
export { Lightbox } from './Lightbox';
|
|
155
149
|
export type { LightboxProps } from './Lightbox';
|
|
156
150
|
|
|
157
|
-
export type { ToastShorthandOptions } from './Toaster';
|
|
158
|
-
|
|
159
151
|
export { Timeline } from './Timeline';
|
|
160
152
|
export type { TimelineProps, TimelineItem, TimelineTone } from './Timeline';
|
|
161
153
|
|
|
@@ -186,3 +178,10 @@ export type { PlanPickerProps, PlanPickerPlan, PlanPickerCycle } from './PlanPic
|
|
|
186
178
|
|
|
187
179
|
export { CoverArt } from './CoverArt';
|
|
188
180
|
export type { CoverArtProps } from './CoverArt';
|
|
181
|
+
|
|
182
|
+
// New Productivity Organisms
|
|
183
|
+
export { StatsGrid } from './StatsGrid';
|
|
184
|
+
export type { StatsGridProps, StatItem } from './StatsGrid';
|
|
185
|
+
|
|
186
|
+
export { DescriptionList } from './DescriptionList';
|
|
187
|
+
export type { DescriptionListProps, DescriptionItem } from './DescriptionList';
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Breadcrumbs, type BreadcrumbItem } from '../organisms/Breadcrumb';
|
|
3
|
+
import { cn } from '../../infrastructure/utils';
|
|
4
|
+
|
|
5
|
+
export interface CrudPageTemplateProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'title'> {
|
|
6
|
+
title: React.ReactNode;
|
|
7
|
+
description?: React.ReactNode;
|
|
8
|
+
breadcrumbItems?: BreadcrumbItem[];
|
|
9
|
+
actions?: React.ReactNode;
|
|
10
|
+
stats?: React.ReactNode;
|
|
11
|
+
toolbar?: React.ReactNode;
|
|
12
|
+
children: React.ReactNode;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const CrudPageTemplate = React.forwardRef<HTMLDivElement, CrudPageTemplateProps>(
|
|
16
|
+
(
|
|
17
|
+
{
|
|
18
|
+
title,
|
|
19
|
+
description,
|
|
20
|
+
breadcrumbItems,
|
|
21
|
+
actions,
|
|
22
|
+
stats,
|
|
23
|
+
toolbar,
|
|
24
|
+
children,
|
|
25
|
+
className,
|
|
26
|
+
...props
|
|
27
|
+
},
|
|
28
|
+
ref
|
|
29
|
+
) => {
|
|
30
|
+
return (
|
|
31
|
+
<div
|
|
32
|
+
ref={ref}
|
|
33
|
+
className={cn('w-full flex flex-col gap-6 p-4 sm:p-6 lg:p-8', className)}
|
|
34
|
+
{...props}
|
|
35
|
+
>
|
|
36
|
+
{/* Breadcrumbs */}
|
|
37
|
+
{breadcrumbItems && breadcrumbItems.length > 0 && (
|
|
38
|
+
<div>
|
|
39
|
+
<Breadcrumbs items={breadcrumbItems} />
|
|
40
|
+
</div>
|
|
41
|
+
)}
|
|
42
|
+
|
|
43
|
+
{/* Page Header */}
|
|
44
|
+
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
|
|
45
|
+
<div>
|
|
46
|
+
<h1 className="text-2xl sm:text-3xl font-bold tracking-tight text-foreground">
|
|
47
|
+
{title}
|
|
48
|
+
</h1>
|
|
49
|
+
{description && (
|
|
50
|
+
<p className="text-sm text-muted-foreground mt-1">{description}</p>
|
|
51
|
+
)}
|
|
52
|
+
</div>
|
|
53
|
+
{actions && <div className="flex items-center gap-2 shrink-0">{actions}</div>}
|
|
54
|
+
</div>
|
|
55
|
+
|
|
56
|
+
{/* Optional Stats Grid */}
|
|
57
|
+
{stats && <div>{stats}</div>}
|
|
58
|
+
|
|
59
|
+
{/* Optional Search / Filter Toolbar */}
|
|
60
|
+
{toolbar && <div>{toolbar}</div>}
|
|
61
|
+
|
|
62
|
+
{/* Main Content (Table / List / Cards) */}
|
|
63
|
+
<div className="w-full">{children}</div>
|
|
64
|
+
</div>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
CrudPageTemplate.displayName = 'CrudPageTemplate';
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ResponsiveContainer Template Component
|
|
3
|
-
* @description Responsive wrapper with mobile/desktop optimizations
|
|
4
|
-
*/
|
|
5
1
|
|
|
6
2
|
import { forwardRef, type HTMLAttributes, type ReactNode } from 'react';
|
|
7
3
|
import { cn } from '../../infrastructure/utils';
|
|
@@ -14,58 +10,22 @@ export interface ResponsiveContainerProps
|
|
|
14
10
|
extends Omit<HTMLAttributes<HTMLDivElement>, 'children'>,
|
|
15
11
|
BaseProps {
|
|
16
12
|
children?: ReactNode;
|
|
17
|
-
/**
|
|
18
|
-
* Maximum width on mobile devices
|
|
19
|
-
* @default 'full'
|
|
20
|
-
*/
|
|
21
13
|
mobileMaxWidth?: ResponsiveSize;
|
|
22
14
|
|
|
23
|
-
/**
|
|
24
|
-
* Maximum width on tablet devices
|
|
25
|
-
* @default 'lg'
|
|
26
|
-
*/
|
|
27
15
|
tabletMaxWidth?: ResponsiveSize;
|
|
28
16
|
|
|
29
|
-
/**
|
|
30
|
-
* Maximum width on desktop devices
|
|
31
|
-
* @default 'xl'
|
|
32
|
-
*/
|
|
33
17
|
desktopMaxWidth?: ResponsiveSize;
|
|
34
18
|
|
|
35
|
-
/**
|
|
36
|
-
* Padding on mobile devices
|
|
37
|
-
* @default true
|
|
38
|
-
*/
|
|
39
19
|
mobilePadding?: boolean;
|
|
40
20
|
|
|
41
|
-
/**
|
|
42
|
-
* Padding on tablet devices
|
|
43
|
-
* @default true
|
|
44
|
-
*/
|
|
45
21
|
tabletPadding?: boolean;
|
|
46
22
|
|
|
47
|
-
/**
|
|
48
|
-
* Padding on desktop devices
|
|
49
|
-
* @default true
|
|
50
|
-
*/
|
|
51
23
|
desktopPadding?: boolean;
|
|
52
24
|
|
|
53
|
-
/**
|
|
54
|
-
* Center content horizontally
|
|
55
|
-
* @default true
|
|
56
|
-
*/
|
|
57
25
|
centered?: boolean;
|
|
58
26
|
|
|
59
|
-
/**
|
|
60
|
-
* Background gradient
|
|
61
|
-
* @default false
|
|
62
|
-
*/
|
|
63
27
|
gradient?: boolean;
|
|
64
28
|
|
|
65
|
-
/**
|
|
66
|
-
* Minimum height
|
|
67
|
-
* @default 'auto'
|
|
68
|
-
*/
|
|
69
29
|
minHeight?: 'auto' | 'screen' | 'full';
|
|
70
30
|
}
|
|
71
31
|
|
|
@@ -100,7 +60,6 @@ export const ResponsiveContainer = forwardRef<
|
|
|
100
60
|
) => {
|
|
101
61
|
const { currentBreakpoint: breakpoint } = useBreakpoint();
|
|
102
62
|
|
|
103
|
-
// Determine current max width based on breakpoint
|
|
104
63
|
const getCurrentMaxWidth = (): string => {
|
|
105
64
|
if (!breakpoint) return maxWidthClasses[mobileMaxWidth];
|
|
106
65
|
|
|
@@ -113,7 +72,6 @@ export const ResponsiveContainer = forwardRef<
|
|
|
113
72
|
return maxWidthClasses[desktopMaxWidth];
|
|
114
73
|
};
|
|
115
74
|
|
|
116
|
-
// Determine current padding based on breakpoint
|
|
117
75
|
const getCurrentPadding = (): string => {
|
|
118
76
|
if (!breakpoint) return mobilePadding ? 'px-4' : '';
|
|
119
77
|
|
|
@@ -126,7 +84,6 @@ export const ResponsiveContainer = forwardRef<
|
|
|
126
84
|
return desktopPadding ? 'px-8' : '';
|
|
127
85
|
};
|
|
128
86
|
|
|
129
|
-
// Determine current py padding based on breakpoint
|
|
130
87
|
const getCurrentPyPadding = (): string => {
|
|
131
88
|
if (!breakpoint) return 'py-8';
|
|
132
89
|
|