@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
|
@@ -6,6 +6,7 @@ import ITText from "@/components/atoms/text/text";
|
|
|
6
6
|
import ITButton from "@/components/atoms/button/button";
|
|
7
7
|
import ITDialog from "@/components/organisms/dialog/dialog";
|
|
8
8
|
import { ITDropfileProps, FileTypeEnum, UploadStatus } from "./dropfile.props";
|
|
9
|
+
import { useITTranslation } from "@/i18n";
|
|
9
10
|
export { FileTypeEnum, UploadStatus } from "./dropfile.props";
|
|
10
11
|
|
|
11
12
|
/**
|
|
@@ -50,9 +51,10 @@ const ITDropfile: React.FC<ITDropfileProps> = ({
|
|
|
50
51
|
onStatusChange,
|
|
51
52
|
initialPreviewUrl,
|
|
52
53
|
view = "drop",
|
|
53
|
-
buttonLabel
|
|
54
|
+
buttonLabel,
|
|
54
55
|
modalTitle,
|
|
55
56
|
}) => {
|
|
57
|
+
const { t } = useITTranslation();
|
|
56
58
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
57
59
|
const [selectedFile, setSelectedFile] = useState<File | null>(null);
|
|
58
60
|
const [fileType, setFileType] = useState<string | null>(null);
|
|
@@ -172,22 +174,22 @@ const ITDropfile: React.FC<ITDropfileProps> = ({
|
|
|
172
174
|
const StatusBadge = ({ status }: { status: UploadStatus }) => {
|
|
173
175
|
const config = {
|
|
174
176
|
[UploadStatus.PENDING]: {
|
|
175
|
-
label: "
|
|
177
|
+
label: t("dropfile.status.pending"),
|
|
176
178
|
color: "bg-warning-100 text-warning-800 border-warning-200",
|
|
177
179
|
dotColor: "bg-warning-400",
|
|
178
180
|
},
|
|
179
181
|
[UploadStatus.UPLOADING]: {
|
|
180
|
-
label: "
|
|
182
|
+
label: t("dropfile.status.uploading"),
|
|
181
183
|
color: "bg-primary-100 text-primary-800 border-primary-200",
|
|
182
184
|
dotColor: "bg-primary-400 animate-pulse",
|
|
183
185
|
},
|
|
184
186
|
[UploadStatus.UPLOADED]: {
|
|
185
|
-
label: "
|
|
187
|
+
label: t("dropfile.status.uploaded"),
|
|
186
188
|
color: "bg-success-100 text-success-800 border-success-200",
|
|
187
189
|
dotColor: "bg-success-400",
|
|
188
190
|
},
|
|
189
191
|
[UploadStatus.ERROR]: {
|
|
190
|
-
label: "
|
|
192
|
+
label: t("dropfile.status.error"),
|
|
191
193
|
color: "bg-danger-100 text-danger-800 border-danger-200",
|
|
192
194
|
dotColor: "bg-danger-400",
|
|
193
195
|
},
|
|
@@ -223,7 +225,7 @@ const ITDropfile: React.FC<ITDropfileProps> = ({
|
|
|
223
225
|
setImagePreview(previewUrl);
|
|
224
226
|
}
|
|
225
227
|
} else {
|
|
226
|
-
alert(
|
|
228
|
+
alert(t("dropfile.fileTypeNotAllowed"));
|
|
227
229
|
setSelectedFile(null);
|
|
228
230
|
setFileType(null);
|
|
229
231
|
setImagePreview(null);
|
|
@@ -318,7 +320,7 @@ const ITDropfile: React.FC<ITDropfileProps> = ({
|
|
|
318
320
|
const headerRow = (
|
|
319
321
|
<div className="flex items-center justify-between mb-2">
|
|
320
322
|
<label className="block text-sm font-semibold text-secondary-700">
|
|
321
|
-
<ITText as="span">
|
|
323
|
+
<ITText as="span">{t("dropfile.upload")} </ITText><ITText as="span" className="text-secondary-400 font-normal text-xs">({getFileExtensions()})</ITText>
|
|
322
324
|
</label>
|
|
323
325
|
|
|
324
326
|
{showStatusBadge && selectedFile && (
|
|
@@ -355,7 +357,7 @@ const ITDropfile: React.FC<ITDropfileProps> = ({
|
|
|
355
357
|
|
|
356
358
|
<div className="text-center space-y-1">
|
|
357
359
|
<ITText as="p" className={`text-sm font-medium transition-colors duration-300 ${isDragActive ? 'text-primary-700' : 'text-secondary-700'}`}>
|
|
358
|
-
{isDragActive ? "
|
|
360
|
+
{isDragActive ? t("dropfile.dropHere") : t("dropfile.clickOrDrag")}
|
|
359
361
|
</ITText>
|
|
360
362
|
</div>
|
|
361
363
|
</div>
|
|
@@ -375,8 +377,8 @@ const ITDropfile: React.FC<ITDropfileProps> = ({
|
|
|
375
377
|
)}
|
|
376
378
|
</div>
|
|
377
379
|
<div className="min-w-0">
|
|
378
|
-
<ITText as="p" className="text-xs font-medium text-secondary-900 truncate" title={selectedFile?.name || "
|
|
379
|
-
{selectedFile?.name || "
|
|
380
|
+
<ITText as="p" className="text-xs font-medium text-secondary-900 truncate" title={selectedFile?.name || t("dropfile.imageLoaded")}>
|
|
381
|
+
{selectedFile?.name || t("dropfile.imageLoaded")}
|
|
380
382
|
</ITText>
|
|
381
383
|
<ITText as="p" className="text-[10px] text-secondary-500">
|
|
382
384
|
{selectedFile ? (selectedFile.size / 1024 / 1024).toFixed(2) + " MB" : ""}
|
|
@@ -389,7 +391,7 @@ const ITDropfile: React.FC<ITDropfileProps> = ({
|
|
|
389
391
|
{((selectedFile && fileType?.startsWith('image/')) || (!selectedFile && imagePreview)) ? (
|
|
390
392
|
<img
|
|
391
393
|
src={imagePreview}
|
|
392
|
-
alt="
|
|
394
|
+
alt={t("dropfile.previewAlt")}
|
|
393
395
|
className="w-full h-full object-contain max-h-[200px]"
|
|
394
396
|
/>
|
|
395
397
|
) : (
|
|
@@ -397,7 +399,7 @@ const ITDropfile: React.FC<ITDropfileProps> = ({
|
|
|
397
399
|
<svg className="w-10 h-10 mb-2 opacity-50" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
398
400
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z" />
|
|
399
401
|
</svg>
|
|
400
|
-
<ITText as="span" className="text-xs">
|
|
402
|
+
<ITText as="span" className="text-xs">{t("dropfile.noPreview")}</ITText>
|
|
401
403
|
</div>
|
|
402
404
|
)}
|
|
403
405
|
</div>
|
|
@@ -412,7 +414,7 @@ const ITDropfile: React.FC<ITDropfileProps> = ({
|
|
|
412
414
|
size="sm"
|
|
413
415
|
onClick={handleCancel}
|
|
414
416
|
>
|
|
415
|
-
<ITText>
|
|
417
|
+
<ITText>{t("common.cancel")}</ITText>
|
|
416
418
|
</ITButton>
|
|
417
419
|
<ITButton
|
|
418
420
|
type="button"
|
|
@@ -422,7 +424,7 @@ const ITDropfile: React.FC<ITDropfileProps> = ({
|
|
|
422
424
|
onClick={handleConfirm}
|
|
423
425
|
>
|
|
424
426
|
<div className="flex items-center gap-2">
|
|
425
|
-
<ITText>
|
|
427
|
+
<ITText>{t("common.confirm")}</ITText>
|
|
426
428
|
<svg className="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
427
429
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
|
428
430
|
</svg>
|
|
@@ -440,7 +442,7 @@ const ITDropfile: React.FC<ITDropfileProps> = ({
|
|
|
440
442
|
<svg className="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
441
443
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
|
|
442
444
|
</svg>
|
|
443
|
-
<ITText>
|
|
445
|
+
<ITText>{t("common.delete")}</ITText>
|
|
444
446
|
</ITButton>
|
|
445
447
|
)}
|
|
446
448
|
</div>
|
|
@@ -479,13 +481,13 @@ const ITDropfile: React.FC<ITDropfileProps> = ({
|
|
|
479
481
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" />
|
|
480
482
|
</svg>
|
|
481
483
|
<ITText className="truncate">
|
|
482
|
-
{selectedFile?.name || (hasFile ? "
|
|
484
|
+
{selectedFile?.name || (hasFile ? t("dropfile.fileLoaded") : (buttonLabel ?? t("dropfile.upload")))}
|
|
483
485
|
</ITText>
|
|
484
486
|
{showStatusBadge && hasFile && <StatusBadge status={uploadStatus} />}
|
|
485
487
|
</div>
|
|
486
488
|
</ITButton>
|
|
487
489
|
|
|
488
|
-
<ITDialog isOpen={isModalOpen} onClose={() => setIsModalOpen(false)} title={modalTitle ?? buttonLabel}>
|
|
490
|
+
<ITDialog isOpen={isModalOpen} onClose={() => setIsModalOpen(false)} title={modalTitle ?? buttonLabel ?? t("dropfile.upload")}>
|
|
489
491
|
<div className="w-full transition-all duration-300">
|
|
490
492
|
{headerRow}
|
|
491
493
|
{dropZoneOrPreview}
|
|
@@ -11,6 +11,7 @@ import { useFieldRules } from "./useFormBuilder";
|
|
|
11
11
|
import { getColSpanClass, getGridColsClass } from "@/utils/styles";
|
|
12
12
|
import ITText from "@/components/atoms/text/text";
|
|
13
13
|
import { FaSpinner } from "react-icons/fa";
|
|
14
|
+
import { useITTranslation } from "@/i18n";
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Resolves `FieldConfigV2["options"]` to a stable `{ value, label }[]` array,
|
|
@@ -123,6 +124,7 @@ const ITFieldRenderer = ({
|
|
|
123
124
|
dependentValues = {},
|
|
124
125
|
}: ITFieldRendererProps) => {
|
|
125
126
|
const context = useITFormBuilderContext();
|
|
127
|
+
const { t } = useITTranslation();
|
|
126
128
|
const { isVisible, isRequired, isDisabled, dynamicProps } = useFieldRules(
|
|
127
129
|
config,
|
|
128
130
|
dependentValues,
|
|
@@ -220,7 +222,7 @@ const ITFieldRenderer = ({
|
|
|
220
222
|
>
|
|
221
223
|
<FaSpinner className="animate-spin text-primary-500" />
|
|
222
224
|
<ITText as="span" className="text-sm text-slate-500">
|
|
223
|
-
|
|
225
|
+
{t("formBuilder.loadingOptions")}
|
|
224
226
|
</ITText>
|
|
225
227
|
</div>
|
|
226
228
|
);
|
|
@@ -366,7 +368,7 @@ const ITFieldRenderer = ({
|
|
|
366
368
|
return (
|
|
367
369
|
<div className="p-4 border-2 border-dashed border-secondary-200 rounded-xl">
|
|
368
370
|
<ITText as="p" className="text-sm text-secondary-500 text-center">
|
|
369
|
-
|
|
371
|
+
{t("formBuilder.arrayField", { label: label ?? "" })}
|
|
370
372
|
</ITText>
|
|
371
373
|
</div>
|
|
372
374
|
);
|
|
@@ -4,6 +4,7 @@ import { FaChevronDown, FaChevronRight, FaUserCircle } from "react-icons/fa";
|
|
|
4
4
|
import { ITNavbarProps, ITNavigationItem } from "./navbar.props";
|
|
5
5
|
import ITText from "@/components/atoms/text/text";
|
|
6
6
|
import { theme } from "@/theme/theme";
|
|
7
|
+
import { useITTranslation } from "@/i18n";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Full sidebar navigation shell with collapsible submenus, user menu dropdown, and themed styling.
|
|
@@ -44,6 +45,7 @@ export default function ITNavbar({
|
|
|
44
45
|
showSidebarOnMobile = false,
|
|
45
46
|
sidebarItems,
|
|
46
47
|
}: ITNavbarProps) {
|
|
48
|
+
const { t } = useITTranslation();
|
|
47
49
|
const [isUserMenuOpen, setIsUserMenuOpen] = useState(false);
|
|
48
50
|
const [expandedItems, setExpandedItems] = useState<Set<string>>(new Set());
|
|
49
51
|
|
|
@@ -106,7 +108,7 @@ export default function ITNavbar({
|
|
|
106
108
|
<img
|
|
107
109
|
className="w-8 h-8 rounded-full"
|
|
108
110
|
src={userMenu.userImage}
|
|
109
|
-
alt="
|
|
111
|
+
alt={t("common.userAvatar")}
|
|
110
112
|
/>
|
|
111
113
|
) : (
|
|
112
114
|
<FaUserCircle className="w-8 h-8 text-secondary-500" />
|
|
@@ -290,7 +292,7 @@ export default function ITNavbar({
|
|
|
290
292
|
<img
|
|
291
293
|
className="w-10 h-10 rounded-full border-2 transition-colors"
|
|
292
294
|
src={userMenu.userImage}
|
|
293
|
-
alt="
|
|
295
|
+
alt={t("common.userAvatar")}
|
|
294
296
|
style={{ borderColor: sidebar.borderColor }}
|
|
295
297
|
/>
|
|
296
298
|
) : (
|
|
@@ -3,6 +3,7 @@ import { ITPageHeaderProps } from "./page-header.props";
|
|
|
3
3
|
import ITBreadcrumbs from "@/components/molecules/breadcrumbs/breadcrumbs";
|
|
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
|
* Page title bar with breadcrumbs, description, back button, and action buttons.
|
|
@@ -29,6 +30,7 @@ export default function ITPageHeader({
|
|
|
29
30
|
iconColor,
|
|
30
31
|
className,
|
|
31
32
|
}: ITPageHeaderProps) {
|
|
33
|
+
const { t } = useITTranslation();
|
|
32
34
|
const showTopRow = breadcrumbs?.length || backAction;
|
|
33
35
|
// Flat appearance: compact title, no decorative icon tile.
|
|
34
36
|
const flat = useITFlatAppearance();
|
|
@@ -43,7 +45,7 @@ export default function ITPageHeader({
|
|
|
43
45
|
<button
|
|
44
46
|
onClick={backAction}
|
|
45
47
|
className="flex items-center justify-center w-9 h-9 rounded-full border border-slate-200 dark:border-slate-700 text-slate-400 hover:text-slate-700 dark:hover:text-slate-200 hover:border-slate-300 dark:hover:border-slate-600 hover:bg-slate-50 dark:hover:bg-slate-800/60 transition-all duration-200 flex-shrink-0"
|
|
46
|
-
aria-label="
|
|
48
|
+
aria-label={t("pageHeader.back")}
|
|
47
49
|
>
|
|
48
50
|
<FaChevronLeft size={14} />
|
|
49
51
|
</button>
|
|
@@ -4,6 +4,7 @@ import PaginationInfo from "./PaginationInfo";
|
|
|
4
4
|
import ITSelect from "@/components/molecules/select/select";
|
|
5
5
|
import ITButton from "@/components/atoms/button/button";
|
|
6
6
|
import ITText from "@/components/atoms/text/text";
|
|
7
|
+
import { useITTranslation } from "@/i18n";
|
|
7
8
|
|
|
8
9
|
interface PaginationControlsProps {
|
|
9
10
|
pageIndex: number;
|
|
@@ -30,13 +31,14 @@ export default function PaginationControls({
|
|
|
30
31
|
currentCount,
|
|
31
32
|
totalCount,
|
|
32
33
|
}: PaginationControlsProps) {
|
|
34
|
+
const { t } = useITTranslation();
|
|
33
35
|
return (
|
|
34
36
|
<div className="flex flex-col sm:flex-row justify-between items-center gap-4">
|
|
35
37
|
<div className="flex items-center space-x-4">
|
|
36
38
|
<PaginationInfo currentCount={currentCount} totalCount={totalCount} />
|
|
37
39
|
|
|
38
40
|
<div className="flex items-center space-x-2">
|
|
39
|
-
<ITText as="span" className="text-sm text-secondary-700">
|
|
41
|
+
<ITText as="span" className="text-sm text-secondary-700">{t("searchTable.showLabel")}</ITText>
|
|
40
42
|
<ITSelect
|
|
41
43
|
name="itemsPerPage"
|
|
42
44
|
options={itemsPerPageOptions.map((option) => ({
|
|
@@ -59,14 +61,14 @@ export default function PaginationControls({
|
|
|
59
61
|
onClick={() => onPageChange(pageIndex - 1)}
|
|
60
62
|
disabled={!hasPreviousPage}
|
|
61
63
|
className="min-w-[32px]"
|
|
62
|
-
ariaLabel="
|
|
63
|
-
title="
|
|
64
|
+
ariaLabel={t("searchTable.prev")}
|
|
65
|
+
title={t("searchTable.prev")}
|
|
64
66
|
>
|
|
65
67
|
<FaArrowLeft aria-hidden="true" />
|
|
66
68
|
</ITButton>
|
|
67
69
|
|
|
68
70
|
<ITText as="span" className="px-4 py-2 text-sm text-secondary-700" aria-live="polite">
|
|
69
|
-
|
|
71
|
+
{t("searchTable.pageOf", { current: pageIndex, total: totalPages })}
|
|
70
72
|
</ITText>
|
|
71
73
|
|
|
72
74
|
<ITButton
|
|
@@ -75,8 +77,8 @@ export default function PaginationControls({
|
|
|
75
77
|
onClick={() => onPageChange(pageIndex + 1)}
|
|
76
78
|
disabled={!hasNextPage}
|
|
77
79
|
className="min-w-[32px]"
|
|
78
|
-
ariaLabel="
|
|
79
|
-
title="
|
|
80
|
+
ariaLabel={t("searchTable.next")}
|
|
81
|
+
title={t("searchTable.next")}
|
|
80
82
|
>
|
|
81
83
|
<FaArrowRight aria-hidden="true" />
|
|
82
84
|
</ITButton>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import ITText from "@/components/atoms/text/text";
|
|
3
|
+
import { useITTranslation } from "@/i18n";
|
|
3
4
|
|
|
4
5
|
interface PaginationInfoProps {
|
|
5
6
|
currentCount: number;
|
|
@@ -12,9 +13,10 @@ export default function PaginationInfo({
|
|
|
12
13
|
totalCount,
|
|
13
14
|
className = "",
|
|
14
15
|
}: PaginationInfoProps) {
|
|
16
|
+
const { t } = useITTranslation();
|
|
15
17
|
return (
|
|
16
18
|
<ITText as="span" className={`text-sm text-secondary-700 ${className}`}>
|
|
17
|
-
|
|
19
|
+
{t("searchTable.showingCount", { from: currentCount, total: totalCount })}
|
|
18
20
|
</ITText>
|
|
19
21
|
);
|
|
20
22
|
}
|
|
@@ -3,6 +3,7 @@ import SearchInput from "./SearchInput";
|
|
|
3
3
|
import SortButton from "./SortButton";
|
|
4
4
|
import ITButton from "@/components/atoms/button/button";
|
|
5
5
|
import ITText from "@/components/atoms/text/text";
|
|
6
|
+
import { useITTranslation } from "@/i18n";
|
|
6
7
|
|
|
7
8
|
interface SearchAndSortBarProps {
|
|
8
9
|
searchTerm: string;
|
|
@@ -22,13 +23,14 @@ export default function SearchAndSortBar({
|
|
|
22
23
|
onClearSearch,
|
|
23
24
|
onGlobalSort,
|
|
24
25
|
sortConfig,
|
|
25
|
-
searchInputPlaceholder
|
|
26
|
+
searchInputPlaceholder,
|
|
26
27
|
}: SearchAndSortBarProps) {
|
|
28
|
+
const { t } = useITTranslation();
|
|
27
29
|
return (
|
|
28
30
|
<div className="bg-secondary-50 px-6 py-4 border-b border-secondary-200">
|
|
29
31
|
<div className="flex items-center gap-4">
|
|
30
32
|
<SearchInput
|
|
31
|
-
placeholder={searchInputPlaceholder}
|
|
33
|
+
placeholder={searchInputPlaceholder ?? t("searchTable.searchPlaceholder")}
|
|
32
34
|
value={searchTerm}
|
|
33
35
|
onChange={onSearchChange}
|
|
34
36
|
/>
|
|
@@ -41,10 +43,10 @@ export default function SearchAndSortBar({
|
|
|
41
43
|
variant="outlined"
|
|
42
44
|
color="danger"
|
|
43
45
|
onClick={onClearSearch}
|
|
44
|
-
ariaLabel="
|
|
45
|
-
title="
|
|
46
|
+
ariaLabel={t("searchTable.clearSearch")}
|
|
47
|
+
title={t("searchTable.clearSearch")}
|
|
46
48
|
>
|
|
47
|
-
<ITText as="span">
|
|
49
|
+
<ITText as="span">{t("common.clear")}</ITText>
|
|
48
50
|
</ITButton>
|
|
49
51
|
)}
|
|
50
52
|
</div>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import ITInput from "@/components/atoms/input/input";
|
|
2
2
|
import React from "react";
|
|
3
3
|
import { FaSearch } from "react-icons/fa";
|
|
4
|
+
import { useITTranslation } from "@/i18n";
|
|
4
5
|
|
|
5
6
|
interface SearchInputProps {
|
|
6
7
|
placeholder?: string;
|
|
@@ -10,11 +11,12 @@ interface SearchInputProps {
|
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
export default function SearchInput({
|
|
13
|
-
placeholder
|
|
14
|
+
placeholder,
|
|
14
15
|
value,
|
|
15
16
|
onChange,
|
|
16
17
|
className = "",
|
|
17
18
|
}: SearchInputProps) {
|
|
19
|
+
const { t } = useITTranslation();
|
|
18
20
|
return (
|
|
19
21
|
<div className={`relative flex-1 ${className}`}>
|
|
20
22
|
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
|
@@ -22,7 +24,7 @@ export default function SearchInput({
|
|
|
22
24
|
</div>
|
|
23
25
|
<ITInput
|
|
24
26
|
name="global-search"
|
|
25
|
-
placeholder={placeholder}
|
|
27
|
+
placeholder={placeholder ?? t("searchTable.searchPlaceholder")}
|
|
26
28
|
value={value}
|
|
27
29
|
onChange={(e) => onChange(e.target.value)}
|
|
28
30
|
onBlur={() => {}}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { FaSort, FaSortUp, FaSortDown } from "react-icons/fa";
|
|
3
3
|
import ITText from "@/components/atoms/text/text";
|
|
4
|
+
import { useITTranslation } from "@/i18n";
|
|
4
5
|
|
|
5
6
|
interface SortButtonProps {
|
|
6
7
|
sortConfig?: {
|
|
@@ -16,18 +17,19 @@ export default function SortButton({
|
|
|
16
17
|
onClick,
|
|
17
18
|
className = "",
|
|
18
19
|
}: SortButtonProps) {
|
|
20
|
+
const { t } = useITTranslation();
|
|
21
|
+
const directionLabel = sortConfig
|
|
22
|
+
? sortConfig.direction === "asc"
|
|
23
|
+
? t("searchTable.sortDescending")
|
|
24
|
+
: t("searchTable.sortAscending")
|
|
25
|
+
: t("searchTable.sortAscending");
|
|
26
|
+
|
|
19
27
|
return (
|
|
20
28
|
<button
|
|
21
29
|
onClick={onClick}
|
|
22
30
|
className={`p-3 rounded-lg bg-white border border-secondary-300 hover:bg-secondary-50 transition-colors duration-200 flex items-center gap-2 min-w-[120px] ${className}`}
|
|
23
|
-
aria-label={
|
|
24
|
-
|
|
25
|
-
? sortConfig.direction === "asc"
|
|
26
|
-
? "descendente"
|
|
27
|
-
: "ascendente"
|
|
28
|
-
: "ascendente"
|
|
29
|
-
}`}
|
|
30
|
-
title="Ordenar tabla"
|
|
31
|
+
aria-label={t("searchTable.sortAria", { direction: directionLabel })}
|
|
32
|
+
title={t("searchTable.sortTable")}
|
|
31
33
|
>
|
|
32
34
|
{sortConfig ? (
|
|
33
35
|
sortConfig.direction === "asc" ? (
|
|
@@ -41,9 +43,9 @@ export default function SortButton({
|
|
|
41
43
|
<ITText as="span" className="text-sm font-medium text-secondary-700">
|
|
42
44
|
{sortConfig
|
|
43
45
|
? sortConfig.direction === "asc"
|
|
44
|
-
? "
|
|
45
|
-
: "
|
|
46
|
-
: "
|
|
46
|
+
? t("searchTable.sortAsc")
|
|
47
|
+
: t("searchTable.sortDesc")
|
|
48
|
+
: t("searchTable.sort")}
|
|
47
49
|
</ITText>
|
|
48
50
|
</button>
|
|
49
51
|
);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import ITText from "@/components/atoms/text/text";
|
|
3
|
+
import { useITTranslation } from "@/i18n";
|
|
3
4
|
|
|
4
5
|
interface TableEmptyStateProps {
|
|
5
6
|
colSpan: number;
|
|
@@ -10,12 +11,13 @@ export default function TableEmptyState({
|
|
|
10
11
|
colSpan,
|
|
11
12
|
searchTerm,
|
|
12
13
|
}: TableEmptyStateProps) {
|
|
14
|
+
const { t } = useITTranslation();
|
|
13
15
|
return (
|
|
14
16
|
<tr>
|
|
15
17
|
<td colSpan={colSpan} className="px-6 py-4 text-center">
|
|
16
18
|
{searchTerm
|
|
17
|
-
? <ITText as="span">
|
|
18
|
-
: <ITText as="span">
|
|
19
|
+
? <ITText as="span">{t("searchTable.emptySearch")}</ITText>
|
|
20
|
+
: <ITText as="span">{t("searchTable.empty")}</ITText>}
|
|
19
21
|
</td>
|
|
20
22
|
</tr>
|
|
21
23
|
);
|
|
@@ -6,6 +6,7 @@ import { FaCheck, FaTimes } from "react-icons/fa";
|
|
|
6
6
|
import { SearchColumn } from "../searchTable.props";
|
|
7
7
|
import EditableCell from "./EditableCell";
|
|
8
8
|
import * as yup from "yup";
|
|
9
|
+
import { useITTranslation, toIntlLocale } from "@/i18n";
|
|
9
10
|
|
|
10
11
|
interface TableRowProps<T> {
|
|
11
12
|
row: T;
|
|
@@ -31,6 +32,7 @@ export default function TableRow<T>({
|
|
|
31
32
|
isEditing = false,
|
|
32
33
|
onEdit,
|
|
33
34
|
}: TableRowProps<T>) {
|
|
35
|
+
const { t, locale } = useITTranslation();
|
|
34
36
|
const {
|
|
35
37
|
editedRow,
|
|
36
38
|
errors,
|
|
@@ -55,18 +57,18 @@ export default function TableRow<T>({
|
|
|
55
57
|
switch (col.type) {
|
|
56
58
|
case "number":
|
|
57
59
|
return typeof value === "number" && col.currencyMX
|
|
58
|
-
? formatCurrencyMX(value)
|
|
60
|
+
? formatCurrencyMX(value, toIntlLocale(locale))
|
|
59
61
|
: (value as React.ReactNode);
|
|
60
62
|
|
|
61
63
|
case "boolean":
|
|
62
64
|
return value ? (
|
|
63
65
|
<FaCheck
|
|
64
66
|
className="text-green-500"
|
|
65
|
-
aria-label="
|
|
66
|
-
title="
|
|
67
|
+
aria-label={t("common.true")}
|
|
68
|
+
title={t("common.true")}
|
|
67
69
|
/>
|
|
68
70
|
) : (
|
|
69
|
-
<FaTimes className="text-danger-500" aria-label="
|
|
71
|
+
<FaTimes className="text-danger-500" aria-label={t("common.false")} title={t("common.false")} />
|
|
70
72
|
);
|
|
71
73
|
|
|
72
74
|
case "actions":
|
|
@@ -11,6 +11,7 @@ import { getNestedValue } from "@/utils/table.utils";
|
|
|
11
11
|
import TableEmptyState from "./components/TableEmptyState";
|
|
12
12
|
import PaginationControls from "./components/PaginationControls";
|
|
13
13
|
import ITText from "@/components/atoms/text/text";
|
|
14
|
+
import { useITTranslation } from "@/i18n";
|
|
14
15
|
|
|
15
16
|
interface CustomITSearchTableProps<T> extends ITSearchTableProps<T> {
|
|
16
17
|
editingRow?: number | null;
|
|
@@ -53,7 +54,7 @@ export default function ITSearchTable<T extends Record<string, unknown>>({
|
|
|
53
54
|
data,
|
|
54
55
|
containerClassName,
|
|
55
56
|
searchTermInitial = "",
|
|
56
|
-
searchInputPlaceholder
|
|
57
|
+
searchInputPlaceholder,
|
|
57
58
|
variant = "default",
|
|
58
59
|
size = "md",
|
|
59
60
|
itemsPerPageOptions = [10, 20, 50, 100],
|
|
@@ -76,6 +77,7 @@ export default function ITSearchTable<T extends Record<string, unknown>>({
|
|
|
76
77
|
onSave,
|
|
77
78
|
onCancel,
|
|
78
79
|
}: CustomITSearchTableProps<T>) {
|
|
80
|
+
const { t } = useITTranslation();
|
|
79
81
|
const [itemsPerPage, setItemsPerPage] = useState(defaultItemsPerPage);
|
|
80
82
|
|
|
81
83
|
const { searchTerm, handleSearchChange, handleClearSearch } = useDebouncedSearch({
|
|
@@ -145,7 +147,7 @@ return (
|
|
|
145
147
|
onClearSearch={handleClearSearchWithClear}
|
|
146
148
|
onGlobalSort={handleGlobalSort}
|
|
147
149
|
sortConfig={sortConfig}
|
|
148
|
-
searchInputPlaceholder={searchInputPlaceholder}
|
|
150
|
+
searchInputPlaceholder={searchInputPlaceholder ?? t("searchTable.searchPlaceholder")}
|
|
149
151
|
/>
|
|
150
152
|
</div>
|
|
151
153
|
|
|
@@ -75,7 +75,7 @@ export interface ITSidebarNotification {
|
|
|
75
75
|
count: number;
|
|
76
76
|
/** Icon rendered left of the label (e.g. a bell). Omit for a count-only pill. */
|
|
77
77
|
icon?: React.ReactNode;
|
|
78
|
-
/** Accessible label and tooltip for the notification button. @default "Notificaciones" */
|
|
78
|
+
/** Accessible label and tooltip for the notification button. @default i18n `sidebar.notifications` ("Notificaciones") */
|
|
79
79
|
label?: string;
|
|
80
80
|
/** Click handler for the notification button. */
|
|
81
81
|
onClick?: () => void;
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
import ITBadget from "@/components/atoms/badget/badget";
|
|
12
12
|
import ITText from "@/components/atoms/text/text";
|
|
13
13
|
import { useITFlatAppearance } from "@/theme/theme-context";
|
|
14
|
+
import { useITTranslation } from "@/i18n";
|
|
14
15
|
|
|
15
16
|
/** Narrows a submenu entry to a titled group. */
|
|
16
17
|
function isSubItemGroup(
|
|
@@ -73,6 +74,7 @@ export default function ITSidebar({
|
|
|
73
74
|
}: ITSidebarProps) {
|
|
74
75
|
// Flat appearance: plain surface, no glow/accent bar, narrower panel.
|
|
75
76
|
const flat = useITFlatAppearance();
|
|
77
|
+
const { t } = useITTranslation();
|
|
76
78
|
const [expandedItems, setExpandedItems] = useState<Set<string>>(new Set());
|
|
77
79
|
const [isHovering, setIsHovering] = useState(false);
|
|
78
80
|
const sidebarRef = useRef<HTMLDivElement>(null);
|
|
@@ -251,7 +253,7 @@ export default function ITSidebar({
|
|
|
251
253
|
const {
|
|
252
254
|
count,
|
|
253
255
|
icon,
|
|
254
|
-
label = "
|
|
256
|
+
label = t("sidebar.notifications"),
|
|
255
257
|
onClick,
|
|
256
258
|
badgeProps,
|
|
257
259
|
} = notification;
|
|
@@ -371,11 +373,14 @@ export default function ITSidebar({
|
|
|
371
373
|
)}
|
|
372
374
|
|
|
373
375
|
{/* Navigation Items */}
|
|
374
|
-
<nav aria-label="
|
|
376
|
+
<nav aria-label={t("sidebar.navAria")} className={`flex-1 py-4 custom-scrollbar ${fixedRail ? "overflow-visible" : "overflow-y-auto overflow-x-hidden"} ${flat && isSidebarCollapsed ? "px-3" : "px-4"}`}>
|
|
375
377
|
<ul className="space-y-1">
|
|
376
378
|
{navigationItems.map((item) => {
|
|
377
379
|
const hasSubmenu = !!item.subitems && item.subitems.length > 0;
|
|
378
380
|
const submenuId = `it-sidebar-submenu-${item.id}`;
|
|
381
|
+
// El submenú solo existe en el DOM cuando la barra está expandida:
|
|
382
|
+
// `aria-controls` a un id inexistente es un valor ARIA inválido.
|
|
383
|
+
const hasRenderedSubmenu = hasSubmenu && !isSidebarCollapsed;
|
|
379
384
|
const { className: badgeClassName, ...badgeRest } = item.badgeProps ?? {};
|
|
380
385
|
// Flat + expanded: a parent whose subitem is active stays plain; the
|
|
381
386
|
// subitem carries the highlight. Collapsed, the parent icon shows it.
|
|
@@ -387,7 +392,7 @@ export default function ITSidebar({
|
|
|
387
392
|
tabIndex={0}
|
|
388
393
|
aria-label={item.label}
|
|
389
394
|
aria-expanded={hasSubmenu ? expandedItems.has(item.id) : undefined}
|
|
390
|
-
aria-controls={
|
|
395
|
+
aria-controls={hasRenderedSubmenu ? submenuId : undefined}
|
|
391
396
|
className={`flex items-center cursor-pointer
|
|
392
397
|
transition-all duration-300 ease-[cubic-bezier(0.2,0,0,1)]
|
|
393
398
|
rounded-xl relative overflow-visible
|
|
@@ -525,7 +530,7 @@ export default function ITSidebar({
|
|
|
525
530
|
))}
|
|
526
531
|
</div>
|
|
527
532
|
) : (
|
|
528
|
-
<ITText as="div" className="px-5 py-3 text-sm italic" style={{ color: "var(--it-sidebar-label-color, var(--color-secondary-400))" }}>
|
|
533
|
+
<ITText as="div" className="px-5 py-3 text-sm italic" style={{ color: "var(--it-sidebar-label-color, var(--color-secondary-400))" }}>{t("sidebar.noSubmenu")}</ITText>
|
|
529
534
|
)}
|
|
530
535
|
</div>
|
|
531
536
|
)}
|
|
@@ -5,6 +5,7 @@ import { useEffect, useState } from "react";
|
|
|
5
5
|
import { ITToastProps } from "./toast.props";
|
|
6
6
|
import { FaTimesCircle, FaCheckCircle, FaExclamationTriangle, FaInfoCircle, FaTimes } from "react-icons/fa";
|
|
7
7
|
import ITText from "@/components/atoms/text/text";
|
|
8
|
+
import { useITTranslation } from "@/i18n";
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* ITToast — floating notification with automatic dismiss and severity-based styling.
|
|
@@ -34,6 +35,7 @@ export default function ITToast({
|
|
|
34
35
|
position = "top-right",
|
|
35
36
|
onClose,
|
|
36
37
|
}: ITToastProps) {
|
|
38
|
+
const { t } = useITTranslation();
|
|
37
39
|
const [isVisible, setIsVisible] = useState(true);
|
|
38
40
|
|
|
39
41
|
useEffect(() => {
|
|
@@ -98,7 +100,7 @@ export default function ITToast({
|
|
|
98
100
|
<button
|
|
99
101
|
onClick={handleClose}
|
|
100
102
|
className="p-1.5 rounded-full hover:bg-black/15 transition-colors focus:outline-none focus:ring-2 focus:ring-white/50"
|
|
101
|
-
aria-label="
|
|
103
|
+
aria-label={t("common.closeNotification")}
|
|
102
104
|
>
|
|
103
105
|
<FaTimes className="w-4 h-4" />
|
|
104
106
|
</button>
|
|
@@ -4,6 +4,7 @@ import { useRef, useState } from "react";
|
|
|
4
4
|
import { ITTopBarProps } from "./topbar.props";
|
|
5
5
|
import ITText from "@/components/atoms/text/text";
|
|
6
6
|
import { useITFlatAppearance } from "@/theme/theme-context";
|
|
7
|
+
import { useITTranslation } from "@/i18n";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* ITTopBar — sticky top navigation bar with logo, nav items, and user avatar dropdown.
|
|
@@ -73,6 +74,7 @@ export default function ITTopBar({
|
|
|
73
74
|
}: ITTopBarProps) {
|
|
74
75
|
// Flat appearance: plain bar (no shadow/blur), initials avatar, name before it.
|
|
75
76
|
const flat = useITFlatAppearance();
|
|
77
|
+
const { t } = useITTranslation();
|
|
76
78
|
const initials = (userMenu?.userName ?? "")
|
|
77
79
|
.trim()
|
|
78
80
|
.split(/\s+/)
|
|
@@ -102,7 +104,7 @@ export default function ITTopBar({
|
|
|
102
104
|
{showMobileMenuButton && (
|
|
103
105
|
<button
|
|
104
106
|
type="button"
|
|
105
|
-
aria-label="
|
|
107
|
+
aria-label={t("common.menu")}
|
|
106
108
|
className={`${showDesktopMenuButton ? "" : "lg:hidden"} p-2.5 -ml-2.5 rounded-xl transition-colors duration-200`}
|
|
107
109
|
style={{
|
|
108
110
|
color: "var(--it-topbar-icon, #64748b)",
|
|
@@ -200,7 +202,7 @@ export default function ITTopBar({
|
|
|
200
202
|
<img
|
|
201
203
|
className="w-9 h-9 rounded-full object-cover ring-2 ring-white shadow-sm"
|
|
202
204
|
src={userMenu.userImage}
|
|
203
|
-
alt="
|
|
205
|
+
alt={t("common.userAvatar")}
|
|
204
206
|
/>
|
|
205
207
|
) : flat && initials ? (
|
|
206
208
|
<div
|