@axzydev/axzy_ui_system 1.4.8 → 1.5.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/README.md +2 -11
- package/dist/index.cjs +1826 -1351
- 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 +115 -14
- package/dist/index.d.ts +115 -14
- package/dist/index.js +1481 -1010
- package/dist/index.js.map +1 -1
- package/dist/layered.css +1 -1
- package/package.json +3 -16
- package/src/App.tsx +90 -73
- package/src/components/atoms/badget/badget.tsx +23 -5
- package/src/components/atoms/chip/chip.tsx +3 -1
- package/src/components/atoms/image/image.tsx +3 -1
- package/src/components/atoms/input/input.tsx +8 -5
- package/src/components/atoms/loader/loader.tsx +3 -1
- package/src/components/atoms/slide/slide.props.ts +12 -0
- package/src/components/atoms/slide/slide.tsx +3 -0
- package/src/components/molecules/alert/alert.tsx +3 -1
- package/src/components/molecules/breadcrumbs/breadcrumbs.tsx +3 -1
- package/src/components/molecules/calendar/calendar.tsx +9 -6
- package/src/components/molecules/card/card.tsx +5 -2
- package/src/components/molecules/chip-input/chip-input.tsx +9 -7
- package/src/components/molecules/date-picker/datePicker.tsx +9 -9
- package/src/components/molecules/dropdown-menu/dropdown-menu.props.ts +1 -1
- package/src/components/molecules/dropdown-menu/dropdown-menu.tsx +6 -3
- package/src/components/molecules/field/field.tsx +3 -1
- package/src/components/molecules/form-header/form-header.tsx +3 -1
- package/src/components/molecules/line-bar-chart/line-bar-chart.props.ts +2 -2
- package/src/components/molecules/line-bar-chart/line-bar-chart.tsx +20 -15
- package/src/components/molecules/masked-input/masked-input.tsx +3 -1
- package/src/components/molecules/multi-select/multi-select.tsx +12 -9
- package/src/components/molecules/pagination/pagination.tsx +11 -5
- package/src/components/molecules/search-select/search-select.tsx +11 -9
- package/src/components/molecules/select/select.tsx +6 -4
- package/src/components/molecules/stepper/stepper.tsx +6 -4
- package/src/components/molecules/table/table.tsx +30 -28
- package/src/components/molecules/time-picker/timePicker.tsx +8 -6
- package/src/components/molecules/wysiwyg/wysiwyg.tsx +23 -12
- package/src/components/organisms/confirm-dialog/confirm-dialog.props.ts +4 -4
- package/src/components/organisms/confirm-dialog/confirm-dialog.tsx +16 -8
- package/src/components/organisms/data-table/dataTable.tsx +31 -25
- package/src/components/organisms/dialog/dialog.tsx +3 -0
- package/src/components/organisms/drawer/drawer.tsx +3 -0
- package/src/components/organisms/dropfile/dropfile.tsx +19 -17
- package/src/components/organisms/form-builder/fieldRenderer.tsx +4 -2
- package/src/components/organisms/navbar/navbar.tsx +4 -2
- package/src/components/organisms/page-header/page-header.tsx +3 -1
- package/src/components/organisms/searchTable/components/PaginationControls.tsx +8 -6
- package/src/components/organisms/searchTable/components/PaginationInfo.tsx +3 -1
- package/src/components/organisms/searchTable/components/SearchAndSortBar.tsx +7 -5
- package/src/components/organisms/searchTable/components/SearchInput.tsx +4 -2
- package/src/components/organisms/searchTable/components/SortButton.tsx +13 -11
- package/src/components/organisms/searchTable/components/TableEmptyState.tsx +4 -2
- package/src/components/organisms/searchTable/components/TableRow.tsx +6 -4
- package/src/components/organisms/searchTable/searchTable.tsx +4 -2
- package/src/components/organisms/sidebar/sidebar.props.ts +1 -1
- package/src/components/organisms/sidebar/sidebar.tsx +9 -4
- package/src/components/organisms/toast/toast.tsx +3 -1
- package/src/components/organisms/topbar/topbar.tsx +4 -2
- package/src/components/templates/page/page.props.ts +4 -4
- package/src/components/templates/page/page.tsx +6 -4
- package/src/components/theme-provider/themeProvider.tsx +28 -17
- package/src/dev.css +77 -2
- package/src/global.d.ts +10 -0
- package/src/i18n/context.ts +9 -0
- package/src/i18n/index.ts +22 -0
- package/src/i18n/locales/en.ts +163 -0
- package/src/i18n/locales/es.ts +165 -0
- package/src/i18n/provider.tsx +44 -0
- package/src/i18n/translator.ts +82 -0
- package/src/i18n/types.ts +54 -0
- package/src/i18n/useITTranslation.ts +20 -0
- package/src/index.css +0 -1
- package/src/index.ts +7 -1
- package/src/sandbox/LandingShowcase.tsx +224 -580
- package/src/sandbox/NotFoundShowcase.tsx +51 -36
- package/src/sandbox/TopbarSearch.tsx +6 -4
- package/src/sandbox/controls.tsx +180 -0
- package/src/sandbox/i18n.ts +1929 -0
- package/src/sandbox/icons.tsx +25 -0
- package/src/sandbox/locale.tsx +72 -0
- package/src/sandbox/ui.tsx +377 -0
- package/src/sandbox/useHashRoute.ts +46 -10
- package/src/showcases/DataShowcases.tsx +103 -87
- package/src/showcases/FeedbackShowcases.tsx +37 -30
- package/src/showcases/FormShowcases.tsx +302 -214
- package/src/showcases/GettingStartedShowcase.tsx +151 -145
- package/src/showcases/HelpShowcase.tsx +126 -128
- package/src/showcases/HomeShowcase.tsx +678 -482
- package/src/showcases/LayoutPrimitivesShowcases.tsx +129 -114
- package/src/showcases/NavigationShowcases.tsx +45 -37
- package/src/showcases/PageShowcases.tsx +171 -152
- package/src/showcases/ProductoDetalle.tsx +272 -129
- package/src/showcases/ShowcaseLayout.tsx +270 -216
- package/src/showcases/SizesShowcase.tsx +123 -64
- package/src/showcases/StructureShowcases.tsx +157 -131
- package/src/showcases/portfolioUi.tsx +153 -0
- package/src/showcases/techIcons.ts +3 -0
- package/src/utils/table.utils.ts +10 -2
- package/src/components/atoms/avatar/avatar.doc.mdx +0 -48
- package/src/components/atoms/avatar/avatar.stories.tsx +0 -64
- package/src/components/atoms/badget/badget.doc.mdx +0 -46
- package/src/components/atoms/badget/badget.stories.tsx +0 -75
- package/src/components/atoms/button/button.doc.mdx +0 -59
- package/src/components/atoms/button/button.stories.tsx +0 -173
- package/src/components/atoms/checkbox/checkbox.doc.mdx +0 -54
- package/src/components/atoms/checkbox/checkbox.stories.tsx +0 -53
- package/src/components/atoms/chip/chip.doc.mdx +0 -47
- package/src/components/atoms/chip/chip.stories.tsx +0 -64
- package/src/components/atoms/divider/divider.doc.mdx +0 -42
- package/src/components/atoms/divider/divider.stories.tsx +0 -33
- package/src/components/atoms/flex/flex.doc.mdx +0 -59
- package/src/components/atoms/flex/flex.stories.tsx +0 -70
- package/src/components/atoms/grid/grid.doc.mdx +0 -54
- package/src/components/atoms/grid/grid.stories.tsx +0 -71
- package/src/components/atoms/image/image.doc.mdx +0 -44
- package/src/components/atoms/image/image.stories.tsx +0 -48
- package/src/components/atoms/input/input.doc.mdx +0 -70
- package/src/components/atoms/input/input.stories.tsx +0 -113
- package/src/components/atoms/input-number/input-number.doc.mdx +0 -74
- package/src/components/atoms/input-number/input-number.stories.tsx +0 -111
- package/src/components/atoms/loader/loader.doc.mdx +0 -43
- package/src/components/atoms/loader/loader.stories.tsx +0 -104
- package/src/components/atoms/popover/popover.doc.mdx +0 -53
- package/src/components/atoms/popover/popover.stories.tsx +0 -24
- package/src/components/atoms/progress/progress.doc.mdx +0 -48
- package/src/components/atoms/progress/progress.stories.tsx +0 -39
- package/src/components/atoms/radio/radio.doc.mdx +0 -62
- package/src/components/atoms/radio/radio.stories.tsx +0 -48
- package/src/components/atoms/segmented-control/segmented-control.doc.mdx +0 -60
- package/src/components/atoms/segmented-control/segmented-control.stories.tsx +0 -62
- package/src/components/atoms/skeleton/skeleton.doc.mdx +0 -43
- package/src/components/atoms/skeleton/skeleton.stories.tsx +0 -29
- package/src/components/atoms/slide/slide.doc.mdx +0 -46
- package/src/components/atoms/slide/slide.stories.tsx +0 -120
- package/src/components/atoms/slider/slider.doc.mdx +0 -49
- package/src/components/atoms/slider/slider.stories.tsx +0 -29
- package/src/components/atoms/stack/stack.doc.mdx +0 -126
- package/src/components/atoms/stack/stack.stories.tsx +0 -283
- package/src/components/atoms/text/text.doc.mdx +0 -41
- package/src/components/atoms/text/text.stories.tsx +0 -66
- package/src/components/atoms/textarea/textarea.doc.mdx +0 -64
- package/src/components/atoms/textarea/textarea.stories.tsx +0 -26
- package/src/components/atoms/tooltip/tooltip.doc.mdx +0 -47
- package/src/components/atoms/tooltip/tooltip.stories.tsx +0 -19
- package/src/components/isolation/isolation.stories.tsx +0 -202
- package/src/components/molecules/accordion/accordion.doc.mdx +0 -47
- package/src/components/molecules/accordion/accordion.stories.tsx +0 -68
- package/src/components/molecules/alert/alert.doc.mdx +0 -48
- package/src/components/molecules/alert/alert.stories.tsx +0 -40
- package/src/components/molecules/breadcrumbs/breadcrumbs.doc.mdx +0 -57
- package/src/components/molecules/breadcrumbs/breadcrumbs.stories.tsx +0 -20
- package/src/components/molecules/calendar/calendar.doc.mdx +0 -76
- package/src/components/molecules/calendar/calendar.stories.tsx +0 -90
- package/src/components/molecules/card/card.doc.mdx +0 -54
- package/src/components/molecules/card/card.stories.tsx +0 -57
- package/src/components/molecules/chip-input/chip-input.doc.mdx +0 -44
- package/src/components/molecules/chip-input/chip-input.stories.tsx +0 -52
- package/src/components/molecules/date-picker/date-picker.doc.mdx +0 -65
- package/src/components/molecules/date-picker/date-picker.stories.tsx +0 -88
- package/src/components/molecules/dropdown-menu/dropdown-menu.doc.mdx +0 -46
- package/src/components/molecules/dropdown-menu/dropdown-menu.stories.tsx +0 -41
- package/src/components/molecules/empty-state/empty-state.doc.mdx +0 -50
- package/src/components/molecules/empty-state/empty-state.stories.tsx +0 -19
- package/src/components/molecules/field/field.doc.mdx +0 -43
- package/src/components/molecules/field/field.stories.tsx +0 -42
- package/src/components/molecules/form-header/form-header.doc.mdx +0 -38
- package/src/components/molecules/form-header/form-header.stories.tsx +0 -52
- package/src/components/molecules/masked-input/masked-input.doc.mdx +0 -78
- package/src/components/molecules/masked-input/masked-input.stories.tsx +0 -126
- package/src/components/molecules/multi-select/multi-select.doc.mdx +0 -55
- package/src/components/molecules/multi-select/multi-select.stories.tsx +0 -59
- package/src/components/molecules/pagination/pagination.doc.mdx +0 -62
- package/src/components/molecules/pagination/pagination.stories.tsx +0 -110
- package/src/components/molecules/search-select/search-select.doc.mdx +0 -77
- package/src/components/molecules/search-select/search-select.stories.tsx +0 -146
- package/src/components/molecules/select/select.doc.mdx +0 -75
- package/src/components/molecules/select/select.stories.tsx +0 -85
- package/src/components/molecules/stat-card/stat-card.doc.mdx +0 -48
- package/src/components/molecules/stat-card/stat-card.stories.tsx +0 -40
- package/src/components/molecules/stepper/stepper.doc.mdx +0 -54
- package/src/components/molecules/stepper/stepper.stories.tsx +0 -154
- package/src/components/molecules/table/table.doc.mdx +0 -140
- package/src/components/molecules/table/table.stories.tsx +0 -402
- package/src/components/molecules/tabs/tabs.doc.mdx +0 -52
- package/src/components/molecules/tabs/tabs.stories.tsx +0 -31
- package/src/components/molecules/time-picker/timePicker.doc.mdx +0 -68
- package/src/components/molecules/time-picker/timePicker.stories.tsx +0 -130
- package/src/components/molecules/wysiwyg/wysiwyg.stories.tsx +0 -95
- package/src/components/organisms/confirm-dialog/confirm-dialog.doc.mdx +0 -60
- package/src/components/organisms/confirm-dialog/confirm-dialog.stories.tsx +0 -32
- package/src/components/organisms/data-table/ITDataTable.doc.mdx +0 -132
- package/src/components/organisms/data-table/ITDataTable.stories.tsx +0 -353
- package/src/components/organisms/dialog/dialog.doc.mdx +0 -54
- package/src/components/organisms/dialog/dialog.stories.tsx +0 -126
- package/src/components/organisms/drawer/drawer.doc.mdx +0 -59
- package/src/components/organisms/drawer/drawer.stories.tsx +0 -40
- package/src/components/organisms/dropfile/dropfile.doc.mdx +0 -74
- package/src/components/organisms/dropfile/dropfile.stories.tsx +0 -93
- package/src/components/organisms/form-builder/formBuilder.doc.mdx +0 -251
- package/src/components/organisms/form-builder/formBuilder.stories.tsx +0 -914
- package/src/components/organisms/navbar/navbar.doc.mdx +0 -77
- package/src/components/organisms/navbar/navbar.stories.tsx +0 -83
- package/src/components/organisms/page-header/page-header.doc.mdx +0 -54
- package/src/components/organisms/page-header/page-header.stories.tsx +0 -74
- package/src/components/organisms/searchTable/searchTable.doc.mdx +0 -79
- package/src/components/organisms/searchTable/searchTable.stories.tsx +0 -73
- package/src/components/organisms/sidebar/sidebar.doc.mdx +0 -176
- package/src/components/organisms/sidebar/sidebar.stories.tsx +0 -234
- package/src/components/organisms/toast/toast.doc.mdx +0 -50
- package/src/components/organisms/toast/toast.stories.tsx +0 -137
- package/src/components/organisms/topbar/topbar.doc.mdx +0 -72
- package/src/components/organisms/topbar/topbar.stories.tsx +0 -79
- package/src/components/organisms/triple-filter/tripleFilter.doc.mdx +0 -62
- package/src/components/organisms/triple-filter/tripleFilter.stories.tsx +0 -31
- package/src/components/templates/layout/layout.doc.mdx +0 -53
- package/src/components/templates/layout/layout.stories.tsx +0 -113
- package/src/components/templates/page/page.doc.mdx +0 -86
- package/src/components/templates/page/page.stories.tsx +0 -97
- package/src/components/theme-provider/themeProvider.doc.mdx +0 -85
- package/src/components/theme-provider/themeProvider.stories.tsx +0 -58
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"packageManager": "pnpm@10.34.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"license": "MIT",
|
|
7
|
-
"version": "1.
|
|
7
|
+
"version": "1.5.0",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"sideEffects": [
|
|
10
10
|
"*.css"
|
|
@@ -38,12 +38,11 @@
|
|
|
38
38
|
"preview": "vite preview",
|
|
39
39
|
"bundle": "tsup src/index.ts && node scripts/build-css.mjs",
|
|
40
40
|
"watch": "tsup src/index.ts --watch",
|
|
41
|
-
"storybook": "storybook dev -p 6006",
|
|
42
|
-
"build-storybook": "storybook build",
|
|
43
41
|
"ext:catalog": "node vscode-extension/scripts/generate-catalog.mjs",
|
|
44
42
|
"ext:build": "node vscode-extension/esbuild.mjs",
|
|
45
43
|
"ext:typecheck": "tsc --noEmit -p vscode-extension/tsconfig.json",
|
|
46
|
-
"ext:package": "node vscode-extension/esbuild.mjs && cd vscode-extension && npx --yes @vscode/vsce package --no-dependencies"
|
|
44
|
+
"ext:package": "node vscode-extension/esbuild.mjs && cd vscode-extension && npx --yes @vscode/vsce package --no-dependencies",
|
|
45
|
+
"audit:sandbox": "node scripts/audit-sandbox.mjs"
|
|
47
46
|
},
|
|
48
47
|
"dependencies": {
|
|
49
48
|
"clsx": "^2.1.1",
|
|
@@ -75,18 +74,6 @@
|
|
|
75
74
|
"tailwindcss": "^4.0.0",
|
|
76
75
|
"tsup": "^8.3.6",
|
|
77
76
|
"vite-plugin-dts": "^4.5.0",
|
|
78
|
-
"storybook": "^10.2.0",
|
|
79
|
-
"@storybook/react-vite": "^10.2.0",
|
|
80
|
-
"@chromatic-com/storybook": "^5.0.0",
|
|
81
|
-
"@storybook/addon-vitest": "^10.2.0",
|
|
82
|
-
"@storybook/addon-a11y": "^10.2.0",
|
|
83
|
-
"@storybook/addon-docs": "^10.2.0",
|
|
84
|
-
"@storybook/addon-onboarding": "^10.2.0",
|
|
85
|
-
"eslint-plugin-storybook": "^10.2.0",
|
|
86
|
-
"vitest": "^4.0.18",
|
|
87
|
-
"playwright": "^1.58.0",
|
|
88
|
-
"@vitest/browser-playwright": "^4.0.18",
|
|
89
|
-
"@vitest/coverage-v8": "^4.0.18",
|
|
90
77
|
"@types/vscode": "1.85.0",
|
|
91
78
|
"esbuild": "^0.25.0"
|
|
92
79
|
}
|
package/src/App.tsx
CHANGED
|
@@ -1,18 +1,11 @@
|
|
|
1
1
|
import React, { useEffect, useMemo, useState } from "react";
|
|
2
|
-
import {
|
|
3
|
-
FaCreditCard,
|
|
4
|
-
FaHome,
|
|
5
|
-
FaKeyboard,
|
|
6
|
-
FaRegBell,
|
|
7
|
-
FaSlidersH,
|
|
8
|
-
FaTable,
|
|
9
|
-
} from "react-icons/fa";
|
|
10
|
-
import { ITLayout, ITThemeProvider, useDebouncedSearch } from "./index";
|
|
2
|
+
import { ITLayout, ITThemeProvider, ITI18nProvider, useITTranslation, useDebouncedSearch } from "./index";
|
|
11
3
|
import type { ITNavigationItem } from "./index";
|
|
12
|
-
import "./index.css";
|
|
13
4
|
|
|
14
5
|
// Import Showcases
|
|
15
6
|
import { HomeShowcase } from "./showcases/HomeShowcase";
|
|
7
|
+
import ProductoDetalle from "./showcases/ProductoDetalle";
|
|
8
|
+
import { PRODUCTOS } from "./showcases/productos";
|
|
16
9
|
import { GettingStartedShowcase } from "./showcases/GettingStartedShowcase";
|
|
17
10
|
import { HelpShowcase } from "./showcases/HelpShowcase";
|
|
18
11
|
import { SizesShowcase } from "./showcases/SizesShowcase";
|
|
@@ -82,18 +75,18 @@ import { useHashRoute } from "./sandbox/useHashRoute";
|
|
|
82
75
|
import TopbarSearch from "./sandbox/TopbarSearch";
|
|
83
76
|
import { LandingShowcase } from "./sandbox/LandingShowcase";
|
|
84
77
|
import NotFoundShowcase from "./sandbox/NotFoundShowcase";
|
|
78
|
+
import { sandboxMessages, translateLabel } from "./sandbox/i18n";
|
|
79
|
+
import { SandboxLocaleProvider, useSandboxLocale } from "./sandbox/locale";
|
|
80
|
+
import { SelectorIdioma, SelectorTema } from "./sandbox/controls";
|
|
81
|
+
import { GROUP_ICONS } from "./sandbox/icons";
|
|
85
82
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
feed: <FaRegBell />,
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
function App() {
|
|
83
|
+
/**
|
|
84
|
+
* Dev-only language switcher for the sandbox chrome. Lee el idioma del contexto
|
|
85
|
+
* compartido, así que el mismo control vive igual en la barra del sandbox y en
|
|
86
|
+
* la cabecera del portafolio.
|
|
87
|
+
*/
|
|
88
|
+
function AppShell() {
|
|
89
|
+
const { t } = useITTranslation();
|
|
97
90
|
const { route, goToItem, goToLanding, goToPortfolio } = useHashRoute();
|
|
98
91
|
const [subitemConnector] = useState<"dot" | "|" | "none">("dot");
|
|
99
92
|
|
|
@@ -127,13 +120,13 @@ function App() {
|
|
|
127
120
|
return SANDBOX_GROUPS.map((group) => {
|
|
128
121
|
const subitems = group.subitems.map((sub) => ({
|
|
129
122
|
id: sub.id,
|
|
130
|
-
label: sub.label,
|
|
123
|
+
label: translateLabel(sub.id, sub.label, t),
|
|
131
124
|
isActive: showroomActive === sub.id,
|
|
132
125
|
action: () => goToItem(group.id, sub.id),
|
|
133
126
|
}));
|
|
134
127
|
return {
|
|
135
128
|
id: group.id,
|
|
136
|
-
label: group.label,
|
|
129
|
+
label: translateLabel(group.id, group.label, t),
|
|
137
130
|
icon: GROUP_ICONS[group.id],
|
|
138
131
|
isActive: subitems.some((sub) => sub.isActive),
|
|
139
132
|
subitems,
|
|
@@ -143,22 +136,23 @@ function App() {
|
|
|
143
136
|
|
|
144
137
|
const flat: ITNavigationItem[] = [];
|
|
145
138
|
SANDBOX_GROUPS.forEach((group) => {
|
|
139
|
+
const groupLabel = translateLabel(group.id, group.label, t);
|
|
146
140
|
const groupMatches =
|
|
147
|
-
|
|
141
|
+
groupLabel.toLowerCase().includes(term) ||
|
|
148
142
|
group.id.toLowerCase().includes(term);
|
|
149
|
-
const groupBadge =
|
|
143
|
+
const groupBadge = groupLabel.split(" ")[0];
|
|
150
144
|
|
|
151
145
|
group.subitems
|
|
152
146
|
.filter(
|
|
153
147
|
(sub) =>
|
|
154
148
|
groupMatches ||
|
|
155
|
-
sub.label.toLowerCase().includes(term) ||
|
|
149
|
+
translateLabel(sub.id, sub.label, t).toLowerCase().includes(term) ||
|
|
156
150
|
sub.id.toLowerCase().includes(term),
|
|
157
151
|
)
|
|
158
152
|
.forEach((sub) => {
|
|
159
153
|
flat.push({
|
|
160
154
|
id: sub.id,
|
|
161
|
-
label: sub.label,
|
|
155
|
+
label: translateLabel(sub.id, sub.label, t),
|
|
162
156
|
icon: GROUP_ICONS[group.id],
|
|
163
157
|
badge: groupBadge,
|
|
164
158
|
isActive: showroomActive === sub.id,
|
|
@@ -167,7 +161,7 @@ function App() {
|
|
|
167
161
|
});
|
|
168
162
|
});
|
|
169
163
|
return flat;
|
|
170
|
-
}, [debouncedTerm, showroomActive, goToItem]);
|
|
164
|
+
}, [debouncedTerm, showroomActive, goToItem, t]);
|
|
171
165
|
|
|
172
166
|
// Sidebar is UNCONTROLLED: ITLayout's internal default is the 88px rail and the
|
|
173
167
|
// rail expands automatically on hover. No toggle button — the hover is the control.
|
|
@@ -188,18 +182,14 @@ function App() {
|
|
|
188
182
|
pending={searchValue.trim() !== debouncedTerm.trim()}
|
|
189
183
|
/>
|
|
190
184
|
),
|
|
191
|
-
// The topbar places `children` in its right area
|
|
185
|
+
// The topbar places `children` in its right area: los controles reales del
|
|
186
|
+
// chrome (idioma y tema). Antes había aquí una campana de notificaciones con
|
|
187
|
+
// un punto rojo que no llevaba a ninguna parte.
|
|
192
188
|
children: (
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
className="relative flex items-center justify-center p-2.5 rounded-xl transition-colors duration-200 hover:bg-[var(--it-topbar-user-hover,#f1f5f9)] focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary-400"
|
|
198
|
-
style={{ color: "var(--it-topbar-icon, #94a3b8)" }}
|
|
199
|
-
>
|
|
200
|
-
<FaRegBell className="w-5 h-5" aria-hidden="true" />
|
|
201
|
-
<span className="absolute top-1.5 right-1.5 w-2 h-2 rounded-full bg-red-500 ring-2 ring-white" />
|
|
202
|
-
</button>
|
|
189
|
+
<>
|
|
190
|
+
<SelectorIdioma />
|
|
191
|
+
<SelectorTema />
|
|
192
|
+
</>
|
|
203
193
|
),
|
|
204
194
|
navItems: [
|
|
205
195
|
{
|
|
@@ -209,7 +199,7 @@ function App() {
|
|
|
209
199
|
},
|
|
210
200
|
{
|
|
211
201
|
id: "portfolio",
|
|
212
|
-
label: "
|
|
202
|
+
label: t("sandbox.nav.portfolio"),
|
|
213
203
|
action: () => goToPortfolio(),
|
|
214
204
|
},
|
|
215
205
|
],
|
|
@@ -217,16 +207,8 @@ function App() {
|
|
|
217
207
|
if (id === "ui-system") goToLanding();
|
|
218
208
|
else if (id === "portfolio") goToPortfolio();
|
|
219
209
|
},
|
|
220
|
-
userMenu
|
|
221
|
-
|
|
222
|
-
userEmail: "alex@axzy.dev",
|
|
223
|
-
menuItems: [
|
|
224
|
-
{
|
|
225
|
-
label: "Ir al Portafolio",
|
|
226
|
-
onClick: () => goToPortfolio(),
|
|
227
|
-
},
|
|
228
|
-
],
|
|
229
|
-
},
|
|
210
|
+
// Sin `userMenu`: el sandbox no tiene sesión. Antes mostraba un usuario
|
|
211
|
+
// inventado ("Alex Dev / alex@axzy.dev") en un portafolio real.
|
|
230
212
|
};
|
|
231
213
|
|
|
232
214
|
// Render correct component based on active showroom navigation
|
|
@@ -340,31 +322,66 @@ function App() {
|
|
|
340
322
|
|
|
341
323
|
return (
|
|
342
324
|
<ITThemeProvider showFab={false} density={0.98} radius={10} shadow={2}>
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
325
|
+
{route.view === "producto" ? (
|
|
326
|
+
<div className="min-h-[100dvh] bg-[#fafafa] dark:bg-[#0b0d10]">
|
|
327
|
+
{route.valid ? (
|
|
328
|
+
<ProductoDetalle
|
|
329
|
+
producto={PRODUCTOS.find((producto) => producto.id === route.producto)!}
|
|
330
|
+
onBack={() => goToPortfolio()}
|
|
331
|
+
/>
|
|
332
|
+
) : (
|
|
333
|
+
<NotFoundShowcase
|
|
334
|
+
attempted={route.raw}
|
|
335
|
+
onGoLanding={() => goToLanding()}
|
|
336
|
+
onGoPortfolio={goToPortfolio}
|
|
337
|
+
/>
|
|
338
|
+
)}
|
|
339
|
+
</div>
|
|
340
|
+
) : route.view === "home" ? (
|
|
341
|
+
<div className="min-h-[100dvh] bg-[#fafafa] dark:bg-[#0b0d10]">
|
|
346
342
|
<HomeShowcase />
|
|
347
343
|
</div>
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
344
|
+
) : (
|
|
345
|
+
<ITLayout sidebar={sidebarProps} topBar={topBarProps}>
|
|
346
|
+
{!route.valid ? (
|
|
347
|
+
<NotFoundShowcase
|
|
348
|
+
attempted={route.raw}
|
|
349
|
+
onGoLanding={() => goToLanding()}
|
|
350
|
+
onGoPortfolio={goToPortfolio}
|
|
351
|
+
/>
|
|
352
|
+
) : !route.group && !route.item ? (
|
|
353
|
+
<LandingShowcase
|
|
354
|
+
onOpenItem={goToItem}
|
|
355
|
+
onOpenPortfolio={goToPortfolio}
|
|
356
|
+
/>
|
|
357
|
+
) : (
|
|
358
|
+
renderShowcase(showroomActive)
|
|
359
|
+
)}
|
|
360
|
+
</ITLayout>
|
|
361
|
+
)}
|
|
362
|
+
</ITThemeProvider>
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Sandbox root: el idioma vive en `SandboxLocaleProvider` (compartido con el
|
|
368
|
+
* portafolio) y `ITI18nProvider` lo aplica a todo el showroom.
|
|
369
|
+
*/
|
|
370
|
+
function SandboxI18n() {
|
|
371
|
+
const { locale } = useSandboxLocale();
|
|
372
|
+
|
|
373
|
+
return (
|
|
374
|
+
<ITI18nProvider locale={locale} messages={sandboxMessages}>
|
|
375
|
+
<AppShell />
|
|
376
|
+
</ITI18nProvider>
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
function App() {
|
|
381
|
+
return (
|
|
382
|
+
<SandboxLocaleProvider>
|
|
383
|
+
<SandboxI18n />
|
|
384
|
+
</SandboxLocaleProvider>
|
|
368
385
|
);
|
|
369
386
|
}
|
|
370
387
|
|
|
@@ -30,6 +30,19 @@ export default function ITBadget({
|
|
|
30
30
|
const themeBadge = (theme as any).badge || {};
|
|
31
31
|
const config = themeBadge[color] || themeBadge.primary || {};
|
|
32
32
|
|
|
33
|
+
/**
|
|
34
|
+
* El acento base de la paleta (`--color-primary`, cian por defecto) queda en
|
|
35
|
+
* 2.4:1 con texto blanco y 3.3:1 como texto sobre blanco. Para `primary` el
|
|
36
|
+
* color se resuelve con utilidades (`primary-700` en claro, `primary-500` en
|
|
37
|
+
* oscuro) que sí pasan AA; el resto de colores del tema se respetan tal cual.
|
|
38
|
+
*/
|
|
39
|
+
const esAcentoPrimario = color === "primary";
|
|
40
|
+
const claseAcento = esAcentoPrimario
|
|
41
|
+
? variant === "filled"
|
|
42
|
+
? "bg-primary-700 text-white dark:bg-primary-500 dark:text-slate-950"
|
|
43
|
+
: "border-primary-700 text-primary-700 dark:border-primary-500 dark:text-primary-500"
|
|
44
|
+
: "";
|
|
45
|
+
|
|
33
46
|
const getStyle = () => {
|
|
34
47
|
const style: React.CSSProperties = {
|
|
35
48
|
fontWeight: config.fontWeight,
|
|
@@ -41,14 +54,18 @@ export default function ITBadget({
|
|
|
41
54
|
};
|
|
42
55
|
|
|
43
56
|
if (variant === "filled") {
|
|
44
|
-
|
|
45
|
-
|
|
57
|
+
if (!esAcentoPrimario) {
|
|
58
|
+
style.backgroundColor = config.backgroundColor;
|
|
59
|
+
style.color = config.color;
|
|
60
|
+
}
|
|
46
61
|
style.borderColor = config.borderColor || 'transparent'; // Some filled badges might have subtle borders
|
|
47
62
|
} else if (variant === "outlined") {
|
|
48
63
|
style.backgroundColor = "transparent";
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
64
|
+
if (!esAcentoPrimario) {
|
|
65
|
+
// El tono del tema para texto y borde: legible sobre cualquier superficie.
|
|
66
|
+
style.color = config.color;
|
|
67
|
+
style.borderColor = config.color;
|
|
68
|
+
}
|
|
52
69
|
}
|
|
53
70
|
|
|
54
71
|
return style;
|
|
@@ -57,6 +74,7 @@ export default function ITBadget({
|
|
|
57
74
|
return (
|
|
58
75
|
<span
|
|
59
76
|
className={clsx(
|
|
77
|
+
claseAcento,
|
|
60
78
|
"inline-flex items-center justify-center",
|
|
61
79
|
// Apply size classes (padding/font-size)
|
|
62
80
|
badgeSizes[size],
|
|
@@ -4,6 +4,7 @@ import { chipSizes } from "@/types/chip.types";
|
|
|
4
4
|
import { theme } from "@/theme/theme";
|
|
5
5
|
import { FaTimes } from "react-icons/fa";
|
|
6
6
|
import ITText from "@/components/atoms/text/text";
|
|
7
|
+
import { useITTranslation } from "@/i18n";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Compact tag / pill used for labels, active filters, and multi-value selections.
|
|
@@ -63,6 +64,7 @@ export default function ITChip({
|
|
|
63
64
|
style.borderColor = palette[500];
|
|
64
65
|
}
|
|
65
66
|
|
|
67
|
+
const { t } = useITTranslation();
|
|
66
68
|
const interactive = Boolean(onClick) && !disabled;
|
|
67
69
|
|
|
68
70
|
return (
|
|
@@ -96,7 +98,7 @@ export default function ITChip({
|
|
|
96
98
|
{removable && (
|
|
97
99
|
<button
|
|
98
100
|
type="button"
|
|
99
|
-
aria-label={label ?
|
|
101
|
+
aria-label={label ? t("chip.remove", { label }) : t("chip.remove", { label: "" }).trim()}
|
|
100
102
|
disabled={disabled}
|
|
101
103
|
onClick={(e) => {
|
|
102
104
|
e.stopPropagation();
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useState } from "react";
|
|
2
2
|
import { ITImageProps } from "./image.props";
|
|
3
|
+
import { useITTranslation } from "@/i18n";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Image component with automatic fallback on load error.
|
|
@@ -27,6 +28,7 @@ const ITImage = ({
|
|
|
27
28
|
fallback = "",
|
|
28
29
|
}: ITImageProps) => {
|
|
29
30
|
const [imageError, setImageError] = useState(false);
|
|
31
|
+
const { t } = useITTranslation();
|
|
30
32
|
|
|
31
33
|
const handleImageError = () => {
|
|
32
34
|
setImageError(true);
|
|
@@ -39,7 +41,7 @@ const ITImage = ({
|
|
|
39
41
|
{imageError ? (
|
|
40
42
|
<img
|
|
41
43
|
src={fallback}
|
|
42
|
-
alt="
|
|
44
|
+
alt={t("image.fallbackAlt")}
|
|
43
45
|
className="w-full h-full object-cover"
|
|
44
46
|
/>
|
|
45
47
|
) : (
|
|
@@ -5,6 +5,7 @@ import { KeyboardEvent, useState, useEffect, useRef, useCallback } from "react";
|
|
|
5
5
|
import { theme } from "@/theme/theme";
|
|
6
6
|
import { disabledOverlay, iconAbsoluteLeft, iconAbsoluteRight, inputError, inputLabel, inputFieldStyle } from "@/utils/styles";
|
|
7
7
|
import ITText from "@/components/atoms/text/text";
|
|
8
|
+
import { useITTranslation } from "@/i18n";
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Text input component with label, validation error display, icon slots,
|
|
@@ -69,6 +70,7 @@ export default function ITInput({
|
|
|
69
70
|
size = "md",
|
|
70
71
|
decimals
|
|
71
72
|
}: ITInputProps) {
|
|
73
|
+
const { t, formatNumber: formatNumberLocale } = useITTranslation();
|
|
72
74
|
const isCheckboxOrRadio = type === "checkbox" || type === "radio";
|
|
73
75
|
const isNumberType = type === "number";
|
|
74
76
|
const isTextArea = type === "textarea";
|
|
@@ -120,11 +122,11 @@ export default function ITInput({
|
|
|
120
122
|
: (value === undefined || value === null || String(value).trim() === "");
|
|
121
123
|
|
|
122
124
|
const effectiveError = error !== undefined && error !== false
|
|
123
|
-
? (error === true ? "
|
|
124
|
-
: (required && isEmpty ? "
|
|
125
|
+
? (error === true ? t("field.required") : error)
|
|
126
|
+
: (required && isEmpty ? t("field.required") : undefined);
|
|
125
127
|
|
|
126
128
|
const hasError = isTouched && !!effectiveError;
|
|
127
|
-
const errorMessage = typeof effectiveError === "string" ? effectiveError : "
|
|
129
|
+
const errorMessage = typeof effectiveError === "string" ? effectiveError : t("field.required");
|
|
128
130
|
|
|
129
131
|
|
|
130
132
|
const handleClick = (e: React.MouseEvent<HTMLInputElement>) => {
|
|
@@ -148,7 +150,7 @@ export default function ITInput({
|
|
|
148
150
|
}
|
|
149
151
|
|
|
150
152
|
if (currencyFormat) {
|
|
151
|
-
return num
|
|
153
|
+
return formatNumberLocale(num, {
|
|
152
154
|
minimumFractionDigits: decimalPlaces,
|
|
153
155
|
maximumFractionDigits: decimalPlaces,
|
|
154
156
|
});
|
|
@@ -160,7 +162,7 @@ export default function ITInput({
|
|
|
160
162
|
|
|
161
163
|
return num.toString();
|
|
162
164
|
},
|
|
163
|
-
[currencyFormat, decimalPlaces]
|
|
165
|
+
[currencyFormat, decimalPlaces, formatNumberLocale]
|
|
164
166
|
);
|
|
165
167
|
|
|
166
168
|
const unformatValue = useCallback(
|
|
@@ -594,6 +596,7 @@ const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {
|
|
|
594
596
|
type="button"
|
|
595
597
|
className="absolute inset-y-0 right-0 flex items-center pr-3 z-10 text-secondary-400 hover:text-secondary-600 focus:outline-none"
|
|
596
598
|
onClick={() => setShowPassword(!showPassword)}
|
|
599
|
+
aria-label={showPassword ? t("input.hidePassword") : t("input.showPassword")}
|
|
597
600
|
tabIndex={-1} // Don't allow tabbing into the eye icon
|
|
598
601
|
>
|
|
599
602
|
{showPassword ? (
|
|
@@ -2,6 +2,7 @@ import { theme } from "@/theme/theme";
|
|
|
2
2
|
import { LoaderSize, sizeClasses } from "@/types/loader.types";
|
|
3
3
|
import { LoaderProps } from "./loader.props";
|
|
4
4
|
import ITText from "@/components/atoms/text/text";
|
|
5
|
+
import { useITTranslation } from "@/i18n";
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Loading indicators with multiple animation types: spinner, dots, pulse,
|
|
@@ -26,6 +27,7 @@ export default function ITLoader({
|
|
|
26
27
|
color = "primary", // Default to semantic primary
|
|
27
28
|
className = "",
|
|
28
29
|
}: LoaderProps) {
|
|
30
|
+
const { t } = useITTranslation();
|
|
29
31
|
|
|
30
32
|
// Resolve color: Check if it's a semantic color in theme, otherwise use as-is
|
|
31
33
|
const isSemantic = color in theme.colors;
|
|
@@ -51,7 +53,7 @@ export default function ITLoader({
|
|
|
51
53
|
style={style}
|
|
52
54
|
>
|
|
53
55
|
<ITText as="span" className="!absolute !-m-px !h-px !w-px !overflow-hidden !whitespace-nowrap !border-0 !p-0 ![clip:rect(0,0,0,0)]">
|
|
54
|
-
|
|
56
|
+
{t("common.loading")}
|
|
55
57
|
</ITText>
|
|
56
58
|
</div>
|
|
57
59
|
);
|
|
@@ -27,6 +27,18 @@ export interface ITSlideToggleProps {
|
|
|
27
27
|
/** Size of the switch: "sm" | "md" | "lg". Default: "md". */
|
|
28
28
|
size?: "sm" | "md" | "lg";
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Texto visible del interruptor. Se asocia al control como nombre accesible
|
|
32
|
+
* (`aria-label`) cuando no hay un `<label>` externo que lo nombre.
|
|
33
|
+
*/
|
|
34
|
+
label?: string;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Nombre accesible cuando la etiqueta visible vive fuera del componente.
|
|
38
|
+
* Tiene prioridad sobre `label`.
|
|
39
|
+
*/
|
|
40
|
+
ariaLabel?: string;
|
|
41
|
+
|
|
30
42
|
/** Additional CSS classes on the container. */
|
|
31
43
|
className?: string;
|
|
32
44
|
}
|
|
@@ -24,6 +24,8 @@ export default function ITSlideToggle({
|
|
|
24
24
|
inactiveColor = "#9ca3af", // default gray-400
|
|
25
25
|
disabled = false,
|
|
26
26
|
size = "md",
|
|
27
|
+
label,
|
|
28
|
+
ariaLabel,
|
|
27
29
|
className = "",
|
|
28
30
|
}: ITSlideToggleProps) {
|
|
29
31
|
// Handle internal state if not controlled
|
|
@@ -98,6 +100,7 @@ export default function ITSlideToggle({
|
|
|
98
100
|
style={{ backgroundColor }}
|
|
99
101
|
role="switch"
|
|
100
102
|
aria-checked={isOn}
|
|
103
|
+
aria-label={ariaLabel ?? label}
|
|
101
104
|
tabIndex={disabled ? -1 : 0}
|
|
102
105
|
onKeyDown={(e) => {
|
|
103
106
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
@@ -2,6 +2,7 @@ import clsx from "clsx";
|
|
|
2
2
|
import { ITAlertProps, AlertVariant } from "./alert.props";
|
|
3
3
|
import { FaInfoCircle, FaCheckCircle, FaExclamationTriangle, FaTimesCircle, FaTimes } from "react-icons/fa";
|
|
4
4
|
import ITText from "@/components/atoms/text/text";
|
|
5
|
+
import { useITTranslation } from "@/i18n";
|
|
5
6
|
|
|
6
7
|
const config: Record<AlertVariant, { icon: React.ReactNode; classes: string }> = {
|
|
7
8
|
info: {
|
|
@@ -39,6 +40,7 @@ export default function ITAlert({
|
|
|
39
40
|
icon,
|
|
40
41
|
className,
|
|
41
42
|
}: ITAlertProps) {
|
|
43
|
+
const { t } = useITTranslation();
|
|
42
44
|
const cfg = config[variant];
|
|
43
45
|
return (
|
|
44
46
|
<div
|
|
@@ -51,7 +53,7 @@ export default function ITAlert({
|
|
|
51
53
|
{children && <ITText as="div" className="text-sm opacity-90">{children}</ITText>}
|
|
52
54
|
</div>
|
|
53
55
|
{dismissible && onDismiss && (
|
|
54
|
-
<button onClick={onDismiss} className="flex-shrink-0 opacity-60 hover:opacity-100 transition-opacity">
|
|
56
|
+
<button onClick={onDismiss} className="flex-shrink-0 opacity-60 hover:opacity-100 transition-opacity" aria-label={t("common.dismiss")}>
|
|
55
57
|
<FaTimes size={12} />
|
|
56
58
|
</button>
|
|
57
59
|
)}
|
|
@@ -2,6 +2,7 @@ import clsx from "clsx";
|
|
|
2
2
|
import { ITBreadcrumbsProps } from "./breadcrumbs.props";
|
|
3
3
|
import { FaChevronRight } from "react-icons/fa";
|
|
4
4
|
import ITText from "@/components/atoms/text/text";
|
|
5
|
+
import { useITTranslation } from "@/i18n";
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Navigation breadcrumb trail with automatic link/button rendering and custom separator.
|
|
@@ -20,8 +21,9 @@ export default function ITBreadcrumbs({
|
|
|
20
21
|
separator = <FaChevronRight size={10} />,
|
|
21
22
|
className,
|
|
22
23
|
}: ITBreadcrumbsProps) {
|
|
24
|
+
const { t } = useITTranslation();
|
|
23
25
|
return (
|
|
24
|
-
<nav className={clsx("flex items-center gap-1.5 text-sm", className)} aria-label="
|
|
26
|
+
<nav className={clsx("flex items-center gap-1.5 text-sm", className)} aria-label={t("breadcrumbs.aria")}>
|
|
25
27
|
{items.map((item, i) => {
|
|
26
28
|
const isLast = i === items.length - 1;
|
|
27
29
|
return (
|
|
@@ -18,12 +18,12 @@ import {
|
|
|
18
18
|
isBefore,
|
|
19
19
|
isAfter
|
|
20
20
|
} from 'date-fns';
|
|
21
|
-
import { es } from 'date-fns/locale';
|
|
22
21
|
import { clsx, type ClassValue } from 'clsx';
|
|
23
22
|
import { twMerge } from 'tailwind-merge';
|
|
24
23
|
import { FaChevronLeft, FaChevronRight } from 'react-icons/fa';
|
|
25
24
|
import { ITCalendarProps, CalendarEvent } from './calendar.props';
|
|
26
25
|
import ITText from "@/components/atoms/text/text";
|
|
26
|
+
import { useITTranslation } from "@/i18n";
|
|
27
27
|
|
|
28
28
|
function cn(...inputs: ClassValue[]) {
|
|
29
29
|
return twMerge(clsx(inputs));
|
|
@@ -74,6 +74,7 @@ export const ITCalendar: React.FC<ITCalendarProps> = ({
|
|
|
74
74
|
className,
|
|
75
75
|
variant = 'primary',
|
|
76
76
|
}) => {
|
|
77
|
+
const { t, dateLocale } = useITTranslation();
|
|
77
78
|
// Determine mode: if onChange provided, assume picker (month) unless specialized
|
|
78
79
|
const mode = modeProp || (onChange ? 'month' : 'week');
|
|
79
80
|
|
|
@@ -326,7 +327,7 @@ export const ITCalendar: React.FC<ITCalendarProps> = ({
|
|
|
326
327
|
e.currentTarget.style.backgroundColor = 'transparent';
|
|
327
328
|
}}
|
|
328
329
|
>
|
|
329
|
-
{format(currentDate, 'MMMM', { locale:
|
|
330
|
+
{format(currentDate, 'MMMM', { locale: dateLocale })}
|
|
330
331
|
</button>
|
|
331
332
|
)}
|
|
332
333
|
<button
|
|
@@ -364,7 +365,7 @@ export const ITCalendar: React.FC<ITCalendarProps> = ({
|
|
|
364
365
|
onMouseEnter={(e) => { e.currentTarget.style.backgroundColor = 'var(--it-calendar-header-hover, #f1f5f9)'; }}
|
|
365
366
|
onMouseLeave={(e) => { e.currentTarget.style.backgroundColor = 'transparent'; }}
|
|
366
367
|
>
|
|
367
|
-
<ITText as="span">
|
|
368
|
+
<ITText as="span">{t("calendar.today")}</ITText>
|
|
368
369
|
</button>
|
|
369
370
|
<button
|
|
370
371
|
onClick={handleNext}
|
|
@@ -437,7 +438,7 @@ export const ITCalendar: React.FC<ITCalendarProps> = ({
|
|
|
437
438
|
onClick={() => pickMonth(monthIndex)}
|
|
438
439
|
>
|
|
439
440
|
<ITText as="span" className="capitalize">
|
|
440
|
-
{format(new Date(2000, monthIndex, 1), 'MMM', { locale:
|
|
441
|
+
{format(new Date(2000, monthIndex, 1), 'MMM', { locale: dateLocale })}
|
|
441
442
|
</ITText>
|
|
442
443
|
</button>
|
|
443
444
|
);
|
|
@@ -447,7 +448,9 @@ export const ITCalendar: React.FC<ITCalendarProps> = ({
|
|
|
447
448
|
<div className="p-4">
|
|
448
449
|
{/* Weekday Headers */}
|
|
449
450
|
<div className="grid grid-cols-7 mb-2">
|
|
450
|
-
{
|
|
451
|
+
{Array.from({ length: 7 }, (_, i) =>
|
|
452
|
+
format(addDays(startOfWeek(currentDate, { weekStartsOn: 1 }), i), 'EEE', { locale: dateLocale })
|
|
453
|
+
).map(day => (
|
|
451
454
|
<ITText key={day} as="div" className="text-center text-xs font-semibold text-secondary-400 uppercase py-1">
|
|
452
455
|
{day}
|
|
453
456
|
</ITText>
|
|
@@ -554,7 +557,7 @@ export const ITCalendar: React.FC<ITCalendarProps> = ({
|
|
|
554
557
|
opacity: isToday(day) ? 1 : 0.6,
|
|
555
558
|
}}
|
|
556
559
|
>
|
|
557
|
-
{format(day, 'EEE', { locale:
|
|
560
|
+
{format(day, 'EEE', { locale: dateLocale })}
|
|
558
561
|
</ITText>
|
|
559
562
|
<ITText
|
|
560
563
|
as="span"
|
|
@@ -3,6 +3,7 @@ import { ITCardProps } from "./card.props";
|
|
|
3
3
|
import { useState } from "react";
|
|
4
4
|
import ITText from "@/components/atoms/text/text";
|
|
5
5
|
import { useITFlatAppearance } from "@/theme/theme-context";
|
|
6
|
+
import { useITTranslation } from "@/i18n";
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Versatile card container with optional image, title, body content, and action footer. Supports interactive hover states.
|
|
@@ -20,7 +21,7 @@ import { useITFlatAppearance } from "@/theme/theme-context";
|
|
|
20
21
|
export default function ITCard({
|
|
21
22
|
title,
|
|
22
23
|
image,
|
|
23
|
-
alt
|
|
24
|
+
alt,
|
|
24
25
|
children,
|
|
25
26
|
actions,
|
|
26
27
|
className,
|
|
@@ -30,8 +31,10 @@ export default function ITCard({
|
|
|
30
31
|
actionClassName,
|
|
31
32
|
onClick,
|
|
32
33
|
}: ITCardProps) {
|
|
34
|
+
const { t } = useITTranslation();
|
|
33
35
|
const [isHovered, setIsHovered] = useState(false);
|
|
34
36
|
const flat = useITFlatAppearance();
|
|
37
|
+
const resolvedAlt = alt ?? t("card.imageAlt");
|
|
35
38
|
|
|
36
39
|
const containerStyle: React.CSSProperties = {
|
|
37
40
|
backgroundColor: "var(--it-card-bg, #ffffff)",
|
|
@@ -76,7 +79,7 @@ export default function ITCard({
|
|
|
76
79
|
{image && (
|
|
77
80
|
<img
|
|
78
81
|
src={image}
|
|
79
|
-
alt={
|
|
82
|
+
alt={resolvedAlt}
|
|
80
83
|
className={clsx("w-full h-48 object-cover", imageClassName)}
|
|
81
84
|
/>
|
|
82
85
|
)}
|