@axzydev/axzy_ui_system 1.2.7 → 1.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +576 -398
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +1463 -86
- package/dist/index.d.ts +1463 -86
- package/dist/index.js +597 -417
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/App.tsx +19 -54
- package/src/components/alert/alert.doc.mdx +48 -0
- package/src/components/alert/alert.props.ts +7 -0
- package/src/components/alert/alert.tsx +8 -0
- package/src/components/avatar/avatar.doc.mdx +48 -0
- package/src/components/avatar/avatar.props.ts +8 -0
- package/src/components/avatar/avatar.tsx +25 -5
- package/src/components/badget/badget.doc.mdx +46 -0
- package/src/components/badget/badget.props.ts +6 -0
- package/src/components/badget/badget.tsx +11 -0
- package/src/components/breadcrumbs/breadcrumbs.doc.mdx +57 -0
- package/src/components/breadcrumbs/breadcrumbs.props.ts +6 -0
- package/src/components/breadcrumbs/breadcrumbs.tsx +12 -0
- package/src/components/button/button.doc.mdx +59 -0
- package/src/components/button/button.props.ts +12 -0
- package/src/components/button/button.tsx +11 -0
- package/src/components/calendar/calendar.doc.mdx +75 -0
- package/src/components/calendar/calendar.props.ts +27 -7
- package/src/components/calendar/calendar.tsx +13 -0
- package/src/components/card/card.doc.mdx +54 -0
- package/src/components/card/card.props.ts +11 -0
- package/src/components/card/card.tsx +13 -0
- package/src/components/checkbox/checkbox.doc.mdx +54 -0
- package/src/components/checkbox/checkbox.props.ts +7 -0
- package/src/components/checkbox/checkbox.tsx +9 -0
- package/src/components/confirm-dialog/confirm-dialog.doc.mdx +60 -0
- package/src/components/confirm-dialog/confirm-dialog.props.ts +9 -0
- package/src/components/confirm-dialog/confirm-dialog.tsx +19 -0
- package/src/components/data-table/ITDataTable.doc.mdx +59 -0
- package/src/components/data-table/dataTable.props.ts +15 -0
- package/src/components/data-table/dataTable.tsx +178 -73
- package/src/components/date-picker/date-picker.doc.mdx +65 -0
- package/src/components/date-picker/date-picker.props.ts +17 -0
- package/src/components/date-picker/datePicker.tsx +31 -1
- package/src/components/dialog/dialog.doc.mdx +54 -0
- package/src/components/dialog/dialog.props.ts +7 -0
- package/src/components/dialog/dialog.tsx +26 -0
- package/src/components/divider/divider.doc.mdx +42 -0
- package/src/components/divider/divider.props.ts +5 -0
- package/src/components/divider/divider.tsx +16 -0
- package/src/components/drawer/drawer.doc.mdx +59 -0
- package/src/components/drawer/drawer.props.ts +9 -0
- package/src/components/drawer/drawer.tsx +20 -0
- package/src/components/dropfile/dropfile.doc.mdx +59 -0
- package/src/components/dropfile/dropfile.props.ts +41 -0
- package/src/components/dropfile/dropfile.tsx +21 -33
- package/src/components/empty-state/empty-state.doc.mdx +50 -0
- package/src/components/empty-state/empty-state.props.ts +5 -0
- package/src/components/empty-state/empty-state.tsx +16 -0
- package/src/components/flex/flex.doc.mdx +59 -0
- package/src/components/flex/flex.props.ts +13 -0
- package/src/components/flex/flex.tsx +15 -0
- package/src/components/form-builder/fieldRenderer.tsx +52 -2
- package/src/components/form-builder/formBuilder.doc.mdx +124 -0
- package/src/components/form-builder/formBuilder.props.ts +12 -2
- package/src/components/form-builder/formBuilder.tsx +31 -0
- package/src/components/form-header/form-header.doc.mdx +38 -0
- package/src/components/form-header/form-header.props.ts +3 -0
- package/src/components/form-header/form-header.stories.tsx +53 -0
- package/src/components/form-header/form-header.tsx +11 -0
- package/src/components/grid/grid.doc.mdx +54 -0
- package/src/components/grid/grid.props.ts +13 -0
- package/src/components/grid/grid.tsx +19 -0
- package/src/components/image/image.doc.mdx +44 -0
- package/src/components/image/image.props.ts +5 -0
- package/src/components/image/image.stories.tsx +49 -0
- package/src/components/image/image.tsx +19 -0
- package/src/components/input/input.doc.mdx +70 -0
- package/src/components/input/input.props.ts +34 -2
- package/src/components/input/input.tsx +29 -0
- package/src/components/layout/layout.doc.mdx +51 -0
- package/src/components/layout/layout.props.ts +5 -0
- package/src/components/layout/layout.tsx +29 -2
- package/src/components/loader/loader.doc.mdx +43 -0
- package/src/components/loader/loader.props.ts +4 -0
- package/src/components/loader/loader.tsx +17 -0
- package/src/components/navbar/navbar.doc.mdx +77 -0
- package/src/components/navbar/navbar.props.ts +37 -1
- package/src/components/navbar/navbar.stories.tsx +84 -0
- package/src/components/navbar/navbar.tsx +27 -0
- package/src/components/page/page.doc.mdx +80 -0
- package/src/components/page/page.props.ts +21 -0
- package/src/components/page/page.tsx +18 -0
- package/src/components/page-header/page-header.doc.mdx +54 -0
- package/src/components/page-header/page-header.props.ts +9 -0
- package/src/components/page-header/page-header.tsx +15 -0
- package/src/components/pagination/pagination.doc.mdx +62 -0
- package/src/components/pagination/pagination.props.ts +11 -32
- package/src/components/pagination/pagination.tsx +17 -0
- package/src/components/popover/popover.doc.mdx +53 -0
- package/src/components/popover/popover.props.ts +8 -0
- package/src/components/popover/popover.tsx +13 -0
- package/src/components/progress/progress.doc.mdx +48 -0
- package/src/components/progress/progress.props.ts +8 -0
- package/src/components/progress/progress.tsx +9 -0
- package/src/components/radio/radio.doc.mdx +62 -0
- package/src/components/radio/radio.props.ts +11 -0
- package/src/components/radio/radio.tsx +18 -0
- package/src/components/search-select/search-select.doc.mdx +72 -0
- package/src/components/search-select/search-select.props.ts +23 -18
- package/src/components/search-select/search-select.tsx +27 -2
- package/src/components/searchTable/searchTable.doc.mdx +79 -0
- package/src/components/searchTable/searchTable.props.ts +42 -3
- package/src/components/searchTable/searchTable.stories.tsx +74 -0
- package/src/components/searchTable/searchTable.tsx +23 -0
- package/src/components/segmented-control/segmented-control.doc.mdx +60 -0
- package/src/components/segmented-control/segmented-control.props.ts +12 -0
- package/src/components/segmented-control/segmented-control.tsx +15 -0
- package/src/components/select/select.doc.mdx +75 -0
- package/src/components/select/select.props.ts +22 -0
- package/src/components/select/select.tsx +2 -5
- package/src/components/sidebar/sidebar.doc.mdx +86 -0
- package/src/components/sidebar/sidebar.props.ts +22 -0
- package/src/components/sidebar/sidebar.tsx +22 -0
- package/src/components/skeleton/skeleton.doc.mdx +43 -0
- package/src/components/skeleton/skeleton.props.ts +8 -0
- package/src/components/skeleton/skeleton.tsx +10 -0
- package/src/components/slide/slide.doc.mdx +46 -0
- package/src/components/slide/slide.props.ts +11 -24
- package/src/components/slide/slide.tsx +10 -1
- package/src/components/slider/slider.doc.mdx +49 -0
- package/src/components/slider/slider.props.ts +9 -0
- package/src/components/slider/slider.tsx +15 -0
- package/src/components/stack/stack.doc.mdx +126 -0
- package/src/components/stack/stack.props.ts +18 -0
- package/src/components/stack/stack.stories.tsx +221 -16
- package/src/components/stack/stack.tsx +21 -0
- package/src/components/stat-card/stat-card.doc.mdx +48 -0
- package/src/components/stat-card/stat-card.props.ts +9 -0
- package/src/components/stat-card/stat-card.tsx +10 -0
- package/src/components/stepper/stepper.doc.mdx +54 -0
- package/src/components/stepper/stepper.props.ts +11 -1
- package/src/components/stepper/stepper.tsx +15 -0
- package/src/components/table/table.doc.mdx +58 -0
- package/src/components/table/table.props.ts +17 -0
- package/src/components/table/table.tsx +199 -84
- package/src/components/tabs/tabs.doc.mdx +52 -0
- package/src/components/tabs/tabs.props.ts +11 -0
- package/src/components/tabs/tabs.tsx +14 -0
- package/src/components/text/text.doc.mdx +41 -0
- package/src/components/text/text.props.ts +5 -0
- package/src/components/text/text.stories.tsx +67 -0
- package/src/components/text/text.tsx +10 -0
- package/src/components/textarea/textarea.doc.mdx +64 -0
- package/src/components/textarea/textarea.props.ts +11 -0
- package/src/components/textarea/textarea.tsx +16 -0
- package/src/components/theme-provider/themeProvider.doc.mdx +75 -0
- package/src/components/theme-provider/themeProvider.props.ts +3 -0
- package/src/components/theme-provider/themeProvider.stories.tsx +59 -0
- package/src/components/theme-provider/themeProvider.tsx +14 -0
- package/src/components/time-picker/timePicker.doc.mdx +68 -0
- package/src/components/time-picker/timePicker.props.ts +14 -0
- package/src/components/time-picker/timePicker.tsx +22 -1
- package/src/components/toast/toast.doc.mdx +50 -0
- package/src/components/toast/toast.props.ts +5 -0
- package/src/components/toast/toast.tsx +21 -0
- package/src/components/tooltip/tooltip.doc.mdx +47 -0
- package/src/components/tooltip/tooltip.props.ts +6 -0
- package/src/components/tooltip/tooltip.tsx +19 -0
- package/src/components/topbar/topbar.doc.mdx +69 -0
- package/src/components/topbar/topbar.props.ts +15 -0
- package/src/components/topbar/topbar.tsx +38 -0
- package/src/components/triple-filter/tripleFilter.doc.mdx +62 -0
- package/src/components/triple-filter/tripleFilter.props.ts +7 -0
- package/src/components/triple-filter/tripleFilter.tsx +32 -0
- package/src/index.css +2 -0
- package/src/showcases/DataShowcases.tsx +529 -45
- package/src/showcases/FormShowcases.tsx +399 -29
- package/src/showcases/HomeShowcase.tsx +252 -272
- package/src/showcases/LayoutPrimitivesShowcases.tsx +1224 -248
- package/src/showcases/PageShowcases.tsx +688 -391
- package/src/showcases/ShowcaseLayout.tsx +237 -73
- package/src/showcases/StructureShowcases.tsx +846 -73
- package/src/types/table.types.ts +1 -1
- package/src/utils/styles.ts +2 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React, { useState, ReactNode } from "react";
|
|
2
|
+
import { FaCode, FaTimes } from "react-icons/fa";
|
|
2
3
|
import ITStack from "../components/stack/stack";
|
|
3
4
|
import ITFlex from "../components/flex/flex";
|
|
4
5
|
import ITGrid from "../components/grid/grid";
|
|
@@ -9,6 +10,9 @@ import ITAvatar from "../components/avatar/avatar";
|
|
|
9
10
|
import ITSlider from "../components/slider/slider";
|
|
10
11
|
import ITSegmentedControl from "../components/segmented-control/segmented-control";
|
|
11
12
|
import ITSlideToggle from "../components/slide/slide";
|
|
13
|
+
import ITSelect from "../components/select/select";
|
|
14
|
+
import ITInput from "../components/input/input";
|
|
15
|
+
import ITText from "../components/text/text";
|
|
12
16
|
import { ShowcaseLayout, CodeViewer } from "./ShowcaseLayout";
|
|
13
17
|
|
|
14
18
|
const DemoBox = ({ children, className = "" }: { children: ReactNode; className?: string }) => (
|
|
@@ -28,84 +32,628 @@ const DemoCard = ({ children, className = "" }: { children: ReactNode; className
|
|
|
28
32
|
// ─────────────────────────────────────────
|
|
29
33
|
// 1. ITStack Showcase
|
|
30
34
|
// ─────────────────────────────────────────
|
|
35
|
+
|
|
36
|
+
const alignOptions: { value: string; label: string }[] = [
|
|
37
|
+
{ value: "start", label: "Start" },
|
|
38
|
+
{ value: "center", label: "Center" },
|
|
39
|
+
{ value: "end", label: "End" },
|
|
40
|
+
{ value: "stretch", label: "Stretch" },
|
|
41
|
+
{ value: "baseline", label: "Baseline" },
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
const justifyOptions: { value: string; label: string }[] = [
|
|
45
|
+
{ value: "start", label: "Start" },
|
|
46
|
+
{ value: "center", label: "Center" },
|
|
47
|
+
{ value: "end", label: "End" },
|
|
48
|
+
{ value: "between", label: "Between" },
|
|
49
|
+
{ value: "around", label: "Around" },
|
|
50
|
+
{ value: "evenly", label: "Evenly" },
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
// Cleaner demo box using inline gradient + soft shadow + numbered
|
|
54
|
+
const StackDemoItem = ({ index, size = "md" }: { index: number; size?: "sm" | "md" | "lg" }) => {
|
|
55
|
+
const sizeClasses = {
|
|
56
|
+
sm: "min-w-[48px] h-10 px-3 text-xs",
|
|
57
|
+
md: "min-w-[64px] h-14 px-4 text-sm",
|
|
58
|
+
lg: "min-w-[80px] h-20 px-5 text-base",
|
|
59
|
+
};
|
|
60
|
+
return (
|
|
61
|
+
<div
|
|
62
|
+
className={`${sizeClasses[size]} rounded-xl text-white font-semibold flex items-center justify-center`}
|
|
63
|
+
style={{
|
|
64
|
+
background: 'linear-gradient(135deg, var(--color-primary-500, #3b82f6) 0%, var(--color-primary-700, #1d4ed8) 100%)',
|
|
65
|
+
boxShadow: '0 4px 14px 0 rgba(59, 130, 246, 0.3)',
|
|
66
|
+
}}
|
|
67
|
+
>
|
|
68
|
+
Item {index}
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// Soft chip-like demo for tag-cloud style
|
|
74
|
+
const StackChip = ({ label, color = "primary" }: { label: string; color?: "primary" | "success" | "warning" | "info" }) => {
|
|
75
|
+
const palettes = {
|
|
76
|
+
primary: "bg-primary-50 text-primary-700 border-primary-200 dark:bg-primary-900/30 dark:text-primary-300 dark:border-primary-800",
|
|
77
|
+
success: "bg-emerald-50 text-emerald-700 border-emerald-200 dark:bg-emerald-900/30 dark:text-emerald-300 dark:border-emerald-800",
|
|
78
|
+
warning: "bg-amber-50 text-amber-700 border-amber-200 dark:bg-amber-900/30 dark:text-amber-300 dark:border-amber-800",
|
|
79
|
+
info: "bg-sky-50 text-sky-700 border-sky-200 dark:bg-sky-900/30 dark:text-sky-300 dark:border-sky-800",
|
|
80
|
+
};
|
|
81
|
+
return (
|
|
82
|
+
<span className={`px-3 py-1.5 rounded-lg border text-xs font-medium ${palettes[color]}`}>
|
|
83
|
+
{label}
|
|
84
|
+
</span>
|
|
85
|
+
);
|
|
86
|
+
};
|
|
87
|
+
|
|
31
88
|
export const StackShowcase = () => {
|
|
32
89
|
const [direction, setDirection] = useState<"row" | "column">("column");
|
|
33
90
|
const [spacing, setSpacing] = useState(3);
|
|
34
91
|
const [withDivider, setWithDivider] = useState(false);
|
|
92
|
+
const [align, setAlign] = useState<string>("start");
|
|
93
|
+
const [justify, setJustify] = useState<string>("start");
|
|
94
|
+
const [wrapMode, setWrapMode] = useState<string>("nowrap");
|
|
35
95
|
|
|
36
|
-
const
|
|
96
|
+
const PATTERN_CODES = {
|
|
97
|
+
pageHeader: `<ITStack
|
|
98
|
+
direction="row"
|
|
99
|
+
spacing={3}
|
|
100
|
+
justifyContent="between"
|
|
101
|
+
alignItems="center"
|
|
102
|
+
>
|
|
103
|
+
<div>
|
|
104
|
+
<p className="text-sm font-bold">Patient Records</p>
|
|
105
|
+
<p className="text-xs text-slate-500">128 active records</p>
|
|
106
|
+
</div>
|
|
107
|
+
<ITStack direction="row" spacing={2}>
|
|
108
|
+
<button className="px-3 py-1.5 rounded-lg border ...">
|
|
109
|
+
Export
|
|
110
|
+
</button>
|
|
111
|
+
<button className="px-3 py-1.5 rounded-lg bg-primary-600 ...">
|
|
112
|
+
+ New Record
|
|
113
|
+
</button>
|
|
114
|
+
</ITStack>
|
|
115
|
+
</ITStack>`,
|
|
116
|
+
tagCloud: `<ITStack
|
|
117
|
+
direction="row"
|
|
118
|
+
spacing={2}
|
|
119
|
+
flexWrap="wrap"
|
|
120
|
+
>
|
|
121
|
+
{tags.map((tag) => (
|
|
122
|
+
<span
|
|
123
|
+
key={tag}
|
|
124
|
+
className="px-3 py-1.5 rounded-lg border ..."
|
|
125
|
+
>
|
|
126
|
+
{tag}
|
|
127
|
+
</span>
|
|
128
|
+
))}
|
|
129
|
+
</ITStack>`,
|
|
130
|
+
sectionList: `<ITStack
|
|
131
|
+
spacing={0}
|
|
132
|
+
divider={
|
|
133
|
+
<div className="h-px bg-slate-200 dark:bg-slate-700 mx-3" />
|
|
134
|
+
}
|
|
135
|
+
>
|
|
136
|
+
{users.map((user) => (
|
|
137
|
+
<div
|
|
138
|
+
key={user.email}
|
|
139
|
+
className="flex items-center gap-3 py-3 px-4 ..."
|
|
140
|
+
>
|
|
141
|
+
<div className="w-9 h-9 rounded-full ...">{user.initial}</div>
|
|
142
|
+
<div className="flex-1 min-w-0">
|
|
143
|
+
<p className="text-sm font-semibold ...">{user.name}</p>
|
|
144
|
+
<p className="text-xs ...">{user.email}</p>
|
|
145
|
+
</div>
|
|
146
|
+
<span className="...">{user.status}</span>
|
|
147
|
+
</div>
|
|
148
|
+
))}
|
|
149
|
+
</ITStack>`,
|
|
150
|
+
notification: `<ITStack
|
|
151
|
+
direction="row"
|
|
152
|
+
spacing={3}
|
|
153
|
+
alignItems="center"
|
|
154
|
+
className="p-4"
|
|
155
|
+
>
|
|
156
|
+
<div className="w-9 h-9 rounded-full bg-emerald-500 ... shrink-0">
|
|
157
|
+
✓
|
|
158
|
+
</div>
|
|
159
|
+
<div className="flex-1 min-w-0">
|
|
160
|
+
<p className="text-sm font-semibold ...">Deployment successful</p>
|
|
161
|
+
<p className="text-xs ...">Your changes are live in production.</p>
|
|
162
|
+
</div>
|
|
163
|
+
<button className="w-7 h-7 ... shrink-0">×</button>
|
|
164
|
+
</ITStack>`,
|
|
165
|
+
statsRow: `<ITStack direction="row" spacing={3}>
|
|
166
|
+
{stats.map((stat) => (
|
|
167
|
+
<div
|
|
168
|
+
key={stat.label}
|
|
169
|
+
className="flex-1 min-w-0 rounded-xl p-3 ..."
|
|
170
|
+
>
|
|
171
|
+
<p className="text-[10px] uppercase ...">{stat.label}</p>
|
|
172
|
+
<p className="text-xl font-bold font-mono">{stat.value}</p>
|
|
173
|
+
<p className="text-[10px] ...">{stat.delta}</p>
|
|
174
|
+
</div>
|
|
175
|
+
))}
|
|
176
|
+
</ITStack>`,
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const buildCode = () => {
|
|
180
|
+
const props = [`direction="${direction}"`, `spacing={${spacing}}`];
|
|
181
|
+
if (align !== "start") props.push(`alignItems="${align}"`);
|
|
182
|
+
if (justify !== "start") props.push(`justifyContent="${justify}"`);
|
|
183
|
+
if (wrapMode !== "nowrap") props.push(`flexWrap="${wrapMode}"`);
|
|
184
|
+
if (withDivider) props.push(`divider={<hr className="border-slate-200 dark:border-slate-700" />}`);
|
|
185
|
+
return `<ITStack\n ${props.join("\n ")}\n>\n <Card>Item 1</Card>\n <Card>Item 2</Card>\n <Card>Item 3</Card>\n</ITStack>`;
|
|
186
|
+
};
|
|
37
187
|
|
|
38
188
|
return (
|
|
39
189
|
<ShowcaseLayout
|
|
40
190
|
title="ITStack"
|
|
41
|
-
description="Layout basado en flexbox con dirección
|
|
42
|
-
code={
|
|
191
|
+
description="Layout basado en flexbox con dirección, spacing uniforme, alineación y distribución. Ideal para secciones verticales, toolbars horizontales, listas de items y form rows."
|
|
192
|
+
code={buildCode()}
|
|
193
|
+
doc={{
|
|
194
|
+
summary:
|
|
195
|
+
"ITStack is a simplified flexbox layout primitive that controls direction, spacing, alignment, and justification in a single component. Supports optional dividers between children and renders as any HTML element.",
|
|
196
|
+
description:
|
|
197
|
+
"Use ITStack everywhere you need consistent vertical or horizontal spacing. The gap is measured in 0.25rem units (Tailwind spacing scale). Combine with align and justify for centering, space-between distribution, or baseline alignment. Wrap mode enables responsive wrapping for tag clouds, filter chips, or toolbar buttons.",
|
|
198
|
+
examples: [
|
|
199
|
+
"<ITStack direction=\"row\" spacing={2} alignItems=\"center\">\n <ITButton>Cancel</ITButton>\n <ITButton color=\"primary\">Save</ITButton>\n</ITStack>",
|
|
200
|
+
"<ITStack spacing={4} divider={<hr />}>\n <div>Section A</div>\n <div>Section B</div>\n</ITStack>",
|
|
201
|
+
"<ITStack direction=\"row\" spacing={1} flexWrap=\"wrap\">\n {tags.map(t => <ITBadget key={t} label={t} />)}\n</ITStack>",
|
|
202
|
+
"<ITStack direction=\"row\" spacing={4} justifyContent=\"between\" alignItems=\"center\" className=\"w-full\">\n <h2>Page Title</h2>\n <ITButton label=\"Action\" />\n</ITStack>",
|
|
203
|
+
],
|
|
204
|
+
props: [
|
|
205
|
+
{ name: "children", type: "ReactNode", description: "Stack children elements." },
|
|
206
|
+
{ name: "direction", type: '"row" | "column" | "row-reverse" | "column-reverse"', default: '"column"', description: "Flex direction." },
|
|
207
|
+
{ name: "spacing", type: "number", default: "0", description: "Gap between children in 0.25rem units (0–12)." },
|
|
208
|
+
{ name: "alignItems", type: '"start" | "end" | "center" | "stretch" | "baseline"', description: "Cross-axis (vertical in row, horizontal in column) alignment." },
|
|
209
|
+
{ name: "justifyContent", type: '"start" | "end" | "center" | "between" | "around" | "evenly"', description: "Main-axis distribution of children." },
|
|
210
|
+
{ name: "flexWrap", type: '"nowrap" | "wrap" | "wrap-reverse"', default: '"nowrap"', description: "Whether children wrap to the next line." },
|
|
211
|
+
{ name: "divider", type: "ReactNode", description: "Optional element rendered between each pair of children." },
|
|
212
|
+
{ name: "className", type: "string", description: "Additional CSS classes on the container." },
|
|
213
|
+
{ name: "style", type: "CSSProperties", description: "Inline styles on the container." },
|
|
214
|
+
{ name: "as", type: "ElementType", default: '"div"', description: "HTML element to render as (e.g. \"section\", \"nav\", \"ul\")." },
|
|
215
|
+
],
|
|
216
|
+
notes: [
|
|
217
|
+
"Spacing is multiplied by 0.25rem internally — spacing={4} equals gap: 1rem.",
|
|
218
|
+
"The container is always display: flex — use direction to switch between vertical and horizontal.",
|
|
219
|
+
"Divider is cloned between children via React.cloneElement — it must be a single valid React element.",
|
|
220
|
+
"Set as=\"ul\" and wrap children in <li> for semantic list layouts.",
|
|
221
|
+
"For complex multi-axis layouts, use ITFlex instead of ITStack.",
|
|
222
|
+
],
|
|
223
|
+
}}
|
|
43
224
|
demo={
|
|
44
|
-
<div className="w-full max-w-
|
|
45
|
-
<
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
225
|
+
<div className="w-full max-w-xl flex flex-col">
|
|
226
|
+
<div className="min-h-[360px]">
|
|
227
|
+
<ITStack
|
|
228
|
+
direction={direction as any}
|
|
229
|
+
spacing={spacing}
|
|
230
|
+
className="w-full"
|
|
231
|
+
alignItems={align as any}
|
|
232
|
+
justifyContent={justify as any}
|
|
233
|
+
flexWrap={wrapMode as any}
|
|
234
|
+
divider={withDivider ? <div className={`${direction === "row" ? "w-px h-8" : "h-px w-full"} bg-slate-200 dark:bg-slate-700 self-stretch`} /> : undefined}
|
|
235
|
+
>
|
|
236
|
+
{[1, 2, 3, 4, 5, 6, 7, 8].map((i) => (
|
|
237
|
+
<div
|
|
238
|
+
key={i}
|
|
239
|
+
className="min-w-[80px] h-8 px-3 rounded-lg text-white text-xs font-semibold flex items-center justify-center shrink-0"
|
|
240
|
+
style={{
|
|
241
|
+
background: 'linear-gradient(135deg, var(--color-primary-500, #3b82f6) 0%, var(--color-primary-700, #1d4ed8) 100%)',
|
|
242
|
+
boxShadow: '0 4px 14px 0 rgba(59, 130, 246, 0.3)',
|
|
243
|
+
}}
|
|
244
|
+
>
|
|
245
|
+
Item {i}
|
|
246
|
+
</div>
|
|
247
|
+
))}
|
|
248
|
+
</ITStack>
|
|
249
|
+
</div>
|
|
250
|
+
|
|
251
|
+
{/* Fixed footer with active-property badges */}
|
|
252
|
+
<div className="sticky bottom-0 mt-4 -mx-6 -mb-6 px-6 py-3 bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-t border-slate-200 dark:border-slate-700 flex items-center flex-wrap gap-1.5 text-[10px] font-mono">
|
|
253
|
+
<span className="text-[9px] uppercase tracking-wider font-bold text-slate-400 dark:text-slate-500 mr-1">Active:</span>
|
|
254
|
+
<span className="px-2 py-0.5 rounded-md bg-slate-900 text-white dark:bg-white dark:text-slate-900 font-semibold">{direction}</span>
|
|
255
|
+
<span className="px-2 py-0.5 rounded-md bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-300">gap:{spacing}</span>
|
|
256
|
+
{align !== "start" && <span className="px-2 py-0.5 rounded-md bg-primary-100 dark:bg-primary-900/30 text-primary-700 dark:text-primary-300">align:{align}</span>}
|
|
257
|
+
{justify !== "start" && <span className="px-2 py-0.5 rounded-md bg-emerald-100 dark:bg-emerald-900/30 text-emerald-700 dark:text-emerald-300">justify:{justify}</span>}
|
|
258
|
+
{wrapMode !== "nowrap" && <span className="px-2 py-0.5 rounded-md bg-amber-100 dark:bg-amber-900/30 text-amber-700 dark:text-amber-300">{wrapMode}</span>}
|
|
259
|
+
{withDivider && <span className="px-2 py-0.5 rounded-md bg-sky-100 dark:bg-sky-900/30 text-sky-700 dark:text-sky-300">divider</span>}
|
|
260
|
+
</div>
|
|
50
261
|
</div>
|
|
51
262
|
}
|
|
52
263
|
controls={
|
|
53
264
|
<>
|
|
54
|
-
<
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
{
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
265
|
+
<div>
|
|
266
|
+
<p className="text-xs font-semibold text-slate-500 dark:text-slate-400 mb-1.5 uppercase tracking-wider">Direction</p>
|
|
267
|
+
<ITSegmentedControl
|
|
268
|
+
options={[
|
|
269
|
+
{ value: "column", label: "Column" },
|
|
270
|
+
{ value: "row", label: "Row" },
|
|
271
|
+
{ value: "row-reverse", label: "Row ↩" },
|
|
272
|
+
{ value: "column-reverse", label: "Column ↩" },
|
|
273
|
+
]}
|
|
274
|
+
value={direction}
|
|
275
|
+
onChange={(v) => setDirection(v as any)}
|
|
276
|
+
/>
|
|
277
|
+
</div>
|
|
278
|
+
<ITSlider label="Spacing (0.25rem units)" value={spacing} onChange={setSpacing} min={0} max={12} />
|
|
279
|
+
<ITSelect
|
|
280
|
+
name="align_items"
|
|
281
|
+
label="Align Items"
|
|
282
|
+
value={align}
|
|
283
|
+
onChange={(e) => setAlign(e.target.value)}
|
|
284
|
+
options={alignOptions}
|
|
61
285
|
/>
|
|
62
|
-
<
|
|
286
|
+
<ITSelect
|
|
287
|
+
name="justify_content"
|
|
288
|
+
label="Justify Content"
|
|
289
|
+
value={justify}
|
|
290
|
+
onChange={(e) => setJustify(e.target.value)}
|
|
291
|
+
options={justifyOptions}
|
|
292
|
+
/>
|
|
293
|
+
<div>
|
|
294
|
+
<p className="text-xs font-semibold text-slate-500 dark:text-slate-400 mb-1.5 uppercase tracking-wider">Flex Wrap</p>
|
|
295
|
+
<ITSegmentedControl
|
|
296
|
+
options={[
|
|
297
|
+
{ value: "nowrap", label: "Nowrap" },
|
|
298
|
+
{ value: "wrap", label: "Wrap" },
|
|
299
|
+
{ value: "wrap-reverse", label: "Reverse" },
|
|
300
|
+
]}
|
|
301
|
+
value={wrapMode}
|
|
302
|
+
onChange={(v) => setWrapMode(v as string)}
|
|
303
|
+
/>
|
|
304
|
+
</div>
|
|
63
305
|
<ITFlex justify="between" align="center">
|
|
64
|
-
<span className="text-sm font-semibold text-slate-700 dark:text-slate-300">
|
|
306
|
+
<span className="text-sm font-semibold text-slate-700 dark:text-slate-300">Show divider</span>
|
|
65
307
|
<ITSlideToggle isOn={withDivider} onToggle={setWithDivider} size="sm" />
|
|
66
308
|
</ITFlex>
|
|
67
309
|
</>
|
|
68
310
|
}
|
|
69
311
|
gallery={
|
|
70
|
-
<ITStack spacing={
|
|
71
|
-
{/*
|
|
72
|
-
<
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
312
|
+
<ITStack spacing={8}>
|
|
313
|
+
{/* ── Section 1: Spacing Scale ── */}
|
|
314
|
+
<GallerySection
|
|
315
|
+
title="Spacing Scale"
|
|
316
|
+
subtitle="Try different gap values to feel the rhythm"
|
|
317
|
+
>
|
|
318
|
+
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
319
|
+
{[
|
|
320
|
+
{ gap: 1, label: "Tight", desc: "Compact UI" },
|
|
321
|
+
{ gap: 3, label: "Default", desc: "Comfortable" },
|
|
322
|
+
{ gap: 6, label: "Relaxed", desc: "Breathing room" },
|
|
323
|
+
{ gap: 10, label: "Spacious", desc: "Hero sections" },
|
|
324
|
+
].map((s) => (
|
|
325
|
+
<div key={s.gap} className="bg-white dark:bg-slate-800/60 rounded-2xl border border-slate-200 dark:border-slate-700 p-5 shadow-sm">
|
|
326
|
+
<div className="flex items-center justify-between mb-3">
|
|
327
|
+
<span className="text-xs font-semibold text-slate-700 dark:text-slate-200">{s.label}</span>
|
|
328
|
+
<span className="text-[10px] font-mono text-slate-400">spacing={s.gap} • {(s.gap * 0.25).toFixed(2)}rem</span>
|
|
329
|
+
</div>
|
|
330
|
+
<p className="text-[11px] text-slate-400 mb-4">{s.desc}</p>
|
|
331
|
+
<ITStack direction="row" spacing={s.gap}>
|
|
332
|
+
<StackDemoItem index={1} size="sm" />
|
|
333
|
+
<StackDemoItem index={2} size="sm" />
|
|
334
|
+
<StackDemoItem index={3} size="sm" />
|
|
335
|
+
</ITStack>
|
|
336
|
+
</div>
|
|
337
|
+
))}
|
|
338
|
+
</div>
|
|
339
|
+
</GallerySection>
|
|
340
|
+
|
|
341
|
+
{/* ── Section 2: Justify Content ── */}
|
|
342
|
+
<GallerySection
|
|
343
|
+
title="Justify Content"
|
|
344
|
+
subtitle="How children are distributed along the main axis"
|
|
345
|
+
>
|
|
346
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
347
|
+
{[
|
|
348
|
+
{ label: "start", desc: "Children packed at the start" },
|
|
349
|
+
{ label: "center", desc: "Children centered on the axis" },
|
|
350
|
+
{ label: "end", desc: "Children packed at the end" },
|
|
351
|
+
{ label: "between", desc: "First/last at edges, rest spread evenly" },
|
|
352
|
+
{ label: "around", desc: "Equal space around each child" },
|
|
353
|
+
{ label: "evenly", desc: "Equal space everywhere" },
|
|
354
|
+
].map((j) => (
|
|
355
|
+
<div key={j.label} className="bg-white dark:bg-slate-800/60 rounded-2xl border border-slate-200 dark:border-slate-700 p-5 shadow-sm">
|
|
356
|
+
<div className="flex items-center justify-between mb-1">
|
|
357
|
+
<code className="text-xs font-mono font-bold text-primary-600 dark:text-primary-400">justifyContent="{j.label}"</code>
|
|
358
|
+
</div>
|
|
359
|
+
<p className="text-[11px] text-slate-400 mb-3">{j.desc}</p>
|
|
360
|
+
<div className="bg-slate-50 dark:bg-slate-900/50 rounded-lg p-3 border border-dashed border-slate-200 dark:border-slate-700">
|
|
361
|
+
<ITStack direction="row" spacing={2} justifyContent={j.label as any} className="w-full">
|
|
362
|
+
<StackDemoItem index={1} size="sm" />
|
|
363
|
+
<StackDemoItem index={2} size="sm" />
|
|
364
|
+
<StackDemoItem index={3} size="sm" />
|
|
365
|
+
</ITStack>
|
|
366
|
+
</div>
|
|
367
|
+
</div>
|
|
368
|
+
))}
|
|
369
|
+
</div>
|
|
370
|
+
</GallerySection>
|
|
371
|
+
|
|
372
|
+
{/* ── Section 3: Align Items ── */}
|
|
373
|
+
<GallerySection
|
|
374
|
+
title="Align Items"
|
|
375
|
+
subtitle="How children are aligned on the cross axis"
|
|
376
|
+
>
|
|
377
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
378
|
+
{[
|
|
379
|
+
{ label: "start", desc: "Aligned to top (in row)" },
|
|
380
|
+
{ label: "center", desc: "Centered on cross axis" },
|
|
381
|
+
{ label: "end", desc: "Aligned to bottom (in row)" },
|
|
382
|
+
{ label: "stretch", desc: "Children fill cross axis" },
|
|
383
|
+
{ label: "baseline", desc: "Text baselines align" },
|
|
384
|
+
].map((a) => (
|
|
385
|
+
<div key={a.label} className="bg-white dark:bg-slate-800/60 rounded-2xl border border-slate-200 dark:border-slate-700 p-5 shadow-sm">
|
|
386
|
+
<div className="flex items-center justify-between mb-1">
|
|
387
|
+
<code className="text-xs font-mono font-bold text-emerald-600 dark:text-emerald-400">alignItems="{a.label}"</code>
|
|
388
|
+
</div>
|
|
389
|
+
<p className="text-[11px] text-slate-400 mb-3">{a.desc}</p>
|
|
390
|
+
<div className="bg-slate-50 dark:bg-slate-900/50 rounded-lg p-3 border border-dashed border-slate-200 dark:border-slate-700">
|
|
391
|
+
<ITStack direction="row" spacing={3} alignItems={a.label as any} className="h-24">
|
|
392
|
+
<StackDemoItem index={1} size="sm" />
|
|
393
|
+
<div className="min-w-[64px] h-14 px-4 text-white rounded-xl flex items-center justify-center font-semibold text-sm"
|
|
394
|
+
style={{
|
|
395
|
+
background: 'linear-gradient(135deg, var(--color-success-500, #10b981) 0%, var(--color-success-700, #047857) 100%)',
|
|
396
|
+
boxShadow: '0 4px 14px 0 rgba(16, 185, 129, 0.3)',
|
|
397
|
+
}}
|
|
398
|
+
>
|
|
399
|
+
Mid
|
|
400
|
+
</div>
|
|
401
|
+
<StackDemoItem index={3} size="sm" />
|
|
402
|
+
</ITStack>
|
|
403
|
+
</div>
|
|
404
|
+
</div>
|
|
405
|
+
))}
|
|
406
|
+
</div>
|
|
407
|
+
</GallerySection>
|
|
408
|
+
|
|
409
|
+
{/* ── Section 4: Real UI cases ── */}
|
|
410
|
+
<GallerySection
|
|
411
|
+
title="Real UI cases"
|
|
412
|
+
subtitle="Production-ready UI built entirely with ITStack"
|
|
413
|
+
>
|
|
414
|
+
<div className="grid grid-cols-1 lg:grid-cols-2 gap-5">
|
|
415
|
+
{/* Page header with actions */}
|
|
416
|
+
<PatternCard title="Page Header" desc="Title + actions on the right" code={PATTERN_CODES.pageHeader}>
|
|
417
|
+
<div className="rounded-xl p-4 border border-slate-200 dark:border-slate-700 bg-slate-50 dark:bg-slate-800/80">
|
|
418
|
+
<ITStack direction="row" spacing={3} justifyContent="between" alignItems="center">
|
|
419
|
+
<div>
|
|
420
|
+
<p className="text-sm font-bold text-slate-800 dark:text-slate-100">Patient Records</p>
|
|
421
|
+
<p className="text-xs text-slate-500 dark:text-slate-400">128 active records</p>
|
|
422
|
+
</div>
|
|
423
|
+
<ITStack direction="row" spacing={2}>
|
|
424
|
+
<ITButton variant="outlined" color="gray" size="small">
|
|
425
|
+
Export
|
|
426
|
+
</ITButton>
|
|
427
|
+
<ITButton variant="filled" color="primary" size="small">
|
|
428
|
+
+ New Record
|
|
429
|
+
</ITButton>
|
|
430
|
+
</ITStack>
|
|
431
|
+
</ITStack>
|
|
432
|
+
</div>
|
|
433
|
+
</PatternCard>
|
|
434
|
+
|
|
435
|
+
{/* Tag cloud */}
|
|
436
|
+
<PatternCard title="Tag Cloud" desc="Wrap enabled for flowing tags" code={PATTERN_CODES.tagCloud}>
|
|
437
|
+
<div className="rounded-xl p-4 border border-slate-200 dark:border-slate-700 bg-slate-50 dark:bg-slate-800/80">
|
|
438
|
+
<ITStack direction="row" spacing={2} flexWrap="wrap">
|
|
439
|
+
<StackChip label="React" color="primary" />
|
|
440
|
+
<StackChip label="TypeScript" color="success" />
|
|
441
|
+
<StackChip label="Tailwind" color="info" />
|
|
442
|
+
<StackChip label="Storybook" color="warning" />
|
|
443
|
+
<StackChip label="Vite" color="primary" />
|
|
444
|
+
<StackChip label="CSS Vars" color="info" />
|
|
445
|
+
<StackChip label="Flexbox" color="success" />
|
|
446
|
+
<StackChip label="Accessibility" color="warning" />
|
|
447
|
+
</ITStack>
|
|
448
|
+
</div>
|
|
449
|
+
</PatternCard>
|
|
450
|
+
|
|
451
|
+
{/* Section list with dividers */}
|
|
452
|
+
<PatternCard title="Section List" desc="Subtle divider between items" code={PATTERN_CODES.sectionList}>
|
|
453
|
+
<div className="rounded-xl p-2 border border-slate-200 dark:border-slate-700 bg-slate-50 dark:bg-slate-800/80">
|
|
454
|
+
<ITStack spacing={0} divider={<div className="h-px bg-slate-200 dark:bg-slate-700 mx-3" />}>
|
|
455
|
+
{[
|
|
456
|
+
{ initial: "JD", name: "John Doe", email: "john@axzy.dev", status: "Active", color: "primary" },
|
|
457
|
+
{ initial: "AS", name: "Anna Smith", email: "anna@axzy.dev", status: "Pending", color: "warning" },
|
|
458
|
+
{ initial: "MK", name: "Mike Kim", email: "mike@axzy.dev", status: "Active", color: "success" },
|
|
459
|
+
].map((user) => (
|
|
460
|
+
<div key={user.email} className="flex items-center gap-3 py-3 px-4 hover:bg-white/60 dark:hover:bg-slate-800/60 rounded-lg transition-colors">
|
|
461
|
+
<div className="w-9 h-9 rounded-full flex items-center justify-center text-white font-semibold text-xs"
|
|
462
|
+
style={{
|
|
463
|
+
background: 'linear-gradient(135deg, var(--color-primary-500, #3b82f6) 0%, var(--color-primary-700, #1d4ed8) 100%)',
|
|
464
|
+
boxShadow: '0 2px 8px 0 rgba(59, 130, 246, 0.25)',
|
|
465
|
+
}}
|
|
466
|
+
>
|
|
467
|
+
{user.initial}
|
|
468
|
+
</div>
|
|
469
|
+
<div className="flex-1 min-w-0">
|
|
470
|
+
<p className="text-sm font-semibold text-slate-800 dark:text-slate-100 truncate">{user.name}</p>
|
|
471
|
+
<p className="text-xs text-slate-500 dark:text-slate-400 truncate">{user.email}</p>
|
|
472
|
+
</div>
|
|
473
|
+
<span className={`px-2.5 py-1 rounded-md text-[10px] font-semibold uppercase tracking-wider ${
|
|
474
|
+
user.color === "primary" ? "bg-primary-100 text-primary-700 dark:bg-primary-900/40 dark:text-primary-300" :
|
|
475
|
+
user.color === "warning" ? "bg-amber-100 text-amber-700 dark:bg-amber-900/40 dark:text-amber-300" :
|
|
476
|
+
"bg-emerald-100 text-emerald-700 dark:bg-emerald-900/40 dark:text-emerald-300"
|
|
477
|
+
}`}>
|
|
478
|
+
{user.status}
|
|
479
|
+
</span>
|
|
480
|
+
</div>
|
|
481
|
+
))}
|
|
482
|
+
</ITStack>
|
|
483
|
+
</div>
|
|
484
|
+
</PatternCard>
|
|
485
|
+
|
|
486
|
+
{/* Notification banner */}
|
|
487
|
+
<PatternCard title="Notification banner" desc="Icon + message + dismiss" code={PATTERN_CODES.notification}>
|
|
488
|
+
<div className="rounded-xl border border-emerald-200 dark:border-emerald-800/50 overflow-hidden bg-emerald-50 dark:bg-emerald-950/40">
|
|
489
|
+
<ITStack direction="row" spacing={3} alignItems="center" className="p-4">
|
|
490
|
+
<div className="w-9 h-9 rounded-full bg-emerald-500 flex items-center justify-center text-white shrink-0 shadow-sm">
|
|
491
|
+
<span className="text-base font-bold leading-none">✓</span>
|
|
492
|
+
</div>
|
|
493
|
+
<div className="flex-1 min-w-0">
|
|
494
|
+
<p className="text-sm font-semibold text-emerald-900 dark:text-emerald-200">Deployment successful</p>
|
|
495
|
+
<p className="text-xs text-emerald-700 dark:text-emerald-400 mt-0.5">Your changes are live in production.</p>
|
|
496
|
+
</div>
|
|
497
|
+
<ITButton variant="icon-only" color="gray" size="small">
|
|
498
|
+
<span className="text-lg leading-none">×</span>
|
|
499
|
+
</ITButton>
|
|
500
|
+
</ITStack>
|
|
501
|
+
</div>
|
|
502
|
+
</PatternCard>
|
|
503
|
+
|
|
504
|
+
{/* Stats row */}
|
|
505
|
+
<PatternCard title="Stats row" desc="3 metric cards in one row" code={PATTERN_CODES.statsRow}>
|
|
506
|
+
<div className="rounded-xl p-4 border border-slate-200 dark:border-slate-700 bg-slate-50 dark:bg-slate-800/80">
|
|
507
|
+
<ITStack direction="row" spacing={3}>
|
|
508
|
+
{[
|
|
509
|
+
{ label: "Revenue", value: "$48.2k", delta: "+12.4%", color: "emerald" },
|
|
510
|
+
{ label: "Active users", value: "2,847", delta: "+5.1%", color: "primary" },
|
|
511
|
+
{ label: "Conversion", value: "3.24%", delta: "−0.8%", color: "amber" },
|
|
512
|
+
].map((stat) => (
|
|
513
|
+
<div key={stat.label} className="flex-1 min-w-0 bg-white dark:bg-slate-800 rounded-xl p-3 border border-slate-200 dark:border-slate-700 shadow-sm">
|
|
514
|
+
<p className="text-[10px] uppercase tracking-wider font-semibold text-slate-500 dark:text-slate-400">{stat.label}</p>
|
|
515
|
+
<p className="text-xl font-bold text-slate-800 dark:text-slate-100 mt-1 font-mono">{stat.value}</p>
|
|
516
|
+
<p className={`text-[10px] font-semibold mt-0.5 ${
|
|
517
|
+
stat.color === "emerald" ? "text-emerald-600 dark:text-emerald-400" :
|
|
518
|
+
stat.color === "amber" ? "text-amber-600 dark:text-amber-400" :
|
|
519
|
+
"text-primary-600 dark:text-primary-400"
|
|
520
|
+
}`}>{stat.delta}</p>
|
|
521
|
+
</div>
|
|
522
|
+
))}
|
|
523
|
+
</ITStack>
|
|
524
|
+
</div>
|
|
525
|
+
</PatternCard>
|
|
526
|
+
</div>
|
|
527
|
+
</GallerySection>
|
|
96
528
|
</ITStack>
|
|
97
529
|
}
|
|
98
530
|
/>
|
|
99
531
|
);
|
|
100
532
|
};
|
|
101
533
|
|
|
534
|
+
// ── Helper components ──
|
|
535
|
+
|
|
536
|
+
const GallerySection = ({ title, subtitle, children }: { title: string; subtitle?: string; children: React.ReactNode }) => (
|
|
537
|
+
<div>
|
|
538
|
+
<div className="mb-5">
|
|
539
|
+
<h3 className="text-base font-bold text-slate-800 dark:text-slate-100 flex items-center gap-2">
|
|
540
|
+
<span className="w-1 h-5 rounded-full bg-gradient-to-b from-primary-500 to-primary-700" />
|
|
541
|
+
{title}
|
|
542
|
+
</h3>
|
|
543
|
+
{subtitle && <p className="text-xs text-slate-500 dark:text-slate-400 mt-1 ml-3">{subtitle}</p>}
|
|
544
|
+
</div>
|
|
545
|
+
{children}
|
|
546
|
+
</div>
|
|
547
|
+
);
|
|
548
|
+
|
|
549
|
+
const PatternCard = ({ title, desc, code, children }: { title: string; desc?: string; code?: string; children: React.ReactNode }) => {
|
|
550
|
+
const [showCode, setShowCode] = useState(false);
|
|
551
|
+
return (
|
|
552
|
+
<div className="bg-white dark:bg-slate-900/60 rounded-2xl border border-slate-200 dark:border-slate-700 shadow-sm hover:shadow-md transition-shadow overflow-hidden">
|
|
553
|
+
<div className="flex items-start justify-between gap-2 p-4 pb-3">
|
|
554
|
+
<div className="min-w-0">
|
|
555
|
+
<p className="text-sm font-semibold text-slate-800 dark:text-slate-100">{title}</p>
|
|
556
|
+
{desc && <p className="text-[11px] text-slate-500 dark:text-slate-400 mt-0.5">{desc}</p>}
|
|
557
|
+
</div>
|
|
558
|
+
{code && (
|
|
559
|
+
<ITButton variant="outlined" color="gray" size="small" onClick={() => setShowCode(!showCode)}>
|
|
560
|
+
<ITFlex align="center" gap={1}>
|
|
561
|
+
<FaCode size={9} />
|
|
562
|
+
{showCode ? "Hide code" : "Code"}
|
|
563
|
+
</ITFlex>
|
|
564
|
+
</ITButton>
|
|
565
|
+
)}
|
|
566
|
+
</div>
|
|
567
|
+
<div className="px-4 pb-4">{children}</div>
|
|
568
|
+
{showCode && code && (
|
|
569
|
+
<div className="px-4 pb-4 border-t border-slate-200 dark:border-slate-700 pt-3">
|
|
570
|
+
<CodeViewer code={code} compact />
|
|
571
|
+
</div>
|
|
572
|
+
)}
|
|
573
|
+
</div>
|
|
574
|
+
);
|
|
575
|
+
};
|
|
576
|
+
|
|
102
577
|
// ─────────────────────────────────────────
|
|
103
578
|
// 2. ITFlex Showcase
|
|
104
579
|
// ─────────────────────────────────────────
|
|
580
|
+
|
|
581
|
+
const FLEX_PATTERN_CODES = {
|
|
582
|
+
spaceBetween: `<ITFlex
|
|
583
|
+
direction="row"
|
|
584
|
+
justify="between"
|
|
585
|
+
align="center"
|
|
586
|
+
gap={3}
|
|
587
|
+
>
|
|
588
|
+
<ITFlex direction="column" gap={0}>
|
|
589
|
+
<p>Document.pdf</p>
|
|
590
|
+
<p>Last edited 2 min ago</p>
|
|
591
|
+
</ITFlex>
|
|
592
|
+
<ITFlex direction="row" gap={2}>
|
|
593
|
+
<ITButton label="Cancel" variant="outlined" color="gray" size="small" />
|
|
594
|
+
<ITButton label="Save" variant="filled" color="primary" size="small" />
|
|
595
|
+
</ITFlex>
|
|
596
|
+
</ITFlex>`,
|
|
597
|
+
growItems: `<ITFlex direction="row" gap={3}>
|
|
598
|
+
<ITFlex grow direction="column" className="...">
|
|
599
|
+
Sidebar
|
|
600
|
+
</ITFlex>
|
|
601
|
+
<ITFlex grow direction="column" className="...">
|
|
602
|
+
Content
|
|
603
|
+
</ITFlex>
|
|
604
|
+
<div className="...">Fixed</div>
|
|
605
|
+
</ITFlex>`,
|
|
606
|
+
centeredCard: `<ITFlex
|
|
607
|
+
direction="column"
|
|
608
|
+
justify="center"
|
|
609
|
+
align="center"
|
|
610
|
+
gap={3}
|
|
611
|
+
className="min-h-56 text-center px-6 py-6"
|
|
612
|
+
>
|
|
613
|
+
<div className="w-14 h-14 rounded-2xl ...">✦</div>
|
|
614
|
+
<div>
|
|
615
|
+
<p className="text-lg font-bold ...">All set!</p>
|
|
616
|
+
<p className="text-xs ...">Your workspace is ready to use.</p>
|
|
617
|
+
</div>
|
|
618
|
+
<ITButton label="Get started" variant="filled" color="primary" size="small" />
|
|
619
|
+
</ITFlex>`,
|
|
620
|
+
formRowWrap: `<ITFlex
|
|
621
|
+
direction="row"
|
|
622
|
+
wrap="wrap"
|
|
623
|
+
gap={3}
|
|
624
|
+
>
|
|
625
|
+
{fields.map((f) => (
|
|
626
|
+
<ITFlex
|
|
627
|
+
key={f.label}
|
|
628
|
+
grow
|
|
629
|
+
basis={56}
|
|
630
|
+
direction="column"
|
|
631
|
+
gap={1}
|
|
632
|
+
>
|
|
633
|
+
<label>{f.label}</label>
|
|
634
|
+
<input />
|
|
635
|
+
</ITFlex>
|
|
636
|
+
))}
|
|
637
|
+
</ITFlex>`,
|
|
638
|
+
stretchColumn: `<ITFlex
|
|
639
|
+
direction="column"
|
|
640
|
+
align="stretch"
|
|
641
|
+
gap={0}
|
|
642
|
+
className="h-full"
|
|
643
|
+
>
|
|
644
|
+
<div className="h-12 ...">Header</div>
|
|
645
|
+
<ITFlex grow align="center" justify="center" direction="column">
|
|
646
|
+
Main content
|
|
647
|
+
</ITFlex>
|
|
648
|
+
<div className="h-12 ...">Footer</div>
|
|
649
|
+
</ITFlex>`,
|
|
650
|
+
};
|
|
651
|
+
|
|
105
652
|
export const FlexShowcase = () => {
|
|
106
|
-
const [direction, setDirection] = useState<"row" | "column">("row");
|
|
653
|
+
const [direction, setDirection] = useState<"row" | "column" | "row-reverse" | "column-reverse">("row");
|
|
107
654
|
const [justify, setJustify] = useState("start");
|
|
108
655
|
const [align, setAlign] = useState("center");
|
|
656
|
+
const [wrap, setWrap] = useState("nowrap");
|
|
109
657
|
const [gap, setGap] = useState(3);
|
|
110
658
|
|
|
111
659
|
const justifyOptions = [
|
|
@@ -114,82 +662,216 @@ export const FlexShowcase = () => {
|
|
|
114
662
|
{ value: "end", label: "End" },
|
|
115
663
|
{ value: "between", label: "Between" },
|
|
116
664
|
{ value: "around", label: "Around" },
|
|
665
|
+
{ value: "evenly", label: "Evenly" },
|
|
117
666
|
];
|
|
118
667
|
|
|
119
|
-
const
|
|
668
|
+
const buildCode = () => {
|
|
669
|
+
const props = [`direction="${direction}"`];
|
|
670
|
+
if (justify !== "start") props.push(`justify="${justify}"`);
|
|
671
|
+
if (align !== "stretch") props.push(`align="${align}"`);
|
|
672
|
+
if (wrap !== "nowrap") props.push(`wrap="${wrap}"`);
|
|
673
|
+
if (gap !== 0) props.push(`gap={${gap}}`);
|
|
674
|
+
return `<ITFlex\n ${props.join("\n ")}\n>\n <Box>Item 1</Box>\n <Box>Item 2</Box>\n <Box>Item 3</Box>\n</ITFlex>`;
|
|
675
|
+
};
|
|
120
676
|
|
|
121
677
|
return (
|
|
122
678
|
<ShowcaseLayout
|
|
123
679
|
title="ITFlex"
|
|
124
680
|
description="Contenedor flexbox completo con control total sobre alineación, distribución y gap. Para layouts complejos que requieren más control que ITStack."
|
|
125
|
-
code={
|
|
681
|
+
code={buildCode()}
|
|
126
682
|
demo={
|
|
127
|
-
<div className="w-full">
|
|
128
|
-
<
|
|
129
|
-
<
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
683
|
+
<div className="w-full max-w-xl flex flex-col">
|
|
684
|
+
<div className="min-h-[360px]">
|
|
685
|
+
<ITFlex
|
|
686
|
+
direction={direction as any}
|
|
687
|
+
justify={justify as any}
|
|
688
|
+
align={align as any}
|
|
689
|
+
wrap={wrap as any}
|
|
690
|
+
gap={gap}
|
|
691
|
+
className="w-full bg-slate-50 dark:bg-slate-900/50 rounded-xl p-4 border border-dashed border-slate-200 dark:border-slate-700"
|
|
692
|
+
>
|
|
693
|
+
{[1, 2, 3, 4].map((i) => (
|
|
694
|
+
<div
|
|
695
|
+
key={i}
|
|
696
|
+
className="min-w-[80px] h-8 px-3 rounded-lg text-white text-xs font-semibold flex items-center justify-center shrink-0"
|
|
697
|
+
style={{
|
|
698
|
+
background: 'linear-gradient(135deg, var(--color-primary-500, #3b82f6) 0%, var(--color-primary-700, #1d4ed8) 100%)',
|
|
699
|
+
boxShadow: '0 4px 14px 0 rgba(59, 130, 246, 0.3)',
|
|
700
|
+
}}
|
|
701
|
+
>
|
|
702
|
+
Item {i}
|
|
703
|
+
</div>
|
|
704
|
+
))}
|
|
705
|
+
</ITFlex>
|
|
706
|
+
</div>
|
|
707
|
+
|
|
708
|
+
{/* Fixed footer with active-property badges */}
|
|
709
|
+
<div className="sticky bottom-0 mt-4 -mx-6 -mb-6 px-6 py-3 bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-t border-slate-200 dark:border-slate-700 flex items-center flex-wrap gap-1.5 text-[10px] font-mono">
|
|
710
|
+
<span className="text-[9px] uppercase tracking-wider font-bold text-slate-400 dark:text-slate-500 mr-1">Active:</span>
|
|
711
|
+
<span className="px-2 py-0.5 rounded-md bg-slate-900 text-white dark:bg-white dark:text-slate-900 font-semibold">{direction}</span>
|
|
712
|
+
<span className="px-2 py-0.5 rounded-md bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-300">gap:{gap}</span>
|
|
713
|
+
{justify !== "start" && <span className="px-2 py-0.5 rounded-md bg-emerald-100 dark:bg-emerald-900/30 text-emerald-700 dark:text-emerald-300">justify:{justify}</span>}
|
|
714
|
+
{align !== "stretch" && <span className="px-2 py-0.5 rounded-md bg-primary-100 dark:bg-primary-900/30 text-primary-700 dark:text-primary-300">align:{align}</span>}
|
|
715
|
+
{wrap !== "nowrap" && <span className="px-2 py-0.5 rounded-md bg-amber-100 dark:bg-amber-900/30 text-amber-700 dark:text-amber-300">{wrap}</span>}
|
|
716
|
+
</div>
|
|
133
717
|
</div>
|
|
134
718
|
}
|
|
135
719
|
controls={
|
|
136
720
|
<ITStack spacing={4}>
|
|
137
|
-
<
|
|
721
|
+
<div>
|
|
722
|
+
<p className="text-xs font-semibold text-slate-500 dark:text-slate-400 mb-1.5 uppercase tracking-wider">Direction</p>
|
|
723
|
+
<ITSegmentedControl
|
|
724
|
+
options={[
|
|
725
|
+
{ value: "row", label: "Row" },
|
|
726
|
+
{ value: "column", label: "Column" },
|
|
727
|
+
{ value: "row-reverse", label: "Row ↩" },
|
|
728
|
+
{ value: "column-reverse", label: "Col ↩" },
|
|
729
|
+
]}
|
|
730
|
+
value={direction}
|
|
731
|
+
onChange={(v) => setDirection(v as any)}
|
|
732
|
+
size="sm"
|
|
733
|
+
/>
|
|
734
|
+
</div>
|
|
735
|
+
<ITSelect
|
|
736
|
+
name="flex_justify"
|
|
737
|
+
label="Justify Content"
|
|
738
|
+
value={justify}
|
|
739
|
+
onChange={(e) => setJustify(e.target.value)}
|
|
740
|
+
options={justifyOptions}
|
|
741
|
+
/>
|
|
742
|
+
<ITSelect
|
|
743
|
+
name="flex_align"
|
|
744
|
+
label="Align Items"
|
|
745
|
+
value={align}
|
|
746
|
+
onChange={(e) => setAlign(e.target.value)}
|
|
138
747
|
options={[
|
|
139
|
-
{
|
|
140
|
-
{
|
|
141
|
-
{
|
|
142
|
-
{
|
|
748
|
+
{ label: "Start", value: "start" },
|
|
749
|
+
{ label: "Center", value: "center" },
|
|
750
|
+
{ label: "End", value: "end" },
|
|
751
|
+
{ label: "Stretch", value: "stretch" },
|
|
752
|
+
{ label: "Baseline", value: "baseline" },
|
|
143
753
|
]}
|
|
144
|
-
value={direction}
|
|
145
|
-
onChange={(v) => setDirection(v as any)}
|
|
146
|
-
size="sm"
|
|
147
754
|
/>
|
|
148
|
-
<
|
|
149
|
-
<
|
|
150
|
-
<ITSegmentedControl
|
|
151
|
-
options={justifyOptions.map(o => ({ value: o.value, label: o.label }))}
|
|
152
|
-
value={justify}
|
|
153
|
-
onChange={setJustify}
|
|
154
|
-
/>
|
|
155
|
-
</ITStack>
|
|
156
|
-
<ITStack spacing={2}>
|
|
157
|
-
<span className="text-xs font-semibold text-slate-600">Align</span>
|
|
755
|
+
<div>
|
|
756
|
+
<p className="text-xs font-semibold text-slate-500 dark:text-slate-400 mb-1.5 uppercase tracking-wider">Flex Wrap</p>
|
|
158
757
|
<ITSegmentedControl
|
|
159
|
-
options={[
|
|
160
|
-
|
|
161
|
-
|
|
758
|
+
options={[
|
|
759
|
+
{ value: "nowrap", label: "Nowrap" },
|
|
760
|
+
{ value: "wrap", label: "Wrap" },
|
|
761
|
+
{ value: "wrap-reverse", label: "Reverse" },
|
|
762
|
+
]}
|
|
763
|
+
value={wrap}
|
|
764
|
+
onChange={(v) => setWrap(v as string)}
|
|
162
765
|
/>
|
|
163
|
-
</
|
|
164
|
-
<ITSlider label="Gap" value={gap} onChange={setGap} min={0} max={
|
|
766
|
+
</div>
|
|
767
|
+
<ITSlider label="Gap (0.25rem units)" value={gap} onChange={setGap} min={0} max={12} />
|
|
165
768
|
</ITStack>
|
|
166
769
|
}
|
|
167
770
|
gallery={
|
|
168
|
-
<ITStack spacing={
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
771
|
+
<ITStack spacing={8}>
|
|
772
|
+
{/* ── Section 1: Real UI cases ── */}
|
|
773
|
+
<GallerySection
|
|
774
|
+
title="Real UI cases"
|
|
775
|
+
subtitle="Production-ready UI built entirely with ITFlex"
|
|
776
|
+
>
|
|
777
|
+
<div className="grid grid-cols-1 lg:grid-cols-2 gap-5">
|
|
778
|
+
{/* Space-between row */}
|
|
779
|
+
<PatternCard title="Toolbar row" desc="justify-between + nested actions" code={FLEX_PATTERN_CODES.spaceBetween}>
|
|
780
|
+
<div className="rounded-xl p-4 border border-slate-200 dark:border-slate-700 overflow-x-auto bg-slate-50 dark:bg-slate-800/80">
|
|
781
|
+
<ITFlex direction="row" justify="between" align="center" gap={3}>
|
|
782
|
+
<ITFlex direction="column" gap={0}>
|
|
783
|
+
<p className="text-sm font-bold text-slate-800 dark:text-slate-100">Document.pdf</p>
|
|
784
|
+
<p className="text-[11px] text-slate-500 dark:text-slate-400">Last edited 2 min ago</p>
|
|
785
|
+
</ITFlex>
|
|
786
|
+
<ITFlex direction="row" gap={2}>
|
|
787
|
+
<ITButton label="Cancel" variant="outlined" color="gray" size="small" />
|
|
788
|
+
<ITButton label="Save" variant="filled" color="primary" size="small" />
|
|
789
|
+
</ITFlex>
|
|
790
|
+
</ITFlex>
|
|
791
|
+
</div>
|
|
792
|
+
</PatternCard>
|
|
793
|
+
|
|
794
|
+
{/* Grow items */}
|
|
795
|
+
<PatternCard title="Grow layout" desc="flex-grow distributes remaining space" code={FLEX_PATTERN_CODES.growItems}>
|
|
796
|
+
<div className="rounded-xl p-4 border border-slate-200 dark:border-slate-700 bg-slate-50 dark:bg-slate-800/80">
|
|
797
|
+
<ITFlex direction="row" gap={3}>
|
|
798
|
+
<ITFlex grow direction="column" gap={1} className="bg-blue-100 dark:bg-blue-900/30 rounded-xl p-4">
|
|
799
|
+
<p className="text-[10px] uppercase tracking-wider font-semibold text-blue-600 dark:text-blue-400">Sidebar</p>
|
|
800
|
+
<p className="text-sm font-semibold text-blue-900 dark:text-blue-200">Navigation</p>
|
|
801
|
+
</ITFlex>
|
|
802
|
+
<ITFlex grow direction="column" gap={1} className="bg-emerald-100 dark:bg-emerald-900/30 rounded-xl p-4">
|
|
803
|
+
<p className="text-[10px] uppercase tracking-wider font-semibold text-emerald-600 dark:text-emerald-400">Content</p>
|
|
804
|
+
<p className="text-sm font-semibold text-emerald-900 dark:text-emerald-200">Main area</p>
|
|
805
|
+
</ITFlex>
|
|
806
|
+
<div className="bg-slate-100 dark:bg-slate-800 rounded-xl p-4 text-center">
|
|
807
|
+
<p className="text-[10px] uppercase tracking-wider font-semibold text-slate-500 dark:text-slate-400">Fixed</p>
|
|
808
|
+
<p className="text-sm font-semibold text-slate-700 dark:text-slate-300 mt-1">100px</p>
|
|
809
|
+
</div>
|
|
810
|
+
</ITFlex>
|
|
811
|
+
</div>
|
|
812
|
+
</PatternCard>
|
|
813
|
+
|
|
814
|
+
{/* Centered card */}
|
|
815
|
+
<PatternCard title="Centered hero" desc="justify-center + align-center" code={FLEX_PATTERN_CODES.centeredCard}>
|
|
816
|
+
<div className="rounded-xl border border-primary-100 dark:border-primary-800/40 overflow-x-auto bg-blue-50 dark:bg-blue-950/30">
|
|
817
|
+
<ITFlex direction="column" justify="center" align="center" gap={3} className="min-h-56 text-center px-6 py-6">
|
|
818
|
+
<div className="w-14 h-14 rounded-2xl flex items-center justify-center text-white text-2xl font-bold"
|
|
819
|
+
style={{
|
|
820
|
+
background: 'linear-gradient(135deg, var(--color-primary-500, #3b82f6) 0%, var(--color-primary-700, #1d4ed8) 100%)',
|
|
821
|
+
boxShadow: '0 8px 24px 0 rgba(59, 130, 246, 0.3)',
|
|
822
|
+
}}
|
|
823
|
+
>
|
|
824
|
+
✦
|
|
825
|
+
</div>
|
|
826
|
+
<div>
|
|
827
|
+
<p className="text-lg font-bold text-slate-800 dark:text-slate-100">All set!</p>
|
|
828
|
+
<p className="text-xs text-slate-500 dark:text-slate-400 mt-1">Your workspace is ready to use.</p>
|
|
829
|
+
</div>
|
|
830
|
+
<ITButton label="Get started" variant="filled" color="primary" size="small" />
|
|
831
|
+
</ITFlex>
|
|
832
|
+
</div>
|
|
833
|
+
</PatternCard>
|
|
834
|
+
|
|
835
|
+
{/* Form row with wrap */}
|
|
836
|
+
<PatternCard title="Responsive form" desc="wrap + grow + basis" code={FLEX_PATTERN_CODES.formRowWrap}>
|
|
837
|
+
<div className="rounded-xl p-4 border border-slate-200 dark:border-slate-700 bg-slate-50 dark:bg-slate-800/80">
|
|
838
|
+
<ITFlex direction="row" wrap="wrap" gap={3}>
|
|
839
|
+
{[
|
|
840
|
+
{ label: "First name", value: "John" },
|
|
841
|
+
{ label: "Last name", value: "Doe" },
|
|
842
|
+
{ label: "Email", value: "john@axzy.dev" },
|
|
843
|
+
].map((field) => (
|
|
844
|
+
<ITFlex key={field.label} grow basis={56} direction="column" gap={1}>
|
|
845
|
+
<label className="text-[10px] font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400">{field.label}</label>
|
|
846
|
+
<div className="h-9 rounded-lg border border-slate-200 dark:border-slate-600 bg-white dark:bg-slate-800 px-3 flex items-center text-sm text-slate-700 dark:text-slate-200 shadow-sm">
|
|
847
|
+
{field.value}
|
|
848
|
+
</div>
|
|
849
|
+
</ITFlex>
|
|
850
|
+
))}
|
|
851
|
+
</ITFlex>
|
|
852
|
+
</div>
|
|
853
|
+
</PatternCard>
|
|
854
|
+
|
|
855
|
+
{/* Stretch column */}
|
|
856
|
+
<PatternCard title="Full-height layout" desc="column + stretch + grow" code={FLEX_PATTERN_CODES.stretchColumn}>
|
|
857
|
+
<div className="rounded-xl border border-slate-200 dark:border-slate-700 overflow-hidden h-72 bg-slate-50 dark:bg-slate-800/80">
|
|
858
|
+
<ITFlex direction="column" align="stretch" gap={0} className="h-full">
|
|
859
|
+
<div className="h-12 px-4 flex items-center justify-between bg-slate-100 dark:bg-slate-800 border-b border-slate-200 dark:border-slate-700">
|
|
860
|
+
<p className="text-xs font-bold text-slate-700 dark:text-slate-200">App Header</p>
|
|
861
|
+
<span className="text-[10px] text-slate-500">v1.0</span>
|
|
862
|
+
</div>
|
|
863
|
+
<ITFlex grow align="center" justify="center" direction="column" gap={2} className="bg-white dark:bg-slate-900/40">
|
|
864
|
+
<p className="text-2xl font-extrabold text-slate-800 dark:text-slate-100">Main content</p>
|
|
865
|
+
<p className="text-xs text-slate-500 dark:text-slate-400">flex-grow fills remaining space</p>
|
|
866
|
+
</ITFlex>
|
|
867
|
+
<div className="h-12 px-4 flex items-center justify-center bg-slate-100 dark:bg-slate-800 border-t border-slate-200 dark:border-slate-700">
|
|
868
|
+
<p className="text-[10px] text-slate-500">App Footer</p>
|
|
869
|
+
</div>
|
|
870
|
+
</ITFlex>
|
|
871
|
+
</div>
|
|
872
|
+
</PatternCard>
|
|
873
|
+
</div>
|
|
874
|
+
</GallerySection>
|
|
193
875
|
</ITStack>
|
|
194
876
|
}
|
|
195
877
|
/>
|
|
@@ -199,87 +881,430 @@ export const FlexShowcase = () => {
|
|
|
199
881
|
// ─────────────────────────────────────────
|
|
200
882
|
// 3. ITGrid Showcase
|
|
201
883
|
// ─────────────────────────────────────────
|
|
884
|
+
|
|
885
|
+
const GRID_PATTERN_CODES = {
|
|
886
|
+
appDashboard: `// App shell: sidebar + main area, stacks on mobile
|
|
887
|
+
<ITGrid container spacing={4}>
|
|
888
|
+
<ITGrid item xs={12} md={3}>
|
|
889
|
+
<NavSidebar />
|
|
890
|
+
</ITGrid>
|
|
891
|
+
<ITGrid item xs={12} md={9}>
|
|
892
|
+
<MainPanel />
|
|
893
|
+
</ITGrid>
|
|
894
|
+
</ITGrid>`,
|
|
895
|
+
userProfile: `// Profile: avatar card + content area
|
|
896
|
+
<ITGrid container spacing={4}>
|
|
897
|
+
<ITGrid item xs={12} md={4}>
|
|
898
|
+
<ProfileCard user={user} />
|
|
899
|
+
</ITGrid>
|
|
900
|
+
<ITGrid item xs={12} md={8}>
|
|
901
|
+
<ActivityFeed activities={user.activity} />
|
|
902
|
+
</ITGrid>
|
|
903
|
+
</ITGrid>`,
|
|
904
|
+
settingsPage: `// Settings: section nav + form panels
|
|
905
|
+
<ITGrid container spacing={4}>
|
|
906
|
+
<ITGrid item xs={12} md={3}>
|
|
907
|
+
<SettingsNav />
|
|
908
|
+
</ITGrid>
|
|
909
|
+
<ITGrid item xs={12} md={9}>
|
|
910
|
+
<SettingsPanel section={current} />
|
|
911
|
+
</ITGrid>
|
|
912
|
+
</ITGrid>`,
|
|
913
|
+
articleLayout: `// Article + sidebar with metadata
|
|
914
|
+
<ITGrid container spacing={6}>
|
|
915
|
+
<ITGrid item xs={12} md={8}>
|
|
916
|
+
<Article />
|
|
917
|
+
</ITGrid>
|
|
918
|
+
<ITGrid item xs={12} md={4}>
|
|
919
|
+
<ArticleMeta author={author} tags={tags} />
|
|
920
|
+
</ITGrid>
|
|
921
|
+
</ITGrid>`,
|
|
922
|
+
pricingTiers: `// 3-column pricing comparison
|
|
923
|
+
<ITGrid container spacing={4}>
|
|
924
|
+
{plans.map((plan) => (
|
|
925
|
+
<ITGrid key={plan.id} item xs={12} md={4}>
|
|
926
|
+
<PricingCard plan={plan} highlighted={plan.featured} />
|
|
927
|
+
</ITGrid>
|
|
928
|
+
))}
|
|
929
|
+
</ITGrid>`,
|
|
930
|
+
};
|
|
931
|
+
|
|
202
932
|
export const GridShowcase = () => {
|
|
203
933
|
const [spacing, setSpacing] = useState(3);
|
|
204
934
|
const [columns, setColumns] = useState(3);
|
|
205
935
|
|
|
206
|
-
const
|
|
936
|
+
const buildCode = () => {
|
|
937
|
+
const md = Math.floor(12 / columns);
|
|
938
|
+
return `<ITGrid container spacing={${spacing}}>\n {items.map((item) => (\n <ITGrid item xs={12} md={${md}}>\n <Card>{item.name}</Card>\n </ITGrid>\n ))}\n</ITGrid>`;
|
|
939
|
+
};
|
|
207
940
|
|
|
208
|
-
const items = Array.from({ length: columns * 2 }, (_, i) =>
|
|
941
|
+
const items = Array.from({ length: columns * 2 }, (_, i) => ({
|
|
942
|
+
id: i + 1,
|
|
943
|
+
name: `Item ${i + 1}`,
|
|
944
|
+
}));
|
|
209
945
|
|
|
210
946
|
return (
|
|
211
947
|
<ShowcaseLayout
|
|
212
948
|
title="ITGrid"
|
|
213
949
|
description="Sistema de grid responsivo de 12 columnas. Ideal para dashboards, galerías, y layouts de página completos."
|
|
214
|
-
code={
|
|
950
|
+
code={buildCode()}
|
|
215
951
|
demo={
|
|
216
|
-
<div className="w-full">
|
|
217
|
-
<
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
<
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
952
|
+
<div className="w-full max-w-xl flex flex-col">
|
|
953
|
+
<div className="min-h-[360px]">
|
|
954
|
+
<ITGrid container spacing={spacing}>
|
|
955
|
+
{items.map((item) => (
|
|
956
|
+
<ITGrid key={item.id} item xs={12} md={Math.floor(12 / columns)}>
|
|
957
|
+
<div
|
|
958
|
+
className="h-16 rounded-lg flex items-center justify-center text-white text-sm font-semibold font-mono"
|
|
959
|
+
style={{
|
|
960
|
+
background: 'linear-gradient(135deg, var(--color-primary-500, #3b82f6) 0%, var(--color-primary-700, #1d4ed8) 100%)',
|
|
961
|
+
boxShadow: '0 4px 14px 0 rgba(59, 130, 246, 0.3)',
|
|
962
|
+
}}
|
|
963
|
+
>
|
|
964
|
+
{item.name}
|
|
965
|
+
</div>
|
|
966
|
+
</ITGrid>
|
|
967
|
+
))}
|
|
968
|
+
</ITGrid>
|
|
969
|
+
</div>
|
|
970
|
+
|
|
971
|
+
{/* Fixed footer with active-property badges */}
|
|
972
|
+
<div className="sticky bottom-0 mt-4 -mx-6 -mb-6 px-6 py-3 bg-white/95 dark:bg-slate-900/95 backdrop-blur-sm border-t border-slate-200 dark:border-slate-700 flex items-center flex-wrap gap-1.5 text-[10px] font-mono">
|
|
973
|
+
<span className="text-[9px] uppercase tracking-wider font-bold text-slate-400 dark:text-slate-500 mr-1">Active:</span>
|
|
974
|
+
<span className="px-2 py-0.5 rounded-md bg-slate-900 text-white dark:bg-white dark:text-slate-900 font-semibold">cols:{columns}</span>
|
|
975
|
+
<span className="px-2 py-0.5 rounded-md bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-300">gap:{spacing}</span>
|
|
976
|
+
<span className="px-2 py-0.5 rounded-md bg-primary-100 dark:bg-primary-900/30 text-primary-700 dark:text-primary-300">md:{Math.floor(12 / columns)}</span>
|
|
977
|
+
</div>
|
|
226
978
|
</div>
|
|
227
979
|
}
|
|
228
980
|
controls={
|
|
229
981
|
<ITStack spacing={4}>
|
|
230
|
-
<ITSlider label="
|
|
231
|
-
<ITSlider label="Spacing" value={spacing} onChange={setSpacing} min={0} max={8} />
|
|
982
|
+
<ITSlider label="Columns" value={columns} onChange={setColumns} min={1} max={6} />
|
|
983
|
+
<ITSlider label="Spacing (0.25rem units)" value={spacing} onChange={setSpacing} min={0} max={8} />
|
|
232
984
|
</ITStack>
|
|
233
985
|
}
|
|
234
986
|
gallery={
|
|
235
|
-
<ITStack spacing={
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
<
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
987
|
+
<ITStack spacing={8}>
|
|
988
|
+
<GallerySection
|
|
989
|
+
title="Real UI cases"
|
|
990
|
+
subtitle="Production-ready layouts built with ITGrid"
|
|
991
|
+
>
|
|
992
|
+
<div className="grid grid-cols-1 lg:grid-cols-2 gap-5">
|
|
993
|
+
|
|
994
|
+
{/* 1. App dashboard — sidebar (3) + main (9) */}
|
|
995
|
+
<PatternCard
|
|
996
|
+
title="App dashboard"
|
|
997
|
+
desc="md=3 + md=9 → stacks on mobile"
|
|
998
|
+
code={GRID_PATTERN_CODES.appDashboard}
|
|
999
|
+
>
|
|
1000
|
+
<div className="rounded-xl border border-slate-200 dark:border-slate-700 overflow-hidden bg-white dark:bg-slate-900">
|
|
1001
|
+
<ITGrid container spacing={0}>
|
|
1002
|
+
<ITGrid item xs={12} md={3}>
|
|
1003
|
+
<div className="bg-slate-50 dark:bg-slate-800/50 px-4 py-5 border-r border-slate-200 dark:border-slate-700">
|
|
1004
|
+
<div className="flex items-center gap-2 mb-5">
|
|
1005
|
+
<div className="w-7 h-7 rounded-lg flex items-center justify-center text-white text-xs font-bold"
|
|
1006
|
+
style={{ background: 'linear-gradient(135deg, var(--color-primary-500) 0%, var(--color-primary-700) 100%)' }}
|
|
1007
|
+
>
|
|
1008
|
+
A
|
|
1009
|
+
</div>
|
|
1010
|
+
<p className="text-sm font-bold text-slate-800 dark:text-slate-100">Acme</p>
|
|
1011
|
+
</div>
|
|
1012
|
+
<div className="space-y-1">
|
|
1013
|
+
{[
|
|
1014
|
+
{ label: "Overview", active: true },
|
|
1015
|
+
{ label: "Projects", active: false },
|
|
1016
|
+
{ label: "Team", active: false },
|
|
1017
|
+
{ label: "Reports", active: false },
|
|
1018
|
+
{ label: "Settings", active: false },
|
|
1019
|
+
].map((item) => (
|
|
1020
|
+
<div
|
|
1021
|
+
key={item.label}
|
|
1022
|
+
className={`text-xs font-medium px-2.5 py-1.5 rounded-lg cursor-pointer transition-colors ${
|
|
1023
|
+
item.active
|
|
1024
|
+
? "bg-primary-100 dark:bg-primary-900/30 text-primary-700 dark:text-primary-300"
|
|
1025
|
+
: "text-slate-600 dark:text-slate-400 hover:bg-slate-100 dark:hover:bg-slate-700/50"
|
|
1026
|
+
}`}
|
|
1027
|
+
>
|
|
1028
|
+
{item.label}
|
|
1029
|
+
</div>
|
|
1030
|
+
))}
|
|
1031
|
+
</div>
|
|
1032
|
+
</div>
|
|
1033
|
+
</ITGrid>
|
|
1034
|
+
<ITGrid item xs={12} md={9}>
|
|
1035
|
+
<div className="p-4">
|
|
1036
|
+
<ITFlex direction="row" justify="between" align="center" className="mb-4">
|
|
1037
|
+
<div>
|
|
1038
|
+
<p className="text-base font-bold text-slate-800 dark:text-slate-100">Overview</p>
|
|
1039
|
+
<p className="text-[11px] text-slate-500 dark:text-slate-400">Last 30 days</p>
|
|
1040
|
+
</div>
|
|
1041
|
+
<ITButton label="+ New project" variant="filled" color="primary" size="small" />
|
|
1042
|
+
</ITFlex>
|
|
1043
|
+
<ITGrid container spacing={2}>
|
|
1044
|
+
{[
|
|
1045
|
+
{ label: "Revenue", value: "$48.2k", tone: "emerald" },
|
|
1046
|
+
{ label: "Active users", value: "2,847", tone: "primary" },
|
|
1047
|
+
{ label: "Pending tasks", value: "12", tone: "amber" },
|
|
1048
|
+
].map((s) => (
|
|
1049
|
+
<ITGrid key={s.label} item xs={12} sm={4}>
|
|
1050
|
+
<div className="rounded-lg border border-slate-200 dark:border-slate-700 p-3 bg-slate-50/50 dark:bg-slate-800/30">
|
|
1051
|
+
<p className="text-[10px] uppercase tracking-wider font-semibold text-slate-500 dark:text-slate-400">{s.label}</p>
|
|
1052
|
+
<p className="text-lg font-bold text-slate-800 dark:text-slate-100 font-mono mt-0.5">{s.value}</p>
|
|
1053
|
+
</div>
|
|
1054
|
+
</ITGrid>
|
|
1055
|
+
))}
|
|
1056
|
+
</ITGrid>
|
|
1057
|
+
</div>
|
|
1058
|
+
</ITGrid>
|
|
1059
|
+
</ITGrid>
|
|
267
1060
|
</div>
|
|
268
|
-
</
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
1061
|
+
</PatternCard>
|
|
1062
|
+
|
|
1063
|
+
{/* 2. User profile — avatar card (4) + activity (8) */}
|
|
1064
|
+
<PatternCard
|
|
1065
|
+
title="User profile"
|
|
1066
|
+
desc="md=4 + md=8 with nested activity"
|
|
1067
|
+
code={GRID_PATTERN_CODES.userProfile}
|
|
1068
|
+
>
|
|
1069
|
+
<div className="rounded-xl border border-slate-200 dark:border-slate-700 overflow-hidden bg-white dark:bg-slate-900">
|
|
1070
|
+
<ITGrid container spacing={0}>
|
|
1071
|
+
<ITGrid item xs={12} md={4}>
|
|
1072
|
+
<div className="bg-gradient-to-br from-primary-50 to-primary-100 dark:from-primary-900/30 dark:to-primary-800/20 p-5 border-r border-slate-200 dark:border-slate-700 text-center">
|
|
1073
|
+
<div className="w-20 h-20 mx-auto rounded-full flex items-center justify-center text-white text-2xl font-bold mb-3"
|
|
1074
|
+
style={{
|
|
1075
|
+
background: 'linear-gradient(135deg, var(--color-primary-500) 0%, var(--color-primary-700) 100%)',
|
|
1076
|
+
boxShadow: '0 8px 24px 0 rgba(59, 130, 246, 0.35)',
|
|
1077
|
+
}}
|
|
1078
|
+
>
|
|
1079
|
+
SC
|
|
1080
|
+
</div>
|
|
1081
|
+
<p className="text-sm font-bold text-slate-800 dark:text-slate-100">Sofía Castillo</p>
|
|
1082
|
+
<p className="text-[11px] text-slate-500 dark:text-slate-400">Product Designer</p>
|
|
1083
|
+
<div className="flex justify-center gap-2 mt-4">
|
|
1084
|
+
<span className="px-2 py-0.5 rounded-full text-[10px] font-semibold bg-primary-600 text-white">Design</span>
|
|
1085
|
+
<span className="px-2 py-0.5 rounded-full text-[10px] font-semibold bg-slate-200 dark:bg-slate-700 text-slate-600 dark:text-slate-300">Figma</span>
|
|
1086
|
+
</div>
|
|
1087
|
+
<ITButton label="Follow" variant="outlined" color="primary" size="small" className="mt-4 w-full" />
|
|
1088
|
+
</div>
|
|
1089
|
+
</ITGrid>
|
|
1090
|
+
<ITGrid item xs={12} md={8}>
|
|
1091
|
+
<div className="p-5">
|
|
1092
|
+
<p className="text-sm font-bold text-slate-800 dark:text-slate-100 mb-3">Recent activity</p>
|
|
1093
|
+
<ITStack spacing={3} divider={<div className="h-px bg-slate-100 dark:bg-slate-800" />}>
|
|
1094
|
+
{[
|
|
1095
|
+
{ action: "Shipped", target: "Onboarding redesign", time: "2h ago", color: "emerald" },
|
|
1096
|
+
{ action: "Reviewed PR", target: "#482 — Token system refactor", time: "Yesterday", color: "primary" },
|
|
1097
|
+
{ action: "Started", target: "Q1 design system audit", time: "3 days ago", color: "info" },
|
|
1098
|
+
].map((a) => (
|
|
1099
|
+
<div key={a.target} className="flex items-start gap-3 py-2">
|
|
1100
|
+
<span className={`w-2 h-2 rounded-full mt-1.5 shrink-0 ${
|
|
1101
|
+
a.color === "emerald" ? "bg-emerald-500" :
|
|
1102
|
+
a.color === "info" ? "bg-sky-500" :
|
|
1103
|
+
"bg-primary-500"
|
|
1104
|
+
}`} />
|
|
1105
|
+
<div className="flex-1 min-w-0">
|
|
1106
|
+
<p className="text-xs text-slate-700 dark:text-slate-200">
|
|
1107
|
+
<span className="font-semibold">{a.action}</span> <span className="text-slate-500 dark:text-slate-400">{a.target}</span>
|
|
1108
|
+
</p>
|
|
1109
|
+
<p className="text-[10px] text-slate-400 dark:text-slate-500 mt-0.5">{a.time}</p>
|
|
1110
|
+
</div>
|
|
1111
|
+
</div>
|
|
1112
|
+
))}
|
|
1113
|
+
</ITStack>
|
|
1114
|
+
</div>
|
|
1115
|
+
</ITGrid>
|
|
1116
|
+
</ITGrid>
|
|
273
1117
|
</div>
|
|
274
|
-
</
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
1118
|
+
</PatternCard>
|
|
1119
|
+
|
|
1120
|
+
{/* 3. Settings page — section nav (3) + form panels (9) */}
|
|
1121
|
+
<PatternCard
|
|
1122
|
+
title="Settings"
|
|
1123
|
+
desc="md=3 nav + md=9 form panels"
|
|
1124
|
+
code={GRID_PATTERN_CODES.settingsPage}
|
|
1125
|
+
>
|
|
1126
|
+
<div className="rounded-xl border border-slate-200 dark:border-slate-700 overflow-hidden bg-white dark:bg-slate-900">
|
|
1127
|
+
<ITGrid container spacing={0}>
|
|
1128
|
+
<ITGrid item xs={12} md={3}>
|
|
1129
|
+
<div className="px-4 py-5 border-r border-slate-200 dark:border-slate-700 space-y-1">
|
|
1130
|
+
{[
|
|
1131
|
+
{ label: "Profile", active: false },
|
|
1132
|
+
{ label: "Account", active: true },
|
|
1133
|
+
{ label: "Notifications", active: false },
|
|
1134
|
+
{ label: "Billing", active: false },
|
|
1135
|
+
{ label: "API keys", active: false },
|
|
1136
|
+
].map((s) => (
|
|
1137
|
+
<div
|
|
1138
|
+
key={s.label}
|
|
1139
|
+
className={`text-xs font-medium px-2.5 py-1.5 rounded-lg cursor-pointer ${
|
|
1140
|
+
s.active
|
|
1141
|
+
? "bg-slate-100 dark:bg-slate-800 text-slate-800 dark:text-slate-100"
|
|
1142
|
+
: "text-slate-500 dark:text-slate-400 hover:bg-slate-50 dark:hover:bg-slate-800/50"
|
|
1143
|
+
}`}
|
|
1144
|
+
>
|
|
1145
|
+
{s.label}
|
|
1146
|
+
</div>
|
|
1147
|
+
))}
|
|
1148
|
+
</div>
|
|
1149
|
+
</ITGrid>
|
|
1150
|
+
<ITGrid item xs={12} md={9}>
|
|
1151
|
+
<div className="p-5 space-y-4">
|
|
1152
|
+
<div>
|
|
1153
|
+
<p className="text-sm font-bold text-slate-800 dark:text-slate-100">Account</p>
|
|
1154
|
+
<p className="text-[11px] text-slate-500 dark:text-slate-400">Manage how your account appears and behaves.</p>
|
|
1155
|
+
</div>
|
|
1156
|
+
<ITGrid container spacing={3}>
|
|
1157
|
+
<ITGrid item xs={12} md={6}>
|
|
1158
|
+
<label className="text-[10px] font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 block mb-1">Username</label>
|
|
1159
|
+
<div className="h-9 rounded-lg border border-slate-200 dark:border-slate-600 bg-slate-50 dark:bg-slate-800/50 px-3 flex items-center text-sm text-slate-700 dark:text-slate-200">@sofia.castillo</div>
|
|
1160
|
+
</ITGrid>
|
|
1161
|
+
<ITGrid item xs={12} md={6}>
|
|
1162
|
+
<label className="text-[10px] font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 block mb-1">Email</label>
|
|
1163
|
+
<div className="h-9 rounded-lg border border-slate-200 dark:border-slate-600 bg-slate-50 dark:bg-slate-800/50 px-3 flex items-center text-sm text-slate-700 dark:text-slate-200">sofia@axzy.dev</div>
|
|
1164
|
+
</ITGrid>
|
|
1165
|
+
<ITGrid item xs={12}>
|
|
1166
|
+
<label className="text-[10px] font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400 block mb-1">Language</label>
|
|
1167
|
+
<div className="h-9 rounded-lg border border-slate-200 dark:border-slate-600 bg-slate-50 dark:bg-slate-800/50 px-3 flex items-center text-sm text-slate-700 dark:text-slate-200">English (US)</div>
|
|
1168
|
+
</ITGrid>
|
|
1169
|
+
</ITGrid>
|
|
1170
|
+
<div className="flex justify-end gap-2 pt-2 border-t border-slate-100 dark:border-slate-800">
|
|
1171
|
+
<ITButton label="Cancel" variant="outlined" color="gray" size="small" />
|
|
1172
|
+
<ITButton label="Save changes" variant="filled" color="primary" size="small" />
|
|
1173
|
+
</div>
|
|
1174
|
+
</div>
|
|
1175
|
+
</ITGrid>
|
|
1176
|
+
</ITGrid>
|
|
279
1177
|
</div>
|
|
280
|
-
</
|
|
281
|
-
|
|
282
|
-
|
|
1178
|
+
</PatternCard>
|
|
1179
|
+
|
|
1180
|
+
{/* 4. Article layout — body (8) + meta (4) */}
|
|
1181
|
+
<PatternCard
|
|
1182
|
+
title="Article layout"
|
|
1183
|
+
desc="md=8 body + md=4 sticky meta"
|
|
1184
|
+
code={GRID_PATTERN_CODES.articleLayout}
|
|
1185
|
+
>
|
|
1186
|
+
<div className="rounded-xl border border-slate-200 dark:border-slate-700 overflow-hidden bg-white dark:bg-slate-900">
|
|
1187
|
+
<ITGrid container spacing={0}>
|
|
1188
|
+
<ITGrid item xs={12} md={8} className="border-r border-slate-200 dark:border-slate-700">
|
|
1189
|
+
<article className="p-5">
|
|
1190
|
+
<span className="text-[10px] uppercase tracking-wider font-bold text-primary-600 dark:text-primary-400">Engineering</span>
|
|
1191
|
+
<h3 className="text-lg font-bold text-slate-800 dark:text-slate-100 mt-1.5 leading-tight">
|
|
1192
|
+
How we cut bundle size by 38% with route-level splitting
|
|
1193
|
+
</h3>
|
|
1194
|
+
<div className="flex items-center gap-2 mt-2 text-[11px] text-slate-500 dark:text-slate-400">
|
|
1195
|
+
<span>8 min read</span>
|
|
1196
|
+
<span>·</span>
|
|
1197
|
+
<span>Nov 14, 2025</span>
|
|
1198
|
+
</div>
|
|
1199
|
+
<p className="text-sm text-slate-600 dark:text-slate-300 mt-3 leading-relaxed">
|
|
1200
|
+
A few weeks ago we shipped lazy loading for all non-critical routes. The result was a 38% drop in our initial JS payload and a measurable improvement in time-to-interactive…
|
|
1201
|
+
</p>
|
|
1202
|
+
<p className="text-sm text-slate-600 dark:text-slate-300 mt-3 leading-relaxed">
|
|
1203
|
+
The strategy was simple: defer everything the user doesn't see on first paint, and split the rest by route. Below is what we measured.
|
|
1204
|
+
</p>
|
|
1205
|
+
</article>
|
|
1206
|
+
</ITGrid>
|
|
1207
|
+
<ITGrid item xs={12} md={4}>
|
|
1208
|
+
<div className="p-5 space-y-4 bg-slate-50/50 dark:bg-slate-800/30">
|
|
1209
|
+
<div>
|
|
1210
|
+
<p className="text-[10px] uppercase tracking-wider font-semibold text-slate-500 dark:text-slate-400 mb-2">Written by</p>
|
|
1211
|
+
<div className="flex items-center gap-2.5">
|
|
1212
|
+
<div className="w-9 h-9 rounded-full bg-emerald-100 dark:bg-emerald-900/30 flex items-center justify-center text-emerald-700 dark:text-emerald-300 text-xs font-bold">EM</div>
|
|
1213
|
+
<div>
|
|
1214
|
+
<p className="text-xs font-semibold text-slate-800 dark:text-slate-100">Elena Martínez</p>
|
|
1215
|
+
<p className="text-[10px] text-slate-500 dark:text-slate-400">Staff Engineer</p>
|
|
1216
|
+
</div>
|
|
1217
|
+
</div>
|
|
1218
|
+
</div>
|
|
1219
|
+
<div>
|
|
1220
|
+
<p className="text-[10px] uppercase tracking-wider font-semibold text-slate-500 dark:text-slate-400 mb-2">Tags</p>
|
|
1221
|
+
<div className="flex flex-wrap gap-1">
|
|
1222
|
+
{["Performance", "Webpack", "React"].map((t) => (
|
|
1223
|
+
<span key={t} className="px-2 py-0.5 rounded-md text-[10px] font-medium bg-slate-200 dark:bg-slate-700 text-slate-700 dark:text-slate-300">{t}</span>
|
|
1224
|
+
))}
|
|
1225
|
+
</div>
|
|
1226
|
+
</div>
|
|
1227
|
+
<ITButton label="Share article" variant="outlined" color="primary" size="small" className="w-full" />
|
|
1228
|
+
</div>
|
|
1229
|
+
</ITGrid>
|
|
1230
|
+
</ITGrid>
|
|
1231
|
+
</div>
|
|
1232
|
+
</PatternCard>
|
|
1233
|
+
|
|
1234
|
+
{/* 5. Pricing tiers — 3 equal columns */}
|
|
1235
|
+
<PatternCard
|
|
1236
|
+
title="Pricing comparison"
|
|
1237
|
+
desc="md=4 × 3 → comparison table"
|
|
1238
|
+
code={GRID_PATTERN_CODES.pricingTiers}
|
|
1239
|
+
>
|
|
1240
|
+
<div className="rounded-xl border border-slate-200 dark:border-slate-700 overflow-hidden bg-white dark:bg-slate-900 p-4">
|
|
1241
|
+
<ITGrid container spacing={3}>
|
|
1242
|
+
{[
|
|
1243
|
+
{
|
|
1244
|
+
name: "Starter",
|
|
1245
|
+
price: "$0",
|
|
1246
|
+
desc: "For personal projects",
|
|
1247
|
+
features: ["1 project", "Community support", "Basic analytics"],
|
|
1248
|
+
cta: "Get started",
|
|
1249
|
+
featured: false,
|
|
1250
|
+
},
|
|
1251
|
+
{
|
|
1252
|
+
name: "Pro",
|
|
1253
|
+
price: "$29",
|
|
1254
|
+
desc: "For growing teams",
|
|
1255
|
+
features: ["Unlimited projects", "Priority support", "Advanced analytics", "Custom domains"],
|
|
1256
|
+
cta: "Start trial",
|
|
1257
|
+
featured: true,
|
|
1258
|
+
},
|
|
1259
|
+
{
|
|
1260
|
+
name: "Enterprise",
|
|
1261
|
+
price: "Custom",
|
|
1262
|
+
desc: "For large organizations",
|
|
1263
|
+
features: ["SSO + SAML", "Dedicated CSM", "99.99% SLA", "Audit logs"],
|
|
1264
|
+
cta: "Contact sales",
|
|
1265
|
+
featured: false,
|
|
1266
|
+
},
|
|
1267
|
+
].map((plan) => (
|
|
1268
|
+
<ITGrid key={plan.name} item xs={12} md={4}>
|
|
1269
|
+
<div className={`h-full rounded-xl p-4 border ${
|
|
1270
|
+
plan.featured
|
|
1271
|
+
? "border-primary-400 dark:border-primary-600 bg-primary-50/50 dark:bg-primary-900/20"
|
|
1272
|
+
: "border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-900"
|
|
1273
|
+
}`}>
|
|
1274
|
+
{plan.featured && (
|
|
1275
|
+
<span className="inline-block px-2 py-0.5 rounded-full bg-primary-600 text-white text-[9px] font-bold uppercase tracking-wider mb-2">
|
|
1276
|
+
Most popular
|
|
1277
|
+
</span>
|
|
1278
|
+
)}
|
|
1279
|
+
<p className="text-sm font-bold text-slate-800 dark:text-slate-100">{plan.name}</p>
|
|
1280
|
+
<p className="text-[11px] text-slate-500 dark:text-slate-400">{plan.desc}</p>
|
|
1281
|
+
<p className="text-2xl font-extrabold text-slate-800 dark:text-slate-100 font-mono mt-3">
|
|
1282
|
+
{plan.price}
|
|
1283
|
+
{plan.price !== "Custom" && <span className="text-xs font-normal text-slate-500 dark:text-slate-400"> /mo</span>}
|
|
1284
|
+
</p>
|
|
1285
|
+
<ul className="mt-3 space-y-1.5">
|
|
1286
|
+
{plan.features.map((f) => (
|
|
1287
|
+
<li key={f} className="text-[11px] text-slate-600 dark:text-slate-300 flex items-start gap-1.5">
|
|
1288
|
+
<span className={`mt-0.5 shrink-0 ${plan.featured ? "text-primary-600 dark:text-primary-400" : "text-emerald-500"}`}>✓</span>
|
|
1289
|
+
<span>{f}</span>
|
|
1290
|
+
</li>
|
|
1291
|
+
))}
|
|
1292
|
+
</ul>
|
|
1293
|
+
<ITButton
|
|
1294
|
+
label={plan.cta}
|
|
1295
|
+
variant={plan.featured ? "filled" : "outlined"}
|
|
1296
|
+
color={plan.featured ? "primary" : "gray"}
|
|
1297
|
+
size="small"
|
|
1298
|
+
className="w-full mt-4"
|
|
1299
|
+
/>
|
|
1300
|
+
</div>
|
|
1301
|
+
</ITGrid>
|
|
1302
|
+
))}
|
|
1303
|
+
</ITGrid>
|
|
1304
|
+
</div>
|
|
1305
|
+
</PatternCard>
|
|
1306
|
+
</div>
|
|
1307
|
+
</GallerySection>
|
|
283
1308
|
</ITStack>
|
|
284
1309
|
}
|
|
285
1310
|
/>
|
|
@@ -456,44 +1481,52 @@ export const ScreenFormShowcase = () => {
|
|
|
456
1481
|
|
|
457
1482
|
<ITGrid container spacing={4}>
|
|
458
1483
|
<ITGrid item xs={12} md={6}>
|
|
459
|
-
<
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
1484
|
+
<ITInput
|
|
1485
|
+
name="nombre"
|
|
1486
|
+
label="Nombre"
|
|
1487
|
+
placeholder="Ej: Juan"
|
|
1488
|
+
onChange={() => {}}
|
|
1489
|
+
/>
|
|
463
1490
|
</ITGrid>
|
|
464
1491
|
<ITGrid item xs={12} md={6}>
|
|
465
|
-
<
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
1492
|
+
<ITInput
|
|
1493
|
+
name="apellido"
|
|
1494
|
+
label="Apellido"
|
|
1495
|
+
placeholder="Ej: Pérez"
|
|
1496
|
+
onChange={() => {}}
|
|
1497
|
+
/>
|
|
469
1498
|
</ITGrid>
|
|
470
1499
|
<ITGrid item xs={12}>
|
|
471
|
-
<
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
1500
|
+
<ITInput
|
|
1501
|
+
name="email"
|
|
1502
|
+
label="Email"
|
|
1503
|
+
placeholder="ej: usuario@correo.com"
|
|
1504
|
+
onChange={() => {}}
|
|
1505
|
+
/>
|
|
475
1506
|
</ITGrid>
|
|
476
1507
|
<ITGrid item xs={12} md={6}>
|
|
477
|
-
<
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
1508
|
+
<ITSelect
|
|
1509
|
+
name="rol"
|
|
1510
|
+
label="Rol"
|
|
1511
|
+
options={[
|
|
1512
|
+
{ label: "Seleccionar...", value: "" },
|
|
1513
|
+
{ label: "Admin", value: "admin" },
|
|
1514
|
+
{ label: "Editor", value: "editor" },
|
|
1515
|
+
{ label: "Usuario", value: "usuario" },
|
|
1516
|
+
]}
|
|
1517
|
+
/>
|
|
486
1518
|
</ITGrid>
|
|
487
1519
|
<ITGrid item xs={12} md={6}>
|
|
488
|
-
<
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
1520
|
+
<ITSelect
|
|
1521
|
+
name="departamento"
|
|
1522
|
+
label="Departamento"
|
|
1523
|
+
options={[
|
|
1524
|
+
{ label: "Seleccionar...", value: "" },
|
|
1525
|
+
{ label: "Ingeniería", value: "ingenieria" },
|
|
1526
|
+
{ label: "Diseño", value: "diseno" },
|
|
1527
|
+
{ label: "Ventas", value: "ventas" },
|
|
1528
|
+
]}
|
|
1529
|
+
/>
|
|
497
1530
|
</ITGrid>
|
|
498
1531
|
<ITGrid item xs={12}>
|
|
499
1532
|
<ITFlex justify="end" gap={3}>
|
|
@@ -510,60 +1543,3 @@ export const ScreenFormShowcase = () => {
|
|
|
510
1543
|
);
|
|
511
1544
|
};
|
|
512
1545
|
|
|
513
|
-
export const ScreenCardGridShowcase = () => {
|
|
514
|
-
const code = `// Grid de tarjetas 100% responsivo
|
|
515
|
-
<ITGrid container spacing={4}>
|
|
516
|
-
{products.map(product => (
|
|
517
|
-
<ITGrid item xs={12} sm={6} md={4} lg={3} key={product.id}>
|
|
518
|
-
<ITCard>
|
|
519
|
-
<img src={product.image} alt={product.name} />
|
|
520
|
-
<ITStack spacing={1}>
|
|
521
|
-
<h3 className="font-bold">{product.name}</h3>
|
|
522
|
-
<p className="text-sm text-slate-500">{product.price}</p>
|
|
523
|
-
<ITButton label="Ver más" fullWidth />
|
|
524
|
-
</ITStack>
|
|
525
|
-
</ITCard>
|
|
526
|
-
</ITGrid>
|
|
527
|
-
))}
|
|
528
|
-
</ITGrid>`;
|
|
529
|
-
|
|
530
|
-
return (
|
|
531
|
-
<ITCard title="Grid de Tarjetas Responsivo">
|
|
532
|
-
<ITStack spacing={4}>
|
|
533
|
-
<div>
|
|
534
|
-
<h2 className="text-xl font-bold text-slate-800 dark:text-white">Productos</h2>
|
|
535
|
-
<p className="text-xs text-slate-400">Galería responsiva que pasa de 1 columna en mobile a 4 columnas en desktop</p>
|
|
536
|
-
</div>
|
|
537
|
-
|
|
538
|
-
<ITGrid container spacing={4}>
|
|
539
|
-
{[
|
|
540
|
-
{ name: "Design Pro", color: "bg-blue-500" },
|
|
541
|
-
{ name: "Dev Kit", color: "bg-emerald-500" },
|
|
542
|
-
{ name: "UI Bundle", color: "bg-purple-500" },
|
|
543
|
-
{ name: "Analytics", color: "bg-amber-500" },
|
|
544
|
-
{ name: "Cloud Sync", color: "bg-rose-500" },
|
|
545
|
-
{ name: "Security+", color: "bg-cyan-500" },
|
|
546
|
-
{ name: "Data Viz", color: "bg-indigo-500" },
|
|
547
|
-
{ name: "API Hub", color: "bg-teal-500" },
|
|
548
|
-
].map((product, i) => (
|
|
549
|
-
<ITGrid key={i} item xs={12} sm={6} md={4} lg={3}>
|
|
550
|
-
<ITStack spacing={3} className="bg-white dark:bg-slate-800 rounded-xl border border-slate-200 dark:border-slate-700 p-4 hover:shadow-md transition-shadow">
|
|
551
|
-
<div className={`${product.color} h-24 rounded-lg flex items-center justify-center text-white text-2xl font-bold`}>
|
|
552
|
-
{product.name.charAt(0)}
|
|
553
|
-
</div>
|
|
554
|
-
<div>
|
|
555
|
-
<h3 className="font-bold text-slate-800 dark:text-white text-sm">{product.name}</h3>
|
|
556
|
-
<p className="text-xs text-slate-400 mt-0.5">A partir de $19.99/mes</p>
|
|
557
|
-
</div>
|
|
558
|
-
<ITButton label="Ver más" size="small" className="w-full" />
|
|
559
|
-
</ITStack>
|
|
560
|
-
</ITGrid>
|
|
561
|
-
))}
|
|
562
|
-
</ITGrid>
|
|
563
|
-
</ITStack>
|
|
564
|
-
<div className="mt-6">
|
|
565
|
-
<CodeViewer code={code} />
|
|
566
|
-
</div>
|
|
567
|
-
</ITCard>
|
|
568
|
-
);
|
|
569
|
-
};
|