@sdcorejs/angular 19.0.0-rc.1
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 +723 -0
- package/assets/fonts/fonts.scss +116 -0
- package/assets/fonts/material-icons/material-icons-outlined-v110-latin-regular.woff2 +0 -0
- package/assets/fonts/material-icons/material-icons-v145-latin-regular.woff2 +0 -0
- package/assets/fonts/material-symbols/material-symbols-v29-latin-regular.woff2 +0 -0
- package/assets/fonts/roboto/roboto-v50-latin_vietnamese-500.woff2 +0 -0
- package/assets/fonts/roboto/roboto-v50-latin_vietnamese-600.woff2 +0 -0
- package/assets/fonts/roboto/roboto-v50-latin_vietnamese-italic.woff2 +0 -0
- package/assets/fonts/roboto/roboto-v50-latin_vietnamese-regular.woff2 +0 -0
- package/assets/images/coming-soon.svg +23 -0
- package/assets/images/data-empty.svg +21 -0
- package/assets/images/expired.svg +22 -0
- package/assets/images/file-error.svg +28 -0
- package/assets/images/filter-empty.svg +20 -0
- package/assets/images/filter-required.svg +21 -0
- package/assets/images/forbidden.svg +15 -0
- package/assets/images/image-error.svg +27 -0
- package/assets/images/maintenance.svg +23 -0
- package/assets/images/not-found.svg +20 -0
- package/assets/images/offline.svg +20 -0
- package/assets/images/submitted.svg +18 -0
- package/assets/images/success.svg +18 -0
- package/assets/images/unauthorized.svg +22 -0
- package/assets/images/unknown-error.svg +18 -0
- package/assets/scss/README.md +604 -0
- package/assets/scss/ckeditor5.scss +88 -0
- package/assets/scss/core/color.scss +74 -0
- package/assets/scss/core/form.scss +302 -0
- package/assets/scss/core/image.scss +35 -0
- package/assets/scss/core/scrollbar.scss +30 -0
- package/assets/scss/core/utilities/_base.scss +333 -0
- package/assets/scss/core/utilities/_border.scss +22 -0
- package/assets/scss/core/utilities/_display.scss +10 -0
- package/assets/scss/core/utilities/_elevation.scss +80 -0
- package/assets/scss/core/utilities/_flexbox.scss +54 -0
- package/assets/scss/core/utilities/_gap.scss +9 -0
- package/assets/scss/core/utilities/_grid.scss +143 -0
- package/assets/scss/core/utilities/_index.scss +17 -0
- package/assets/scss/core/utilities/_misc.scss +20 -0
- package/assets/scss/core/utilities/_overflow.scss +9 -0
- package/assets/scss/core/utilities/_position.scss +8 -0
- package/assets/scss/core/utilities/_sizing.scss +28 -0
- package/assets/scss/core/utilities/_spacing.scss +31 -0
- package/assets/scss/core/utilities/_typography.scss +99 -0
- package/assets/scss/sd-core.scss +17 -0
- package/assets/scss/themes/default.scss +45 -0
- package/assets/scss/themes/material-theme.scss +101 -0
- package/components/anchor/index.d.ts +1 -0
- package/components/anchor/src/components/anchor/anchor.component.d.ts +22 -0
- package/components/anchor/src/components/anchor-item/anchor-item.component.d.ts +13 -0
- package/components/anchor/src/components/anchor-nav/anchor-nav.component.d.ts +21 -0
- package/components/anchor/src/components/index.d.ts +2 -0
- package/components/anchor/src/index.d.ts +2 -0
- package/components/anchor/src/models/index.d.ts +1 -0
- package/components/anchor/src/models/sd-anchor.model.d.ts +7 -0
- package/components/autoid-inspector/index.d.ts +8 -0
- package/components/autoid-inspector/src/autoid-inspector.component.d.ts +55 -0
- package/components/autoid-inspector/src/models/autoid-element.model.d.ts +55 -0
- package/components/autoid-inspector/src/models/autoid-export-format.model.d.ts +6 -0
- package/components/autoid-inspector/src/models/autoid-inspector-config.model.d.ts +8 -0
- package/components/autoid-inspector/src/services/autoid-audit.service.d.ts +19 -0
- package/components/autoid-inspector/src/services/autoid-export.service.d.ts +21 -0
- package/components/autoid-inspector/src/services/autoid-highlight.service.d.ts +12 -0
- package/components/autoid-inspector/src/services/autoid-scanner.service.d.ts +23 -0
- package/components/avatar/index.d.ts +1 -0
- package/components/avatar/src/avatar.component.d.ts +19 -0
- package/components/badge/index.d.ts +1 -0
- package/components/badge/src/badge.component.d.ts +98 -0
- package/components/base/index.d.ts +1 -0
- package/components/base/src/base-secure.component.d.ts +8 -0
- package/components/button/index.d.ts +1 -0
- package/components/button/src/button.component.d.ts +42 -0
- package/components/chart/index.d.ts +4 -0
- package/components/chart/src/bar-chart.component.d.ts +18 -0
- package/components/chart/src/doughnut-chart.component.d.ts +16 -0
- package/components/chart/src/line-chart.component.d.ts +18 -0
- package/components/chart/src/pie-chart.component.d.ts +16 -0
- package/components/ckeditor-styles/index.d.ts +1 -0
- package/components/ckeditor-styles/src/ckeditor-styles.component.d.ts +25 -0
- package/components/code-editor/index.d.ts +1 -0
- package/components/code-editor/src/code-editor.component.d.ts +25 -0
- package/components/document-builder/index.d.ts +4 -0
- package/components/document-builder/src/components/header-footer-builder/header-footer-builder.component.d.ts +16 -0
- package/components/document-builder/src/components/header-footer-builder/plugins/page-number.plugin.d.ts +4 -0
- package/components/document-builder/src/components/index.d.ts +1 -0
- package/components/document-builder/src/document-builder.component.d.ts +53 -0
- package/components/document-builder/src/document-builder.config.d.ts +21 -0
- package/components/document-builder/src/document-builder.model.d.ts +41 -0
- package/components/document-builder/src/document-builder.utils.d.ts +10 -0
- package/components/document-builder/src/plugins/block-space/block-space.plugin.d.ts +9 -0
- package/components/document-builder/src/plugins/ck-comment/ck-comment.plugin.d.ts +44 -0
- package/components/document-builder/src/plugins/ck-comment/ck-comment.plugin.model.d.ts +57 -0
- package/components/document-builder/src/plugins/heading/heading.plugin.d.ts +5 -0
- package/components/document-builder/src/plugins/highlight-range/highlight-range.plugin.d.ts +4 -0
- package/components/document-builder/src/plugins/image-custom/image-custom.plugin.d.ts +31 -0
- package/components/document-builder/src/plugins/image-upload/image-upload.plugin.d.ts +5 -0
- package/components/document-builder/src/plugins/index.d.ts +11 -0
- package/components/document-builder/src/plugins/page-orientation/page-orientation.plugin.d.ts +24 -0
- package/components/document-builder/src/plugins/paste-handler/filters/bookmark.d.ts +14 -0
- package/components/document-builder/src/plugins/paste-handler/filters/br.d.ts +15 -0
- package/components/document-builder/src/plugins/paste-handler/filters/image.d.ts +25 -0
- package/components/document-builder/src/plugins/paste-handler/filters/list.d.ts +29 -0
- package/components/document-builder/src/plugins/paste-handler/filters/parse.d.ts +35 -0
- package/components/document-builder/src/plugins/paste-handler/filters/removeboldwrapper.d.ts +15 -0
- package/components/document-builder/src/plugins/paste-handler/filters/removegooglesheetstag.d.ts +15 -0
- package/components/document-builder/src/plugins/paste-handler/filters/removeinvalidtablewidth.d.ts +15 -0
- package/components/document-builder/src/plugins/paste-handler/filters/removemsattributes.d.ts +15 -0
- package/components/document-builder/src/plugins/paste-handler/filters/removestyleblock.d.ts +15 -0
- package/components/document-builder/src/plugins/paste-handler/filters/removexmlns.d.ts +15 -0
- package/components/document-builder/src/plugins/paste-handler/filters/replacemsfootnotes.d.ts +54 -0
- package/components/document-builder/src/plugins/paste-handler/filters/replacetabswithinprewithspaces.d.ts +24 -0
- package/components/document-builder/src/plugins/paste-handler/filters/space.d.ts +27 -0
- package/components/document-builder/src/plugins/paste-handler/filters/table.d.ts +16 -0
- package/components/document-builder/src/plugins/paste-handler/filters/utils.d.ts +25 -0
- package/components/document-builder/src/plugins/paste-handler/index.d.ts +35 -0
- package/components/document-builder/src/plugins/paste-handler/normalizers/googledocsnormalizer.d.ts +31 -0
- package/components/document-builder/src/plugins/paste-handler/normalizers/googlesheetsnormalizer.d.ts +31 -0
- package/components/document-builder/src/plugins/paste-handler/normalizers/mswordnormalizer.d.ts +29 -0
- package/components/document-builder/src/plugins/paste-handler/types.d.ts +30 -0
- package/components/document-builder/src/plugins/table-custom/index.d.ts +34 -0
- package/components/document-builder/src/plugins/variable/variable.plugin.d.ts +51 -0
- package/components/editor/index.d.ts +3 -0
- package/components/editor/src/configurations/editor.configuration.d.ts +12 -0
- package/components/editor/src/configurations/index.d.ts +1 -0
- package/components/editor/src/editor.component.d.ts +52 -0
- package/components/editor/src/models/editor.model.d.ts +10 -0
- package/components/editor/src/models/image-upload.plugin.model.d.ts +51 -0
- package/components/editor/src/models/index.d.ts +2 -0
- package/components/editor/src/plugins/image-upload/image-upload.plugin.d.ts +22 -0
- package/components/editor/src/plugins/image-upload/utils/batch.utils.d.ts +14 -0
- package/components/editor/src/plugins/image-upload/utils/index.d.ts +3 -0
- package/components/editor/src/plugins/image-upload/utils/style.utils.d.ts +3 -0
- package/components/editor/src/plugins/image-upload/utils/validate.utils.d.ts +4 -0
- package/components/form-generic/index.d.ts +4 -0
- package/components/form-generic/src/components/form-builder/components/attribute-expression/attribute-expression.component.d.ts +23 -0
- package/components/form-generic/src/components/form-builder/components/attribute-input/attribute-input.component.d.ts +17 -0
- package/components/form-generic/src/components/form-builder/components/attribute-input-number/attribute-input-number.component.d.ts +14 -0
- package/components/form-generic/src/components/form-builder/components/attribute-parameter/attribute-parameter.component.d.ts +33 -0
- package/components/form-generic/src/components/form-builder/components/attribute-select/attribute-select.component.d.ts +26 -0
- package/components/form-generic/src/components/form-builder/components/attribute-selection/attribute-selection.component.d.ts +27 -0
- package/components/form-generic/src/components/form-builder/components/attribute-selection/components/build-queries/build-queries.component.d.ts +35 -0
- package/components/form-generic/src/components/form-builder/components/attribute-selection/components/build-variables/build-variables.component.d.ts +41 -0
- package/components/form-generic/src/components/form-builder/components/attribute-switch/attribute-switch.component.d.ts +14 -0
- package/components/form-generic/src/components/form-builder/components/attribute-table/attribute-table.component.d.ts +36 -0
- package/components/form-generic/src/components/form-builder/components/attribute-template/attribute-template.component.d.ts +15 -0
- package/components/form-generic/src/components/form-builder/components/attribute-textarea/attribute-textarea.component.d.ts +17 -0
- package/components/form-generic/src/components/form-builder/components/checkbox/attribute/checkbox-attribute.component.d.ts +21 -0
- package/components/form-generic/src/components/form-builder/components/checkbox/control/checkbox-control.component.d.ts +8 -0
- package/components/form-generic/src/components/form-builder/components/checkbox/index.d.ts +2 -0
- package/components/form-generic/src/components/form-builder/components/chip-calendar/attribute/chip-calendar-attribute.component.d.ts +22 -0
- package/components/form-generic/src/components/form-builder/components/chip-calendar/control/chip-calendar-control.component.d.ts +16 -0
- package/components/form-generic/src/components/form-builder/components/chip-calendar/index.d.ts +2 -0
- package/components/form-generic/src/components/form-builder/components/chip-string/attribute/chip-string-attribute.component.d.ts +22 -0
- package/components/form-generic/src/components/form-builder/components/chip-string/control/chip-string-control.component.d.ts +16 -0
- package/components/form-generic/src/components/form-builder/components/chip-string/index.d.ts +2 -0
- package/components/form-generic/src/components/form-builder/components/configure-validation/configure-validation.component.d.ts +31 -0
- package/components/form-generic/src/components/form-builder/components/datetime/attribute/datetime-attribute.component.d.ts +21 -0
- package/components/form-generic/src/components/form-builder/components/datetime/control/datetime-control.component.d.ts +18 -0
- package/components/form-generic/src/components/form-builder/components/datetime/index.d.ts +2 -0
- package/components/form-generic/src/components/form-builder/components/expression-builder/expression-builder.component.d.ts +47 -0
- package/components/form-generic/src/components/form-builder/components/group/attribute/group-attribute.component.d.ts +23 -0
- package/components/form-generic/src/components/form-builder/components/group/index.d.ts +1 -0
- package/components/form-generic/src/components/form-builder/components/html/attribute/components/build-queries/build-queries.component.d.ts +35 -0
- package/components/form-generic/src/components/form-builder/components/html/attribute/html-attribute.component.d.ts +30 -0
- package/components/form-generic/src/components/form-builder/components/html/control/html-control.component.d.ts +20 -0
- package/components/form-generic/src/components/form-builder/components/html/index.d.ts +2 -0
- package/components/form-generic/src/components/form-builder/components/index.d.ts +13 -0
- package/components/form-generic/src/components/form-builder/components/number/attribute/number-attribute.component.d.ts +22 -0
- package/components/form-generic/src/components/form-builder/components/number/control/number-control.component.d.ts +17 -0
- package/components/form-generic/src/components/form-builder/components/number/index.d.ts +2 -0
- package/components/form-generic/src/components/form-builder/components/radio/attribute/radio-attribute.component.d.ts +22 -0
- package/components/form-generic/src/components/form-builder/components/radio/control/radio-control.component.d.ts +16 -0
- package/components/form-generic/src/components/form-builder/components/radio/index.d.ts +2 -0
- package/components/form-generic/src/components/form-builder/components/select/attribute/select-attribute.component.d.ts +22 -0
- package/components/form-generic/src/components/form-builder/components/select/control/select-control.component.d.ts +16 -0
- package/components/form-generic/src/components/form-builder/components/select/index.d.ts +2 -0
- package/components/form-generic/src/components/form-builder/components/table/attribute/table-attribute.component.d.ts +22 -0
- package/components/form-generic/src/components/form-builder/components/table/control/table-control.component.d.ts +19 -0
- package/components/form-generic/src/components/form-builder/components/table/index.d.ts +2 -0
- package/components/form-generic/src/components/form-builder/components/textarea/attribute/textarea-attribute.component.d.ts +21 -0
- package/components/form-generic/src/components/form-builder/components/textarea/control/textarea-control.component.d.ts +16 -0
- package/components/form-generic/src/components/form-builder/components/textarea/index.d.ts +2 -0
- package/components/form-generic/src/components/form-builder/components/textfield/attribute/textfield-attribute.component.d.ts +21 -0
- package/components/form-generic/src/components/form-builder/components/textfield/control/textfield-control.component.d.ts +16 -0
- package/components/form-generic/src/components/form-builder/components/textfield/index.d.ts +2 -0
- package/components/form-generic/src/components/form-builder/components/upload/attribute/upload-attribute.component.d.ts +27 -0
- package/components/form-generic/src/components/form-builder/components/upload/control/upload-control.component.d.ts +16 -0
- package/components/form-generic/src/components/form-builder/components/upload/index.d.ts +2 -0
- package/components/form-generic/src/components/form-builder/form-builder.component.d.ts +120 -0
- package/components/form-generic/src/components/form-builder/services/builder.service.d.ts +11 -0
- package/components/form-generic/src/components/form-builder/services/index.d.ts +1 -0
- package/components/form-generic/src/components/form-render/components/index.d.ts +2 -0
- package/components/form-generic/src/components/form-render/components/item/components/chip-calendar/chip-calendar.component.d.ts +30 -0
- package/components/form-generic/src/components/form-render/components/item/components/chip-string/chip-string.component.d.ts +30 -0
- package/components/form-generic/src/components/form-render/components/item/components/datetime/datetime.component.d.ts +34 -0
- package/components/form-generic/src/components/form-render/components/item/components/html/html.component.d.ts +32 -0
- package/components/form-generic/src/components/form-render/components/item/components/index.d.ts +11 -0
- package/components/form-generic/src/components/form-render/components/item/components/number/number.component.d.ts +30 -0
- package/components/form-generic/src/components/form-render/components/item/components/radio/radio.component.d.ts +38 -0
- package/components/form-generic/src/components/form-render/components/item/components/select/select.component.d.ts +43 -0
- package/components/form-generic/src/components/form-render/components/item/components/table/table.component.d.ts +51 -0
- package/components/form-generic/src/components/form-render/components/item/components/textarea/textarea.component.d.ts +30 -0
- package/components/form-generic/src/components/form-render/components/item/components/textfield/textfield.component.d.ts +33 -0
- package/components/form-generic/src/components/form-render/components/item/components/upload/upload.component.d.ts +36 -0
- package/components/form-generic/src/components/form-render/components/item/item.component.d.ts +32 -0
- package/components/form-generic/src/components/form-render/components/variable/variable.component.d.ts +22 -0
- package/components/form-generic/src/components/form-render/form-render.component.d.ts +39 -0
- package/components/form-generic/src/components/index.d.ts +3 -0
- package/components/form-generic/src/components/sd-feel-expression/sd-feel-expression.component.d.ts +43 -0
- package/components/form-generic/src/configurations/form-generic.configuration.d.ts +6 -0
- package/components/form-generic/src/configurations/form.configuration.d.ts +12 -0
- package/components/form-generic/src/configurations/index.d.ts +2 -0
- package/components/form-generic/src/models/form-generic-component.model.d.ts +318 -0
- package/components/form-generic/src/models/form-generic-definition-html.model.d.ts +28 -0
- package/components/form-generic/src/models/form-generic-definition-selection.model.d.ts +49 -0
- package/components/form-generic/src/models/form-generic-definition-table.model.d.ts +6 -0
- package/components/form-generic/src/models/form-generic-expression.model.d.ts +74 -0
- package/components/form-generic/src/models/form-generic-template.model.d.ts +6 -0
- package/components/form-generic/src/models/form-generic-validation.model.d.ts +30 -0
- package/components/form-generic/src/models/form-generic.model.d.ts +7 -0
- package/components/form-generic/src/models/form-render/form-render-args.model.d.ts +7 -0
- package/components/form-generic/src/models/form-render/form-render-entity.model.d.ts +3 -0
- package/components/form-generic/src/models/form-render/index.d.ts +2 -0
- package/components/form-generic/src/models/index.d.ts +8 -0
- package/components/form-generic/src/pipes/component-viewed.pipe.d.ts +14 -0
- package/components/form-generic/src/pipes/expression-feel.pipe.d.ts +10 -0
- package/components/form-generic/src/pipes/expression-query.pipe.d.ts +10 -0
- package/components/form-generic/src/pipes/expression-view.pipe.d.ts +8 -0
- package/components/form-generic/src/pipes/html.pipe.d.ts +11 -0
- package/components/form-generic/src/pipes/hyperlink.pipe.d.ts +8 -0
- package/components/form-generic/src/pipes/index.d.ts +7 -0
- package/components/form-generic/src/pipes/when-expression.pipe.d.ts +13 -0
- package/components/form-generic/src/services/form-generic.service.d.ts +26 -0
- package/components/form-generic/src/services/form-render.service.d.ts +10 -0
- package/components/form-generic/src/services/index.d.ts +2 -0
- package/components/history/index.d.ts +1 -0
- package/components/history/models/history.model.d.ts +13 -0
- package/components/history/pipes/view-date.pipe.d.ts +8 -0
- package/components/history/src/history.component.d.ts +7 -0
- package/components/import-excel/index.d.ts +2 -0
- package/components/import-excel/src/import-excel.component.d.ts +47 -0
- package/components/import-excel/src/import-excel.model.d.ts +102 -0
- package/components/import-excel/src/pipes/columm-hidden.pipe.d.ts +10 -0
- package/components/import-excel/src/pipes/column-transform.pipe.d.ts +11 -0
- package/components/index.d.ts +23 -0
- package/components/inform/index.d.ts +2 -0
- package/components/inform/src/inform-action.directive.d.ts +9 -0
- package/components/inform/src/inform.component.d.ts +59 -0
- package/components/mini-editor/index.d.ts +2 -0
- package/components/mini-editor/src/mini-editor.component.d.ts +91 -0
- package/components/mini-editor/src/mini-editor.model.d.ts +44 -0
- package/components/modal/index.d.ts +1 -0
- package/components/modal/src/modal.component.d.ts +30 -0
- package/components/operator/index.d.ts +1 -0
- package/components/operator/src/operator.component.d.ts +34 -0
- package/components/preview/index.d.ts +4 -0
- package/components/preview/src/preview-image/preview-image.component.d.ts +88 -0
- package/components/preview/src/preview-image/preview-image.types.d.ts +53 -0
- package/components/preview/src/preview-pdf/preview-pdf.component.d.ts +186 -0
- package/components/preview/src/preview-pdf/preview-pdf.types.d.ts +84 -0
- package/components/query-bar/index.d.ts +2 -0
- package/components/query-bar/src/components/actions-bar/actions-bar.component.d.ts +28 -0
- package/components/query-bar/src/components/build-chip/build-chip.component.d.ts +67 -0
- package/components/query-bar/src/components/chip-popover/chip-popover.component.d.ts +73 -0
- package/components/query-bar/src/components/field-picker/field-picker.component.d.ts +37 -0
- package/components/query-bar/src/components/inline-chip/inline-chip.component.d.ts +87 -0
- package/components/query-bar/src/components/inline-value-chip/inline-value-chip.component.d.ts +71 -0
- package/components/query-bar/src/components/popover-chip/popover-chip.component.d.ts +35 -0
- package/components/query-bar/src/components/saved-filters-menu/saved-filters-menu.component.d.ts +39 -0
- package/components/query-bar/src/query-bar.component.d.ts +137 -0
- package/components/query-bar/src/query-bar.model.d.ts +136 -0
- package/components/query-builder/index.d.ts +1 -0
- package/components/query-builder/src/query-builder.component.d.ts +26 -0
- package/components/quick-action/index.d.ts +1 -0
- package/components/quick-action/src/quick-action.component.d.ts +9 -0
- package/components/section/index.d.ts +2 -0
- package/components/section/src/section-item/section-item.component.d.ts +7 -0
- package/components/section/src/section.component.d.ts +18 -0
- package/components/side-drawer/index.d.ts +1 -0
- package/components/side-drawer/src/side-drawer.component.d.ts +30 -0
- package/components/splitter/index.d.ts +3 -0
- package/components/splitter/src/splitter-handle/splitter-handle.component.d.ts +24 -0
- package/components/splitter/src/splitter-panel/splitter-panel.component.d.ts +16 -0
- package/components/splitter/src/splitter-state.service.d.ts +26 -0
- package/components/splitter/src/splitter.component.d.ts +28 -0
- package/components/splitter/src/splitter.models.d.ts +23 -0
- package/components/stepper/index.d.ts +2 -0
- package/components/stepper/src/step.component.d.ts +17 -0
- package/components/stepper/src/stepper.component.d.ts +33 -0
- package/components/tab/index.d.ts +2 -0
- package/components/tab/src/tab-group.component.d.ts +37 -0
- package/components/tab/src/tab.component.d.ts +13 -0
- package/components/tab-router/index.d.ts +4 -0
- package/components/tab-router/src/actions/tab-router.action.d.ts +5 -0
- package/components/tab-router/src/components/tab-router-item/tab-router-item.component.d.ts +22 -0
- package/components/tab-router/src/components/tab-router-nav/tab-router-nav.component.d.ts +16 -0
- package/components/tab-router/src/components/tab-router-outlet/tab-router-outlet.component.d.ts +15 -0
- package/components/tab-router/src/decorators/tab.decorator.d.ts +16 -0
- package/components/tab-router/src/events/tab-router.event.d.ts +11 -0
- package/components/tab-router/src/models/index.d.ts +1 -0
- package/components/tab-router/src/models/tab-router.model.d.ts +21 -0
- package/components/tab-router/src/pipes/tab-info.pipe.d.ts +11 -0
- package/components/tab-router/src/services/tab-decorator.service.d.ts +9 -0
- package/components/tab-router/src/services/tab-router.service.d.ts +27 -0
- package/components/table/index.d.ts +11 -0
- package/components/table/src/components/column-title/column-title.component.d.ts +10 -0
- package/components/table/src/components/command/desktop-command.component.d.ts +14 -0
- package/components/table/src/components/command/pipes/command.pipe.d.ts +30 -0
- package/components/table/src/components/command/pipes/filter.pipe.d.ts +35 -0
- package/components/table/src/components/config/config.component.d.ts +25 -0
- package/components/table/src/components/desktop-cell/desktop-cell.component.d.ts +24 -0
- package/components/table/src/components/desktop-cell/view/view.component.d.ts +24 -0
- package/components/table/src/components/filter/column-filter/column-filter.component.d.ts +32 -0
- package/components/table/src/components/filter/external-filter/external-filter.component.d.ts +27 -0
- package/components/table/src/components/filter/index.d.ts +3 -0
- package/components/table/src/components/filter/mobile-filter/mobile-filter.component.d.ts +42 -0
- package/components/table/src/components/index.d.ts +3 -0
- package/components/table/src/components/popup-export/popup-export.component.d.ts +51 -0
- package/components/table/src/components/selector-action/action-filter.pipe.d.ts +34 -0
- package/components/table/src/components/selector-action/selector-action.component.d.ts +16 -0
- package/components/table/src/configurations/index.d.ts +1 -0
- package/components/table/src/configurations/table.configuration.d.ts +35 -0
- package/components/table/src/directives/index.d.ts +6 -0
- package/components/table/src/directives/sd-column-resize.directive.d.ts +13 -0
- package/components/table/src/directives/sd-table-cell-def.directive.d.ts +16 -0
- package/components/table/src/directives/sd-table-column-filter-def.directive.d.ts +16 -0
- package/components/table/src/directives/sd-table-expand-def.directive.d.ts +13 -0
- package/components/table/src/directives/sd-table-filter-def.directive.d.ts +14 -0
- package/components/table/src/directives/sd-table-footer-def.directive.d.ts +16 -0
- package/components/table/src/directives/sd-table-group-def.directive.d.ts +44 -0
- package/components/table/src/directives/sd-table-title-def.directive.d.ts +14 -0
- package/components/table/src/directives/sticky-shadow.directive.d.ts +17 -0
- package/components/table/src/models/index.d.ts +5 -0
- package/components/table/src/models/table-column.model.d.ts +119 -0
- package/components/table/src/models/table-command.model.d.ts +25 -0
- package/components/table/src/models/table-item.model.d.ts +65 -0
- package/components/table/src/models/table-option-config.model.d.ts +42 -0
- package/components/table/src/models/table-option-expand.model.d.ts +6 -0
- package/components/table/src/models/table-option-export.model.d.ts +42 -0
- package/components/table/src/models/table-option-group.model.d.ts +21 -0
- package/components/table/src/models/table-option-paginate.model.d.ts +7 -0
- package/components/table/src/models/table-option-reload.model.d.ts +7 -0
- package/components/table/src/models/table-option-selector.model.d.ts +105 -0
- package/components/table/src/models/table-option-sort.model.d.ts +3 -0
- package/components/table/src/models/table-option-style.model.d.ts +11 -0
- package/components/table/src/models/table-option-tree.model.d.ts +12 -0
- package/components/table/src/models/table-option.model.d.ts +181 -0
- package/components/table/src/pipes/filter-values.pipe.d.ts +8 -0
- package/components/table/src/pipes/index.d.ts +2 -0
- package/components/table/src/pipes/sd-group.pipe.d.ts +23 -0
- package/components/table/src/pipes/sd-tree.pipe.d.ts +9 -0
- package/components/table/src/pipes/selection-disabled.pipe.d.ts +9 -0
- package/components/table/src/pipes/selection-visible-select-all.pipe.d.ts +9 -0
- package/components/table/src/pipes/selection-visible.pipe.d.ts +9 -0
- package/components/table/src/services/column-width.util.d.ts +7 -0
- package/components/table/src/services/config.service.d.ts +21 -0
- package/components/table/src/services/index.d.ts +3 -0
- package/components/table/src/services/table-export/table-export.service.d.ts +26 -0
- package/components/table/src/services/table-filter/table-filter.model.d.ts +150 -0
- package/components/table/src/services/table-filter/table-filter.service.d.ts +20 -0
- package/components/table/src/services/table-format/table-format.service.d.ts +16 -0
- package/components/table/src/services/tree/tree.util.d.ts +14 -0
- package/components/table/src/table.component.d.ts +137 -0
- package/components/upload-file/index.d.ts +2 -0
- package/components/upload-file/src/components/preview/preview.component.d.ts +23 -0
- package/components/upload-file/src/configurations/index.d.ts +1 -0
- package/components/upload-file/src/configurations/upload-file.configuration.d.ts +50 -0
- package/components/upload-file/src/pipes/document.pipe.d.ts +8 -0
- package/components/upload-file/src/pipes/image.pipe.d.ts +8 -0
- package/components/upload-file/src/pipes/index.d.ts +2 -0
- package/components/upload-file/src/services/index.d.ts +2 -0
- package/components/upload-file/src/services/upload-file.model.d.ts +12 -0
- package/components/upload-file/src/services/upload-file.service.d.ts +10 -0
- package/components/upload-file/src/upload-file.component.d.ts +85 -0
- package/components/view/index.d.ts +1 -0
- package/components/view/src/view.component.d.ts +17 -0
- package/configurations/index.d.ts +1 -0
- package/configurations/src/sd-core.configuration.d.ts +10 -0
- package/directives/index.d.ts +6 -0
- package/directives/src/sd-desktop.directive.d.ts +7 -0
- package/directives/src/sd-hover-copy.directive.d.ts +16 -0
- package/directives/src/sd-href.directive.d.ts +9 -0
- package/directives/src/sd-mobile.directive.d.ts +7 -0
- package/directives/src/sd-scroll.directive.d.ts +14 -0
- package/directives/src/sd-tooltip.directive.d.ts +26 -0
- package/fesm2022/sdcorejs-angular-components-anchor.mjs +197 -0
- package/fesm2022/sdcorejs-angular-components-anchor.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-autoid-inspector.mjs +723 -0
- package/fesm2022/sdcorejs-angular-components-autoid-inspector.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-avatar.mjs +103 -0
- package/fesm2022/sdcorejs-angular-components-avatar.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-badge.mjs +138 -0
- package/fesm2022/sdcorejs-angular-components-badge.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-base.mjs +23 -0
- package/fesm2022/sdcorejs-angular-components-base.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-button.mjs +118 -0
- package/fesm2022/sdcorejs-angular-components-button.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-chart.mjs +290 -0
- package/fesm2022/sdcorejs-angular-components-chart.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-ckeditor-styles.mjs +38 -0
- package/fesm2022/sdcorejs-angular-components-ckeditor-styles.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-code-editor.mjs +128 -0
- package/fesm2022/sdcorejs-angular-components-code-editor.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-document-builder.mjs +5053 -0
- package/fesm2022/sdcorejs-angular-components-document-builder.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-editor.mjs +1079 -0
- package/fesm2022/sdcorejs-angular-components-editor.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-form-generic.mjs +6715 -0
- package/fesm2022/sdcorejs-angular-components-form-generic.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-history.mjs +51 -0
- package/fesm2022/sdcorejs-angular-components-history.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-import-excel.mjs +583 -0
- package/fesm2022/sdcorejs-angular-components-import-excel.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-inform.mjs +190 -0
- package/fesm2022/sdcorejs-angular-components-inform.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-mini-editor.mjs +333 -0
- package/fesm2022/sdcorejs-angular-components-mini-editor.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-modal.mjs +108 -0
- package/fesm2022/sdcorejs-angular-components-modal.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-operator.mjs +75 -0
- package/fesm2022/sdcorejs-angular-components-operator.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-preview.mjs +1987 -0
- package/fesm2022/sdcorejs-angular-components-preview.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-query-bar.mjs +1430 -0
- package/fesm2022/sdcorejs-angular-components-query-bar.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-query-builder.mjs +83 -0
- package/fesm2022/sdcorejs-angular-components-query-builder.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-quick-action.mjs +22 -0
- package/fesm2022/sdcorejs-angular-components-quick-action.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-section.mjs +64 -0
- package/fesm2022/sdcorejs-angular-components-section.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-side-drawer.mjs +129 -0
- package/fesm2022/sdcorejs-angular-components-side-drawer.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-splitter.mjs +649 -0
- package/fesm2022/sdcorejs-angular-components-splitter.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-stepper.mjs +140 -0
- package/fesm2022/sdcorejs-angular-components-stepper.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-tab-router.mjs +605 -0
- package/fesm2022/sdcorejs-angular-components-tab-router.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-tab.mjs +145 -0
- package/fesm2022/sdcorejs-angular-components-tab.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-table.mjs +4524 -0
- package/fesm2022/sdcorejs-angular-components-table.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-upload-file.mjs +868 -0
- package/fesm2022/sdcorejs-angular-components-upload-file.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components-view.mjs +48 -0
- package/fesm2022/sdcorejs-angular-components-view.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-components.mjs +28 -0
- package/fesm2022/sdcorejs-angular-components.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-configurations.mjs +10 -0
- package/fesm2022/sdcorejs-angular-configurations.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-directives.mjs +497 -0
- package/fesm2022/sdcorejs-angular-directives.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs +454 -0
- package/fesm2022/sdcorejs-angular-forms-autocomplete.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-forms-checkbox.mjs +139 -0
- package/fesm2022/sdcorejs-angular-forms-checkbox.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs +364 -0
- package/fesm2022/sdcorejs-angular-forms-chip-calendar.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-forms-chip.mjs +363 -0
- package/fesm2022/sdcorejs-angular-forms-chip.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-forms-date-range.mjs +354 -0
- package/fesm2022/sdcorejs-angular-forms-date-range.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-forms-date.mjs +356 -0
- package/fesm2022/sdcorejs-angular-forms-date.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-forms-datetime.mjs +748 -0
- package/fesm2022/sdcorejs-angular-forms-datetime.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-forms-directives.mjs +67 -0
- package/fesm2022/sdcorejs-angular-forms-directives.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-forms-input-color.mjs +117 -0
- package/fesm2022/sdcorejs-angular-forms-input-color.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-forms-input-number.mjs +438 -0
- package/fesm2022/sdcorejs-angular-forms-input-number.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-forms-input.mjs +354 -0
- package/fesm2022/sdcorejs-angular-forms-input.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-forms-label.mjs +51 -0
- package/fesm2022/sdcorejs-angular-forms-label.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-forms-models.mjs +137 -0
- package/fesm2022/sdcorejs-angular-forms-models.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-forms-radio.mjs +190 -0
- package/fesm2022/sdcorejs-angular-forms-radio.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-forms-select.mjs +593 -0
- package/fesm2022/sdcorejs-angular-forms-select.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-forms-switch.mjs +144 -0
- package/fesm2022/sdcorejs-angular-forms-switch.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-forms-textarea.mjs +300 -0
- package/fesm2022/sdcorejs-angular-forms-textarea.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-forms.mjs +48 -0
- package/fesm2022/sdcorejs-angular-forms.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-handlers.mjs +67 -0
- package/fesm2022/sdcorejs-angular-handlers.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-i18n.mjs +2592 -0
- package/fesm2022/sdcorejs-angular-i18n.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-interceptors.mjs +166 -0
- package/fesm2022/sdcorejs-angular-interceptors.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-models.mjs +6 -0
- package/fesm2022/sdcorejs-angular-models.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-modules-auth.mjs +137 -0
- package/fesm2022/sdcorejs-angular-modules-auth.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-modules-authom.mjs +360 -0
- package/fesm2022/sdcorejs-angular-modules-authom.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-modules-keycloak.mjs +127 -0
- package/fesm2022/sdcorejs-angular-modules-keycloak.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-modules-layout.mjs +1633 -0
- package/fesm2022/sdcorejs-angular-modules-layout.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-modules-permission.mjs +249 -0
- package/fesm2022/sdcorejs-angular-modules-permission.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-modules.mjs +10 -0
- package/fesm2022/sdcorejs-angular-modules.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-pipes.mjs +149 -0
- package/fesm2022/sdcorejs-angular-pipes.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-services-api.mjs +235 -0
- package/fesm2022/sdcorejs-angular-services-api.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-services-cache.mjs +161 -0
- package/fesm2022/sdcorejs-angular-services-cache.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-services-confirm.mjs +208 -0
- package/fesm2022/sdcorejs-angular-services-confirm.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-services-docx.mjs +300 -0
- package/fesm2022/sdcorejs-angular-services-docx.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-services-excel.mjs +422 -0
- package/fesm2022/sdcorejs-angular-services-excel.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-services-license.mjs +104 -0
- package/fesm2022/sdcorejs-angular-services-license.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-services-loading.mjs +92 -0
- package/fesm2022/sdcorejs-angular-services-loading.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-services-notify.mjs +268 -0
- package/fesm2022/sdcorejs-angular-services-notify.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-services-storage.mjs +174 -0
- package/fesm2022/sdcorejs-angular-services-storage.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-services.mjs +13 -0
- package/fesm2022/sdcorejs-angular-services.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-utilities-data-state.mjs +38 -0
- package/fesm2022/sdcorejs-angular-utilities-data-state.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-utilities-extensions.mjs +391 -0
- package/fesm2022/sdcorejs-angular-utilities-extensions.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-utilities-models.mjs +55 -0
- package/fesm2022/sdcorejs-angular-utilities-models.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular-utilities.mjs +8 -0
- package/fesm2022/sdcorejs-angular-utilities.mjs.map +1 -0
- package/fesm2022/sdcorejs-angular.mjs +19 -0
- package/fesm2022/sdcorejs-angular.mjs.map +1 -0
- package/forms/autocomplete/index.d.ts +1 -0
- package/forms/autocomplete/src/autocomplete.component.d.ts +93 -0
- package/forms/checkbox/index.d.ts +1 -0
- package/forms/checkbox/src/checkbox.component.d.ts +28 -0
- package/forms/chip/index.d.ts +1 -0
- package/forms/chip/src/chip.component.d.ts +71 -0
- package/forms/chip/src/index.d.ts +2 -0
- package/forms/chip/src/pipes/index.d.ts +1 -0
- package/forms/chip/src/pipes/removable-chip.pipe.d.ts +8 -0
- package/forms/chip-calendar/index.d.ts +1 -0
- package/forms/chip-calendar/src/chip-calendar.component.d.ts +71 -0
- package/forms/chip-calendar/src/pipes/index.d.ts +1 -0
- package/forms/chip-calendar/src/pipes/removable-chip.pipe.d.ts +8 -0
- package/forms/date/index.d.ts +1 -0
- package/forms/date/src/date.component.d.ts +79 -0
- package/forms/date-range/index.d.ts +1 -0
- package/forms/date-range/src/date-range.component.d.ts +81 -0
- package/forms/datetime/index.d.ts +1 -0
- package/forms/datetime/src/datetime.component.d.ts +89 -0
- package/forms/datetime/src/popup/sd-datetime-picker.component.d.ts +37 -0
- package/forms/datetime/src/popup/sd-time-spinner.component.d.ts +41 -0
- package/forms/directives/index.d.ts +4 -0
- package/forms/directives/src/item-def.directive.d.ts +13 -0
- package/forms/directives/src/label-def.directive.d.ts +9 -0
- package/forms/directives/src/suffix-def.directive.d.ts +9 -0
- package/forms/directives/src/view-def.directive.d.ts +14 -0
- package/forms/index.d.ts +17 -0
- package/forms/input/index.d.ts +1 -0
- package/forms/input/src/input.component.d.ts +84 -0
- package/forms/input-color/index.d.ts +1 -0
- package/forms/input-color/src/input-color.component.d.ts +32 -0
- package/forms/input-number/index.d.ts +1 -0
- package/forms/input-number/src/input-number.component.d.ts +95 -0
- package/forms/label/index.d.ts +1 -0
- package/forms/label/src/label.component.d.ts +13 -0
- package/forms/models/index.d.ts +6 -0
- package/forms/models/src/form-control-state.d.ts +23 -0
- package/forms/models/src/sd-custom-validator.model.d.ts +15 -0
- package/forms/models/src/sd-form-control.model.d.ts +21 -0
- package/forms/models/src/sd-form.configuration.d.ts +6 -0
- package/forms/models/src/sd-search.model.d.ts +7 -0
- package/forms/models/src/sd-selection-data.model.d.ts +7 -0
- package/forms/radio/index.d.ts +1 -0
- package/forms/radio/src/radio.component.d.ts +49 -0
- package/forms/select/index.d.ts +1 -0
- package/forms/select/src/select.component.d.ts +93 -0
- package/forms/src/forms.module.d.ts +14 -0
- package/forms/switch/index.d.ts +1 -0
- package/forms/switch/src/switch.component.d.ts +32 -0
- package/forms/textarea/index.d.ts +1 -0
- package/forms/textarea/src/textarea.component.d.ts +65 -0
- package/handlers/global-error.handler.d.ts +9 -0
- package/handlers/index.d.ts +1 -0
- package/i18n/index.d.ts +5 -0
- package/i18n/src/en.d.ts +449 -0
- package/i18n/src/i18n.messages.d.ts +2 -0
- package/i18n/src/i18n.pipe.d.ts +9 -0
- package/i18n/src/i18n.service.d.ts +14 -0
- package/i18n/src/i18n.token.d.ts +1 -0
- package/i18n/src/i18n.types.d.ts +31 -0
- package/i18n/src/ja.d.ts +2 -0
- package/i18n/src/ko.d.ts +2 -0
- package/i18n/src/vi.d.ts +2 -0
- package/i18n/src/zh.d.ts +2 -0
- package/index.d.ts +5 -0
- package/interceptors/index.d.ts +2 -0
- package/interceptors/no-internet/no-internet.interceptor.d.ts +14 -0
- package/interceptors/unauthorized/unauthorized.interceptor.d.ts +12 -0
- package/models/index.d.ts +1 -0
- package/models/src/language.model.d.ts +2 -0
- package/modules/auth/configurations/auth.configuration.d.ts +19 -0
- package/modules/auth/configurations/index.d.ts +1 -0
- package/modules/auth/guards/auth.guard.d.ts +11 -0
- package/modules/auth/guards/index.d.ts +2 -0
- package/modules/auth/guards/portal.guard.d.ts +11 -0
- package/modules/auth/index.d.ts +3 -0
- package/modules/auth/services/auth.model.d.ts +8 -0
- package/modules/auth/services/auth.service.d.ts +17 -0
- package/modules/auth/services/index.d.ts +2 -0
- package/modules/authom/authom.configuration.d.ts +17 -0
- package/modules/authom/authom.interceptor.d.ts +3 -0
- package/modules/authom/authom.module.d.ts +16 -0
- package/modules/authom/authom.service.d.ts +32 -0
- package/modules/authom/index.d.ts +35 -0
- package/modules/index.d.ts +5 -0
- package/modules/keycloak/index.d.ts +4 -0
- package/modules/keycloak/keycloak.configuration.d.ts +11 -0
- package/modules/keycloak/keycloak.interceptor.d.ts +2 -0
- package/modules/keycloak/keycloak.module.d.ts +18 -0
- package/modules/keycloak/keycloak.service.d.ts +14 -0
- package/modules/layout/components/index.d.ts +4 -0
- package/modules/layout/components/layout-main/layout-main.component.d.ts +12 -0
- package/modules/layout/components/page/page.component.d.ts +10 -0
- package/modules/layout/components/sidebar-mobile-v1/components/sidebar/sidebar.component.d.ts +35 -0
- package/modules/layout/components/sidebar-mobile-v1/components/user/user.component.d.ts +24 -0
- package/modules/layout/components/sidebar-mobile-v1/main.component.d.ts +21 -0
- package/modules/layout/components/sidebar-v1/components/sidebar/sidebar.component.d.ts +55 -0
- package/modules/layout/components/sidebar-v1/components/user/user.component.d.ts +22 -0
- package/modules/layout/components/sidebar-v1/main.component.d.ts +24 -0
- package/modules/layout/configurations/index.d.ts +1 -0
- package/modules/layout/configurations/layout.configuration.d.ts +67 -0
- package/modules/layout/index.d.ts +5 -0
- package/modules/layout/layout.module.d.ts +7 -0
- package/modules/layout/layout.routing.d.ts +2 -0
- package/modules/layout/modules/forbidden/forbidden.module.d.ts +8 -0
- package/modules/layout/modules/forbidden/forbidden.routing.d.ts +2 -0
- package/modules/layout/modules/forbidden/index.d.ts +1 -0
- package/modules/layout/modules/forbidden/pages/root/root.component.d.ts +10 -0
- package/modules/layout/modules/home/components/home-page/home-page.component.d.ts +33 -0
- package/modules/layout/modules/home/guards/home-redirect.guard.d.ts +11 -0
- package/modules/layout/modules/home/home.module.d.ts +8 -0
- package/modules/layout/modules/home/home.routing.d.ts +7 -0
- package/modules/layout/modules/home/index.d.ts +1 -0
- package/modules/layout/modules/index.d.ts +3 -0
- package/modules/layout/modules/not-found/index.d.ts +1 -0
- package/modules/layout/modules/not-found/not-found.module.d.ts +8 -0
- package/modules/layout/modules/not-found/not-found.routing.d.ts +2 -0
- package/modules/layout/modules/not-found/pages/root/root.component.d.ts +10 -0
- package/modules/layout/pipes/high-light-search.pipe.d.ts +10 -0
- package/modules/layout/pipes/index.d.ts +3 -0
- package/modules/layout/pipes/menu-focus.pipe.d.ts +10 -0
- package/modules/layout/pipes/menu.pipe.d.ts +13 -0
- package/modules/layout/services/index.d.ts +3 -0
- package/modules/layout/services/layout.service.d.ts +10 -0
- package/modules/layout/services/menu/menu.model.d.ts +24 -0
- package/modules/layout/services/storage/storage.service.d.ts +13 -0
- package/modules/permission/index.d.ts +4 -0
- package/modules/permission/src/configurations/index.d.ts +1 -0
- package/modules/permission/src/configurations/permission.configuration.d.ts +63 -0
- package/modules/permission/src/directives/index.d.ts +1 -0
- package/modules/permission/src/directives/permission.directive.d.ts +9 -0
- package/modules/permission/src/guards/index.d.ts +1 -0
- package/modules/permission/src/guards/permission.guard.d.ts +14 -0
- package/modules/permission/src/services/index.d.ts +1 -0
- package/modules/permission/src/services/permission.service.d.ts +12 -0
- package/package.json +344 -0
- package/pipes/index.d.ts +4 -0
- package/pipes/src/empty.pipe.d.ts +7 -0
- package/pipes/src/format-number.pipe.d.ts +11 -0
- package/pipes/src/safe-html.pipe.d.ts +11 -0
- package/pipes/src/time-different.pipe.d.ts +13 -0
- package/public-api.d.ts +10 -0
- package/services/api/index.d.ts +4 -0
- package/services/api/src/api.model.d.ts +36 -0
- package/services/api/src/api.module.d.ts +6 -0
- package/services/api/src/api.service.d.ts +19 -0
- package/services/api/src/interceptors/api.interceptor.d.ts +9 -0
- package/services/cache/index.d.ts +2 -0
- package/services/cache/src/cache.model.d.ts +30 -0
- package/services/cache/src/cache.service.d.ts +9 -0
- package/services/confirm/index.d.ts +1 -0
- package/services/confirm/src/lib/components/dialog-confirm/dialog-confirm.component.d.ts +46 -0
- package/services/confirm/src/lib/confirm.service.d.ts +55 -0
- package/services/confirm/src/public-api.d.ts +2 -0
- package/services/docx/index.d.ts +1 -0
- package/services/docx/src/lib/docx.model.d.ts +9 -0
- package/services/docx/src/lib/docx.service.d.ts +15 -0
- package/services/docx/src/lib/pandoc-core.d.ts +11 -0
- package/services/docx/src/public-api.d.ts +2 -0
- package/services/excel/index.d.ts +1 -0
- package/services/excel/src/lib/excel.model.d.ts +31 -0
- package/services/excel/src/lib/excel.service.d.ts +19 -0
- package/services/excel/src/public-api.d.ts +2 -0
- package/services/index.d.ts +8 -0
- package/services/license/index.d.ts +1 -0
- package/services/license/src/license.service.d.ts +10 -0
- package/services/loading/index.d.ts +1 -0
- package/services/loading/src/loading.service.d.ts +14 -0
- package/services/notify/index.d.ts +2 -0
- package/services/notify/src/components/toast/toast.component.d.ts +28 -0
- package/services/notify/src/components/toast-container.component.d.ts +8 -0
- package/services/notify/src/notify.model.d.ts +16 -0
- package/services/notify/src/notify.service.d.ts +20 -0
- package/services/storage/index.d.ts +2 -0
- package/services/storage/src/storage.model.d.ts +20 -0
- package/services/storage/src/storage.service.d.ts +10 -0
- package/utilities/data-state/index.d.ts +1 -0
- package/utilities/data-state/src/data-state.d.ts +11 -0
- package/utilities/extensions/index.d.ts +6 -0
- package/utilities/extensions/src/array.extension.d.ts +1 -0
- package/utilities/extensions/src/color.extension.d.ts +5 -0
- package/utilities/extensions/src/date.extension.d.ts +1 -0
- package/utilities/extensions/src/number.extension.d.ts +1 -0
- package/utilities/extensions/src/string.extension.d.ts +50 -0
- package/utilities/extensions/src/utility.extension.d.ts +31 -0
- package/utilities/index.d.ts +3 -0
- package/utilities/models/index.d.ts +12 -0
- package/utilities/models/src/color.model.d.ts +4 -0
- package/utilities/models/src/empty.model.d.ts +4 -0
- package/utilities/models/src/filter.model.d.ts +12 -0
- package/utilities/models/src/icon.model.d.ts +2 -0
- package/utilities/models/src/maybe-async.model.d.ts +10 -0
- package/utilities/models/src/nested-key-of.model.d.ts +4 -0
- package/utilities/models/src/operator.model.d.ts +13 -0
- package/utilities/models/src/order.model.d.ts +4 -0
- package/utilities/models/src/paging.model.d.ts +8 -0
- package/utilities/models/src/pattern.model.d.ts +21 -0
- package/utilities/models/src/size.model.d.ts +4 -0
- package/utilities/models/src/unwrap-signal.model.d.ts +6 -0
|
@@ -0,0 +1,1633 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, ElementRef, input, booleanAttribute, effect, Component, Injectable, InjectionToken, signal, Pipe, output, DestroyRef, computed, untracked, viewChild, Inject, NgModule } from '@angular/core';
|
|
3
|
+
import * as i1$4 from '@angular/common';
|
|
4
|
+
import { CommonModule, NgTemplateOutlet } from '@angular/common';
|
|
5
|
+
import * as i1$6 from '@angular/router';
|
|
6
|
+
import { Router, NavigationEnd, RouterModule, ActivatedRoute } from '@angular/router';
|
|
7
|
+
import { __decorate } from 'tslib';
|
|
8
|
+
import * as i1$3 from '@angular/material/icon';
|
|
9
|
+
import { MatIconModule } from '@angular/material/icon';
|
|
10
|
+
import { SdAvatar, SdTabComponent, SdButton } from '@sdcorejs/angular/components';
|
|
11
|
+
import { I18nService, TranslatePipe, I18N_STORAGE_KEY, I18N_MESSAGES } from '@sdcorejs/angular/i18n';
|
|
12
|
+
import * as i1 from '@sdcorejs/angular/services';
|
|
13
|
+
import { resolveMaybeAsync } from '@sdcorejs/utils/models';
|
|
14
|
+
import * as uuid from 'uuid';
|
|
15
|
+
import { Utilities, StringUtilities, BrowserUtilities } from '@sdcorejs/utils/fns';
|
|
16
|
+
import * as i1$1 from '@sdcorejs/angular/modules/permission';
|
|
17
|
+
import * as i1$5 from '@angular/material/sidenav';
|
|
18
|
+
import { MatSidenavModule } from '@angular/material/sidenav';
|
|
19
|
+
import { NestedTreeControl } from '@angular/cdk/tree';
|
|
20
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
21
|
+
import { FormsModule } from '@angular/forms';
|
|
22
|
+
import { MatInputModule } from '@angular/material/input';
|
|
23
|
+
import * as i4 from '@angular/material/tooltip';
|
|
24
|
+
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
25
|
+
import * as i3 from '@angular/material/tree';
|
|
26
|
+
import { MatTreeNestedDataSource, MatTreeModule } from '@angular/material/tree';
|
|
27
|
+
import { SdInput, SdSuffixDefDirective } from '@sdcorejs/angular/forms';
|
|
28
|
+
import { SdSafeHtmlPipe } from '@sdcorejs/angular/pipes';
|
|
29
|
+
import * as i2 from '@angular/material/button';
|
|
30
|
+
import { MatButtonModule } from '@angular/material/button';
|
|
31
|
+
import * as i1$2 from '@angular/material/menu';
|
|
32
|
+
import { MatMenuModule } from '@angular/material/menu';
|
|
33
|
+
|
|
34
|
+
class SdPageComponent {
|
|
35
|
+
el = inject(ElementRef);
|
|
36
|
+
title = input('', { alias: 'title' });
|
|
37
|
+
description = input('', { alias: 'description' });
|
|
38
|
+
noHeader = input(false, { transform: booleanAttribute, alias: 'noHeader' });
|
|
39
|
+
constructor() {
|
|
40
|
+
effect(() => {
|
|
41
|
+
if (this.title()) {
|
|
42
|
+
this.el.nativeElement.removeAttribute('title');
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
47
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: SdPageComponent, isStandalone: true, selector: "sd-page", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, noHeader: { classPropertyName: "noHeader", publicName: "noHeader", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (!noHeader()) {\n <div class=\"c-page-header bg-white\">\n <div class=\"p-16 d-flex align-items-center w-full justify-content-between\">\n <div class=\"d-flex\">\n <ng-content select=\"[headerLeft]\">\n <div class=\"d-flex flex-column\">\n <div class=\"T20M\">{{ title() }}</div>\n @if (description()) {\n <div class=\"T14R text-secondary mt-4\">{{ description() }}</div>\n }\n </div>\n </ng-content>\n </div>\n <ng-content select=\"[headerRight]\"></ng-content>\n </div>\n </div>\n}\n\n<div class=\"c-page-wrapper px-0\">\n <div class=\"c-page-content\">\n <ng-content></ng-content>\n </div>\n</div>\n", styles: [":host{height:100%;display:flex;flex-direction:column;background-color:#f9f9f9}.c-page-header{box-shadow:0 1px 2px #2f31361a;z-index:1;position:relative}.c-page-wrapper{flex:1;display:flex;flex-direction:row;width:100%;overflow-y:auto;max-height:100vh}.c-page-wrapper .c-page-content{flex:1;height:100%;width:100%}.c-page-wrapper .c-page-right{position:-webkit-sticky;position:sticky;top:0;height:100%;overflow-y:auto}\n"] });
|
|
48
|
+
}
|
|
49
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdPageComponent, decorators: [{
|
|
50
|
+
type: Component,
|
|
51
|
+
args: [{ selector: 'sd-page', template: "@if (!noHeader()) {\n <div class=\"c-page-header bg-white\">\n <div class=\"p-16 d-flex align-items-center w-full justify-content-between\">\n <div class=\"d-flex\">\n <ng-content select=\"[headerLeft]\">\n <div class=\"d-flex flex-column\">\n <div class=\"T20M\">{{ title() }}</div>\n @if (description()) {\n <div class=\"T14R text-secondary mt-4\">{{ description() }}</div>\n }\n </div>\n </ng-content>\n </div>\n <ng-content select=\"[headerRight]\"></ng-content>\n </div>\n </div>\n}\n\n<div class=\"c-page-wrapper px-0\">\n <div class=\"c-page-content\">\n <ng-content></ng-content>\n </div>\n</div>\n", styles: [":host{height:100%;display:flex;flex-direction:column;background-color:#f9f9f9}.c-page-header{box-shadow:0 1px 2px #2f31361a;z-index:1;position:relative}.c-page-wrapper{flex:1;display:flex;flex-direction:row;width:100%;overflow-y:auto;max-height:100vh}.c-page-wrapper .c-page-content{flex:1;height:100%;width:100%}.c-page-wrapper .c-page-right{position:-webkit-sticky;position:sticky;top:0;height:100%;overflow-y:auto}\n"] }]
|
|
52
|
+
}], ctorParameters: () => [] });
|
|
53
|
+
|
|
54
|
+
class SdLayoutStorageService {
|
|
55
|
+
sdStorageService;
|
|
56
|
+
// Thông tin state của sidebar
|
|
57
|
+
isShowSidebar;
|
|
58
|
+
menuLockStatus;
|
|
59
|
+
lastActiveMenuGroupId;
|
|
60
|
+
pinnedMenuGroup;
|
|
61
|
+
// End
|
|
62
|
+
constructor(sdStorageService) {
|
|
63
|
+
this.sdStorageService = sdStorageService;
|
|
64
|
+
// State sidebar
|
|
65
|
+
this.isShowSidebar = this.sdStorageService.create('cb07c316-ed6d-4620-9e92-53dbef6aa983');
|
|
66
|
+
this.menuLockStatus = this.sdStorageService.create('2c2f4816-18b3-4ec3-8177-7b90bff036c3');
|
|
67
|
+
this.lastActiveMenuGroupId = this.sdStorageService.create('2e6961d0-3380-4a94-a6a1-38837560cd96');
|
|
68
|
+
this.pinnedMenuGroup = this.sdStorageService.create('e81da122-5dab-4250-b309-64197fb19d44');
|
|
69
|
+
// End
|
|
70
|
+
}
|
|
71
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdLayoutStorageService, deps: [{ token: i1.SdStorageService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
72
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdLayoutStorageService, providedIn: 'root' });
|
|
73
|
+
}
|
|
74
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdLayoutStorageService, decorators: [{
|
|
75
|
+
type: Injectable,
|
|
76
|
+
args: [{
|
|
77
|
+
providedIn: 'root',
|
|
78
|
+
}]
|
|
79
|
+
}], ctorParameters: () => [{ type: i1.SdStorageService }] });
|
|
80
|
+
|
|
81
|
+
const SD_LAYOUT_CONFIGURATION = new InjectionToken('sd.layout.configuration');
|
|
82
|
+
|
|
83
|
+
class SdLayoutService {
|
|
84
|
+
// ==========================================
|
|
85
|
+
// INJECT CONFIGURATIONS
|
|
86
|
+
// ==========================================
|
|
87
|
+
// WHY: optional=true cho phép layout module chạy không cần SD_LAYOUT_CONFIGURATION
|
|
88
|
+
// (use case demo / khởi tạo nhanh). Khi token không có → fallback mock data trong constructor.
|
|
89
|
+
#layoutConfiguration = inject(SD_LAYOUT_CONFIGURATION, { optional: true });
|
|
90
|
+
#i18n = inject(I18nService);
|
|
91
|
+
// ==========================================
|
|
92
|
+
// SHARED SIGNALS (STATE)
|
|
93
|
+
// ==========================================
|
|
94
|
+
userInfo = signal(undefined);
|
|
95
|
+
sidebar = signal(undefined);
|
|
96
|
+
constructor() {
|
|
97
|
+
if (!this.#layoutConfiguration) {
|
|
98
|
+
// WHY: cho phép layout module chạy không cần config (use case demo / khởi tạo nhanh).
|
|
99
|
+
// Fallback dùng mock data đã i18n hóa; thật tế khi tích hợp portal cần provide SD_LAYOUT_CONFIGURATION.
|
|
100
|
+
// @i18n-ignore dev-facing console.warn — không cần dịch
|
|
101
|
+
console.warn(
|
|
102
|
+
// @i18n-ignore
|
|
103
|
+
'[SdLayoutService] SD_LAYOUT_CONFIGURATION chưa được inject — đang dùng mock data. ' +
|
|
104
|
+
// @i18n-ignore
|
|
105
|
+
'Provide token này (xem ISdLayoutConfiguration) để custom user info / sidebar / signout.');
|
|
106
|
+
this.userInfo.set(this.#mockUserInfo());
|
|
107
|
+
this.sidebar.set(this.#mockSidebar());
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
this.#initUserInfo();
|
|
111
|
+
this.#initSidebar();
|
|
112
|
+
}
|
|
113
|
+
// ==========================================
|
|
114
|
+
// PRIVATE METHODS
|
|
115
|
+
// ==========================================
|
|
116
|
+
#initUserInfo() {
|
|
117
|
+
const userInfoConfig = this.#layoutConfiguration.userInfo;
|
|
118
|
+
if (typeof userInfoConfig === 'function') {
|
|
119
|
+
resolveMaybeAsync(userInfoConfig()).then(userInfo => this.userInfo.set(userInfo));
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
this.userInfo.set(userInfoConfig);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
#initSidebar() {
|
|
126
|
+
const sidebarConfig = this.#layoutConfiguration.sidebar;
|
|
127
|
+
if (typeof sidebarConfig === 'function') {
|
|
128
|
+
resolveMaybeAsync(sidebarConfig()).then(config => this.sidebar.set(config));
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
this.sidebar.set(sidebarConfig);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
#mockUserInfo() {
|
|
135
|
+
return {
|
|
136
|
+
fullName: this.#i18n.t('core.module.layout.mock.user.full-name'),
|
|
137
|
+
email: 'demo@example.com',
|
|
138
|
+
username: 'demo',
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
#mockSidebar() {
|
|
142
|
+
return {
|
|
143
|
+
version: 1,
|
|
144
|
+
defaultTitle: 'Back Office',
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdLayoutService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
148
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdLayoutService, providedIn: 'root' // Có thể đổi thành 'any' hoặc khai báo trong mảng providers của LayoutModule tùy kiến trúc của bạn
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdLayoutService, decorators: [{
|
|
152
|
+
type: Injectable,
|
|
153
|
+
args: [{
|
|
154
|
+
providedIn: 'root' // Có thể đổi thành 'any' hoặc khai báo trong mảng providers của LayoutModule tùy kiến trúc của bạn
|
|
155
|
+
}]
|
|
156
|
+
}], ctorParameters: () => [] });
|
|
157
|
+
|
|
158
|
+
// End
|
|
159
|
+
class MenuPipe {
|
|
160
|
+
permissionService;
|
|
161
|
+
constructor(permissionService) {
|
|
162
|
+
this.permissionService = permissionService;
|
|
163
|
+
}
|
|
164
|
+
transform(menus) {
|
|
165
|
+
const results = [];
|
|
166
|
+
const check = (menu) => {
|
|
167
|
+
if ('children' in menu) {
|
|
168
|
+
const children = [];
|
|
169
|
+
menu.children?.forEach(childMenu => {
|
|
170
|
+
childMenu = check(childMenu);
|
|
171
|
+
if (childMenu) {
|
|
172
|
+
children.push({ ...childMenu, id: this.#getHashIdMenu(childMenu) });
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
if (!children.length) {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
...menu,
|
|
180
|
+
children,
|
|
181
|
+
id: this.#getHashIdMenu(menu),
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
if ('permission' in menu) {
|
|
185
|
+
const path = menu?.path?.includes('http') ? menu.path : menu.path;
|
|
186
|
+
if (!menu.path) {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
if ((typeof menu.permission === 'string' || Array.isArray(menu.permission)) && this.permissionService.hasPermission(menu.permission, menu.permissionKey)) {
|
|
190
|
+
return {
|
|
191
|
+
...menu,
|
|
192
|
+
path,
|
|
193
|
+
id: this.#getHashIdMenu(menu),
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
if (typeof menu.permission === 'boolean' && menu.permission) {
|
|
197
|
+
return {
|
|
198
|
+
...menu,
|
|
199
|
+
path,
|
|
200
|
+
id: this.#getHashIdMenu(menu),
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
if (typeof menu.permission === 'function' && menu.permission()) {
|
|
204
|
+
return {
|
|
205
|
+
...menu,
|
|
206
|
+
path,
|
|
207
|
+
id: this.#getHashIdMenu(menu),
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
return {
|
|
213
|
+
...menu,
|
|
214
|
+
id: uuid.v4(),
|
|
215
|
+
};
|
|
216
|
+
};
|
|
217
|
+
menus?.forEach(menu => {
|
|
218
|
+
menu = check(menu);
|
|
219
|
+
if (menu) {
|
|
220
|
+
results.push(menu);
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
return results;
|
|
224
|
+
}
|
|
225
|
+
#getHashIdMenu = (menu) => {
|
|
226
|
+
const extendedMenu = menu;
|
|
227
|
+
const hashKeys = ['title', 'path', 'permission', 'permissionKey', 'queryParams', 'icon', 'level', 'tooltipTitle'];
|
|
228
|
+
const hashData = hashKeys.reduce((acc, key) => {
|
|
229
|
+
const value = extendedMenu[key];
|
|
230
|
+
if (value !== undefined && value !== null) {
|
|
231
|
+
acc[key] = value;
|
|
232
|
+
}
|
|
233
|
+
return acc;
|
|
234
|
+
}, {});
|
|
235
|
+
return Object.keys(hashData).length > 0 ? Utilities.hash(hashData) : uuid.v4();
|
|
236
|
+
};
|
|
237
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: MenuPipe, deps: [{ token: i1$1.SdPermissionService }], target: i0.ɵɵFactoryTarget.Pipe });
|
|
238
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.21", ngImport: i0, type: MenuPipe, isStandalone: true, name: "menu" });
|
|
239
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: MenuPipe, providedIn: 'root' });
|
|
240
|
+
}
|
|
241
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: MenuPipe, decorators: [{
|
|
242
|
+
type: Pipe,
|
|
243
|
+
args: [{
|
|
244
|
+
name: 'menu',
|
|
245
|
+
}]
|
|
246
|
+
}, {
|
|
247
|
+
type: Injectable,
|
|
248
|
+
args: [{
|
|
249
|
+
providedIn: 'root',
|
|
250
|
+
}]
|
|
251
|
+
}], ctorParameters: () => [{ type: i1$1.SdPermissionService }] });
|
|
252
|
+
|
|
253
|
+
// End
|
|
254
|
+
class MenuFocusPipe {
|
|
255
|
+
transform(routePath, menuItem) {
|
|
256
|
+
if (!routePath) {
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
if ('children' in menuItem && menuItem.children) {
|
|
260
|
+
return menuItem.children.some(child => {
|
|
261
|
+
return 'path' in child && child.path ? this.#match(routePath, child.path) : false;
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
return 'path' in menuItem && this.#match(routePath, menuItem.path);
|
|
265
|
+
}
|
|
266
|
+
#match = (routePath, path) => {
|
|
267
|
+
if (!path) {
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
270
|
+
if (routePath === path) {
|
|
271
|
+
return true;
|
|
272
|
+
}
|
|
273
|
+
return this.#normalizePath(routePath).startsWith(this.#normalizePath(path));
|
|
274
|
+
};
|
|
275
|
+
#normalizePath = (p) => {
|
|
276
|
+
return p.endsWith('/') ? p : p + '/';
|
|
277
|
+
};
|
|
278
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: MenuFocusPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
279
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.21", ngImport: i0, type: MenuFocusPipe, isStandalone: true, name: "menuFocus" });
|
|
280
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: MenuFocusPipe, providedIn: 'root' });
|
|
281
|
+
}
|
|
282
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: MenuFocusPipe, decorators: [{
|
|
283
|
+
type: Pipe,
|
|
284
|
+
args: [{
|
|
285
|
+
name: 'menuFocus',
|
|
286
|
+
}]
|
|
287
|
+
}, {
|
|
288
|
+
type: Injectable,
|
|
289
|
+
args: [{ providedIn: 'root' }]
|
|
290
|
+
}] });
|
|
291
|
+
|
|
292
|
+
class HighlightSearchPipe {
|
|
293
|
+
transform(value, keyword, args) {
|
|
294
|
+
const { color = '#ffff00' } = args ?? {};
|
|
295
|
+
keyword = this.#normalizeValue(keyword);
|
|
296
|
+
if (!keyword || keyword.length < 2) {
|
|
297
|
+
return value;
|
|
298
|
+
}
|
|
299
|
+
value = value?.trim() || '';
|
|
300
|
+
const regex = new RegExp(StringUtilities.changeAliasLowerCase(keyword), 'gi'); //'gi' for case insensitive and can use 'g' if you want the search to be case sensitive.
|
|
301
|
+
const aliasLowerCaseStr = StringUtilities.changeAliasLowerCase(value);
|
|
302
|
+
const strs = [];
|
|
303
|
+
let previousOffset = 0;
|
|
304
|
+
aliasLowerCaseStr.replace(regex, (_, offset) => {
|
|
305
|
+
strs.push(value.substring(previousOffset, offset));
|
|
306
|
+
strs.push(`<mark style="background-color: ${color}">${value.substring(offset, offset + keyword.length)}</mark>`);
|
|
307
|
+
previousOffset = offset + keyword.length;
|
|
308
|
+
return `<mark style="background-color: ${color}">${value.substring(offset, offset + keyword.length)}</mark>`;
|
|
309
|
+
});
|
|
310
|
+
strs.push(value.substring(previousOffset, value.length));
|
|
311
|
+
return strs.join('');
|
|
312
|
+
}
|
|
313
|
+
#normalizeValue = (keyword) => {
|
|
314
|
+
let str = keyword?.toString() ?? '';
|
|
315
|
+
/* eslint-disable no-useless-escape */
|
|
316
|
+
str = str.replace(/!|@|%|\^|\*|\(|\)|\+|\=|\<|\>|\?|\/|,|\.|\:|\;|\'|\"|\&|\#|\[|\]|~|\$|_|`|-|{|}|\||\\/g, '');
|
|
317
|
+
str = str.replace(/ + /g, ' ');
|
|
318
|
+
str = str.trim();
|
|
319
|
+
return str;
|
|
320
|
+
};
|
|
321
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HighlightSearchPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
322
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.21", ngImport: i0, type: HighlightSearchPipe, isStandalone: true, name: "highLightSearch" });
|
|
323
|
+
}
|
|
324
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HighlightSearchPipe, decorators: [{
|
|
325
|
+
type: Pipe,
|
|
326
|
+
args: [{
|
|
327
|
+
name: 'highLightSearch',
|
|
328
|
+
}]
|
|
329
|
+
}] });
|
|
330
|
+
|
|
331
|
+
let LayoutUserComponent$1 = class LayoutUserComponent {
|
|
332
|
+
// ==========================================
|
|
333
|
+
// INJECT SERVICES
|
|
334
|
+
// ==========================================
|
|
335
|
+
#layoutConfiguration = inject(SD_LAYOUT_CONFIGURATION);
|
|
336
|
+
// ==========================================
|
|
337
|
+
// SIGNAL INPUTS & OUTPUTS
|
|
338
|
+
// ==========================================
|
|
339
|
+
isMobileOrTablet = input(false);
|
|
340
|
+
isMenuLock = input(false);
|
|
341
|
+
isShowSidebar = input(false);
|
|
342
|
+
userInfo = input.required();
|
|
343
|
+
// Chuyển thành void vì các hàm emit hiện tại không truyền data
|
|
344
|
+
menuClosed = output();
|
|
345
|
+
menuOpened = output();
|
|
346
|
+
toggleMenuLock = output();
|
|
347
|
+
// Config actions
|
|
348
|
+
singoutLayoutConfig = this.#layoutConfiguration.signout;
|
|
349
|
+
changePasswordLayoutConfig = this.#layoutConfiguration?.changePassword;
|
|
350
|
+
// ==========================================
|
|
351
|
+
// EVENT HANDLERS
|
|
352
|
+
// ==========================================
|
|
353
|
+
onMenuOpened = () => {
|
|
354
|
+
this.menuOpened.emit();
|
|
355
|
+
};
|
|
356
|
+
onMenuClosed = () => {
|
|
357
|
+
this.menuClosed.emit();
|
|
358
|
+
};
|
|
359
|
+
keepOpenWhenClickInsideMenu = (event) => {
|
|
360
|
+
event.stopPropagation();
|
|
361
|
+
};
|
|
362
|
+
logout = () => {
|
|
363
|
+
this.singoutLayoutConfig();
|
|
364
|
+
};
|
|
365
|
+
changePassword = () => {
|
|
366
|
+
// Dùng Optional Chaining gọi hàm cực gọn
|
|
367
|
+
this.changePasswordLayoutConfig?.();
|
|
368
|
+
};
|
|
369
|
+
onToggleMenuLock = (event) => {
|
|
370
|
+
this.toggleMenuLock.emit(event);
|
|
371
|
+
};
|
|
372
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LayoutUserComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
373
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: LayoutUserComponent, isStandalone: true, selector: "lib-layout-user", inputs: { isMobileOrTablet: { classPropertyName: "isMobileOrTablet", publicName: "isMobileOrTablet", isSignal: true, isRequired: false, transformFunction: null }, isMenuLock: { classPropertyName: "isMenuLock", publicName: "isMenuLock", isSignal: true, isRequired: false, transformFunction: null }, isShowSidebar: { classPropertyName: "isShowSidebar", publicName: "isShowSidebar", isSignal: true, isRequired: false, transformFunction: null }, userInfo: { classPropertyName: "userInfo", publicName: "userInfo", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { menuClosed: "menuClosed", menuOpened: "menuOpened", toggleMenuLock: "toggleMenuLock" }, ngImport: i0, template: "@let _userInfo = userInfo();\n@let avatar = _userInfo?.avatar || _userInfo?.fullName || _userInfo?.username || _userInfo?.email;\n\n<div class=\"c-layout-user-wrapper\">\n <div class=\"c-layout-user-avatar\" [matMenuTriggerFor]=\"userMenu\" (menuClosed)=\"onMenuClosed()\" (menuOpened)=\"onMenuOpened()\">\n <sd-avatar [src]=\"avatar\" [size]=\"32\"></sd-avatar>\n </div>\n\n @if (!isMobileOrTablet()) {\n <div aria-hidden=\"true\" mat-mini-fab class=\"c-layout-icon-toggle\" (click)=\"onToggleMenuLock($event)\">\n <mat-icon style=\"color: #8c8c8c\">\n {{ isShowSidebar() ? 'keyboard_arrow_right' : 'keyboard_arrow_left' }}\n </mat-icon>\n </div>\n }\n</div>\n\n<mat-menu #userMenu=\"matMenu\" xPosition=\"before\" backdropClass=\"c-user-menu-backdrop-f90ce131-fa4c-4f71-a49b-ab7fa374fdd0\">\n <div aria-hidden=\"true\" class=\"c-user-menu-wrapper\" (click)=\"keepOpenWhenClickInsideMenu($event)\">\n <div class=\"c-user-info-wrapper\">\n <div class=\"c-user-avatar\">\n <sd-avatar [src]=\"avatar\" [size]=\"40\"></sd-avatar>\n </div>\n <span class=\"c-user-name\">{{ _userInfo.fullName || _userInfo.username }}</span>\n <span class=\"c-user-email\">{{ _userInfo.email }}</span>\n </div>\n\n @if (changePasswordLayoutConfig) {\n <div class=\"c-sign-button-wrapper\">\n <button class=\"c-account-options\" (click)=\"changePassword()\">\n <mat-icon fontSet=\"material-icons-outlined\">lock</mat-icon>\n <span>{{ 'core.module.layout.user.change-password' | translate }}</span>\n </button>\n </div>\n }\n\n <div class=\"c-sign-button-wrapper\">\n <button class=\"c-sign-button\" mat-flat-button (click)=\"logout()\">{{ 'core.module.layout.user.logout' | translate }}</button>\n </div>\n </div>\n</mat-menu>", styles: ["::ng-deep .c-user-menu-backdrop-f90ce131-fa4c-4f71-a49b-ab7fa374fdd0+* .cdk-overlay-pane{transform:translate(277px,83px)}.c-layout-user-wrapper{display:flex;flex-direction:column;align-items:center;width:60px;height:80px}.c-layout-user-wrapper .c-layout-user-avatar{width:32px;height:32px;display:flex;align-items:center;justify-content:center;cursor:pointer}.c-layout-user-wrapper .c-layout-icon-toggle{background-color:transparent;border-top:1px solid #f0f0f0;box-shadow:none;margin-top:10px;width:32px;height:40px;display:flex;justify-content:center;align-items:center;cursor:pointer}.c-user-menu-wrapper .c-user-info-wrapper{width:250px;padding:16px;display:flex;flex-direction:column;align-items:center;gap:8px}.c-user-menu-wrapper .c-user-info-wrapper .c-user-avatar{width:40px;height:40px}.c-user-menu-wrapper .c-user-info-wrapper .c-user-name{font-size:16px;font-weight:700;text-align:center}.c-user-menu-wrapper .c-user-info-wrapper .c-user-email{font-size:14px;color:#7a7a7a;text-align:center}.c-user-menu-wrapper .c-sign-button-wrapper{text-align:center;padding:16px 16px 8px;width:100%;border-top:1px solid #dee2e6}.c-user-menu-wrapper .c-sign-button-wrapper .c-account-options{all:unset;cursor:pointer;font-size:14px;display:flex;align-items:center;gap:8px}.c-user-menu-wrapper .c-sign-button-wrapper .c-account-options mat-icon{font-size:21px;width:21px;height:21px;color:#8c8c8c}.c-user-menu-wrapper .c-sign-button-wrapper .c-sign-button{width:100%;color:#000;padding:16px;font-weight:700;background-color:#eef0f2}.c-avatar{max-width:100%;object-fit:cover}\n"], dependencies: [{ kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i1$2.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "directive", type: i1$2.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "component", type: SdAvatar, selector: "sd-avatar", inputs: ["src", "size"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
|
|
374
|
+
};
|
|
375
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LayoutUserComponent$1, decorators: [{
|
|
376
|
+
type: Component,
|
|
377
|
+
args: [{ selector: 'lib-layout-user', imports: [MatMenuModule, MatButtonModule, MatIconModule, MatTooltipModule, SdAvatar, TranslatePipe], standalone: true, template: "@let _userInfo = userInfo();\n@let avatar = _userInfo?.avatar || _userInfo?.fullName || _userInfo?.username || _userInfo?.email;\n\n<div class=\"c-layout-user-wrapper\">\n <div class=\"c-layout-user-avatar\" [matMenuTriggerFor]=\"userMenu\" (menuClosed)=\"onMenuClosed()\" (menuOpened)=\"onMenuOpened()\">\n <sd-avatar [src]=\"avatar\" [size]=\"32\"></sd-avatar>\n </div>\n\n @if (!isMobileOrTablet()) {\n <div aria-hidden=\"true\" mat-mini-fab class=\"c-layout-icon-toggle\" (click)=\"onToggleMenuLock($event)\">\n <mat-icon style=\"color: #8c8c8c\">\n {{ isShowSidebar() ? 'keyboard_arrow_right' : 'keyboard_arrow_left' }}\n </mat-icon>\n </div>\n }\n</div>\n\n<mat-menu #userMenu=\"matMenu\" xPosition=\"before\" backdropClass=\"c-user-menu-backdrop-f90ce131-fa4c-4f71-a49b-ab7fa374fdd0\">\n <div aria-hidden=\"true\" class=\"c-user-menu-wrapper\" (click)=\"keepOpenWhenClickInsideMenu($event)\">\n <div class=\"c-user-info-wrapper\">\n <div class=\"c-user-avatar\">\n <sd-avatar [src]=\"avatar\" [size]=\"40\"></sd-avatar>\n </div>\n <span class=\"c-user-name\">{{ _userInfo.fullName || _userInfo.username }}</span>\n <span class=\"c-user-email\">{{ _userInfo.email }}</span>\n </div>\n\n @if (changePasswordLayoutConfig) {\n <div class=\"c-sign-button-wrapper\">\n <button class=\"c-account-options\" (click)=\"changePassword()\">\n <mat-icon fontSet=\"material-icons-outlined\">lock</mat-icon>\n <span>{{ 'core.module.layout.user.change-password' | translate }}</span>\n </button>\n </div>\n }\n\n <div class=\"c-sign-button-wrapper\">\n <button class=\"c-sign-button\" mat-flat-button (click)=\"logout()\">{{ 'core.module.layout.user.logout' | translate }}</button>\n </div>\n </div>\n</mat-menu>", styles: ["::ng-deep .c-user-menu-backdrop-f90ce131-fa4c-4f71-a49b-ab7fa374fdd0+* .cdk-overlay-pane{transform:translate(277px,83px)}.c-layout-user-wrapper{display:flex;flex-direction:column;align-items:center;width:60px;height:80px}.c-layout-user-wrapper .c-layout-user-avatar{width:32px;height:32px;display:flex;align-items:center;justify-content:center;cursor:pointer}.c-layout-user-wrapper .c-layout-icon-toggle{background-color:transparent;border-top:1px solid #f0f0f0;box-shadow:none;margin-top:10px;width:32px;height:40px;display:flex;justify-content:center;align-items:center;cursor:pointer}.c-user-menu-wrapper .c-user-info-wrapper{width:250px;padding:16px;display:flex;flex-direction:column;align-items:center;gap:8px}.c-user-menu-wrapper .c-user-info-wrapper .c-user-avatar{width:40px;height:40px}.c-user-menu-wrapper .c-user-info-wrapper .c-user-name{font-size:16px;font-weight:700;text-align:center}.c-user-menu-wrapper .c-user-info-wrapper .c-user-email{font-size:14px;color:#7a7a7a;text-align:center}.c-user-menu-wrapper .c-sign-button-wrapper{text-align:center;padding:16px 16px 8px;width:100%;border-top:1px solid #dee2e6}.c-user-menu-wrapper .c-sign-button-wrapper .c-account-options{all:unset;cursor:pointer;font-size:14px;display:flex;align-items:center;gap:8px}.c-user-menu-wrapper .c-sign-button-wrapper .c-account-options mat-icon{font-size:21px;width:21px;height:21px;color:#8c8c8c}.c-user-menu-wrapper .c-sign-button-wrapper .c-sign-button{width:100%;color:#000;padding:16px;font-weight:700;background-color:#eef0f2}.c-avatar{max-width:100%;object-fit:cover}\n"] }]
|
|
378
|
+
}] });
|
|
379
|
+
|
|
380
|
+
class SidebarComponent {
|
|
381
|
+
// ==========================================
|
|
382
|
+
// INJECT SERVICES (Thay thế Constructor rườm rà)
|
|
383
|
+
// ==========================================
|
|
384
|
+
#router = inject(Router);
|
|
385
|
+
#layoutStorageService = inject(SdLayoutStorageService);
|
|
386
|
+
#menuFocusPipe = inject(MenuFocusPipe);
|
|
387
|
+
#destroyRef = inject(DestroyRef); // Dùng để unsubscribe RxJS tự động
|
|
388
|
+
// ==========================================
|
|
389
|
+
// SIGNAL INPUTS & OUTPUTS
|
|
390
|
+
// ==========================================
|
|
391
|
+
isShowSidebar = input.required();
|
|
392
|
+
menus = input.required();
|
|
393
|
+
userInfo = input.required();
|
|
394
|
+
sidebar = input.required();
|
|
395
|
+
expandSideBar = output();
|
|
396
|
+
popupUserMenuClosed = output();
|
|
397
|
+
popupUserMenuOpened = output();
|
|
398
|
+
showSideBar = output();
|
|
399
|
+
// ==========================================
|
|
400
|
+
// STATE SIGNALS
|
|
401
|
+
// ==========================================
|
|
402
|
+
screenHeight = window.innerHeight;
|
|
403
|
+
isMobileOrTablet = BrowserUtilities.isMobile();
|
|
404
|
+
isMenuLock = signal(this.#layoutStorageService.menuLockStatus?.get() ?? true);
|
|
405
|
+
currentPath = signal(window.location.pathname);
|
|
406
|
+
searchText = signal('');
|
|
407
|
+
titleMenuGroup = signal('');
|
|
408
|
+
idMenuGroupActive = signal('');
|
|
409
|
+
menusByGroup = signal([]);
|
|
410
|
+
#hoveredMenuNodeKey = signal(null);
|
|
411
|
+
#pinIconHoverTimerId = signal(null);
|
|
412
|
+
pinnedMenuGroup = signal(this.#layoutStorageService.pinnedMenuGroup.get() ?? {
|
|
413
|
+
id: 'pinned-menu-group',
|
|
414
|
+
title: 'Đã ghim',
|
|
415
|
+
children: [],
|
|
416
|
+
});
|
|
417
|
+
// ==========================================
|
|
418
|
+
// COMPUTED STATE
|
|
419
|
+
// ==========================================
|
|
420
|
+
totalMenuInMenusByGroup = computed(() => this.#getTotalMenus(this.menusByGroup()));
|
|
421
|
+
pinnedNodeKeys = computed(() => new Set(this.pinnedMenuGroup().children?.map(m => this.#getMenuNodeKey(m)) ?? []));
|
|
422
|
+
isPinnedMenuGroupActive = computed(() => this.idMenuGroupActive() === this.pinnedMenuGroup().id);
|
|
423
|
+
// ==========================================
|
|
424
|
+
// DATA STRUCTURES
|
|
425
|
+
// ==========================================
|
|
426
|
+
#pinIconHoverTimerDelay = 300;
|
|
427
|
+
#isFirstBindingMenu = signal(true);
|
|
428
|
+
dataSource = new MatTreeNestedDataSource();
|
|
429
|
+
treeControl = new NestedTreeControl(node => ('children' in node && node.children?.length ? node.children : []));
|
|
430
|
+
constructor() {
|
|
431
|
+
this.#setupEffects();
|
|
432
|
+
this.#setupSubscriptions();
|
|
433
|
+
}
|
|
434
|
+
#setupEffects() {
|
|
435
|
+
effect(() => {
|
|
436
|
+
const currentMenus = this.menus();
|
|
437
|
+
untracked(() => {
|
|
438
|
+
const lastActiveMenuGroupId = this.#layoutStorageService.lastActiveMenuGroupId.get();
|
|
439
|
+
const pinnedGroup = this.pinnedMenuGroup();
|
|
440
|
+
const isPinEnabled = this.sidebar()?.pin?.enabled;
|
|
441
|
+
// Xử lý khi lần đầu vào web (nếu chưa có active group)
|
|
442
|
+
if (!lastActiveMenuGroupId || (lastActiveMenuGroupId === pinnedGroup?.id && !isPinEnabled)) {
|
|
443
|
+
// Ưu tiên pinnedGroup nếu đủ điều kiện, còn không lấy menu đầu tiền dev khai báo
|
|
444
|
+
const targetId = isPinEnabled && pinnedGroup?.children?.length ? pinnedGroup?.id : currentMenus?.[0]?.id;
|
|
445
|
+
this.#layoutStorageService.lastActiveMenuGroupId.set(targetId ?? '');
|
|
446
|
+
}
|
|
447
|
+
this.#bindingMenuGroupByCurrentPath(currentMenus);
|
|
448
|
+
this.#isFirstBindingMenu.set(false);
|
|
449
|
+
});
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
#setupSubscriptions() {
|
|
453
|
+
this.#router.events.pipe(takeUntilDestroyed(this.#destroyRef)).subscribe(event => {
|
|
454
|
+
if (event instanceof NavigationEnd) {
|
|
455
|
+
if (this.currentPath() !== window.location.pathname) {
|
|
456
|
+
this.currentPath.set(window.location.pathname);
|
|
457
|
+
this.#bindingMenuGroupByCurrentPath(this.menus());
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
// ==========================================
|
|
463
|
+
// EVENT HANDLERS
|
|
464
|
+
// ==========================================
|
|
465
|
+
hasChild = (_, node) => 'children' in node && !!node.children?.length;
|
|
466
|
+
onToggleMenuNode = (menu) => {
|
|
467
|
+
this.treeControl.toggle(menu);
|
|
468
|
+
};
|
|
469
|
+
isPinnedNode = (node) => this.pinnedNodeKeys().has(this.#getMenuNodeKey(node));
|
|
470
|
+
isHoveredNode = (node) => this.#hoveredMenuNodeKey() === this.#getMenuNodeKey(node);
|
|
471
|
+
expandPinnedGroup = () => {
|
|
472
|
+
const group = this.pinnedMenuGroup();
|
|
473
|
+
this.idMenuGroupActive.set(group.id);
|
|
474
|
+
this.#layoutStorageService.lastActiveMenuGroupId.set(group.id || '');
|
|
475
|
+
this.titleMenuGroup.set(group.title);
|
|
476
|
+
this.#setMenusByGroup(group.children ?? []);
|
|
477
|
+
this.searchText.set('');
|
|
478
|
+
this.expandSideBar.emit();
|
|
479
|
+
};
|
|
480
|
+
onTogglePin = (event, node) => {
|
|
481
|
+
event.stopPropagation();
|
|
482
|
+
const key = this.#getMenuNodeKey(node);
|
|
483
|
+
this.pinnedMenuGroup.update(group => {
|
|
484
|
+
const children = group.children ?? [];
|
|
485
|
+
const exists = children.some(m => this.#getMenuNodeKey(m) === key);
|
|
486
|
+
const updatedChildren = exists ? children.filter(m => this.#getMenuNodeKey(m) !== key) : [...children, node];
|
|
487
|
+
const updatedGroup = { id: 'pinned-menu-group', title: 'Đã ghim', children: updatedChildren };
|
|
488
|
+
this.#layoutStorageService.pinnedMenuGroup.set(updatedGroup);
|
|
489
|
+
return updatedGroup;
|
|
490
|
+
});
|
|
491
|
+
};
|
|
492
|
+
#onExpandAllMenuNodes = (menus) => {
|
|
493
|
+
menus?.forEach(menu => {
|
|
494
|
+
this.treeControl.expand(menu);
|
|
495
|
+
if ('children' in menu && menu.children?.length) {
|
|
496
|
+
this.#onExpandAllMenuNodes(menu.children);
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
};
|
|
500
|
+
#onCollapseAllMenuNodes = (menus) => {
|
|
501
|
+
menus?.forEach(menu => {
|
|
502
|
+
this.treeControl.collapse(menu);
|
|
503
|
+
if ('children' in menu && menu.children?.length) {
|
|
504
|
+
this.#onCollapseAllMenuNodes(menu.children);
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
};
|
|
508
|
+
toggleMenuLock(event) {
|
|
509
|
+
event.stopPropagation();
|
|
510
|
+
this.isMenuLock.update(v => !v);
|
|
511
|
+
this.#layoutStorageService.menuLockStatus?.set(this.isMenuLock());
|
|
512
|
+
this.showSideBar.emit(this.isMenuLock());
|
|
513
|
+
}
|
|
514
|
+
openHomePage = () => {
|
|
515
|
+
if (!this.isMobileOrTablet) {
|
|
516
|
+
this.#router.navigateByUrl('/layout/home');
|
|
517
|
+
}
|
|
518
|
+
else {
|
|
519
|
+
window.location.href = '/layout/home';
|
|
520
|
+
}
|
|
521
|
+
this.searchText.set('');
|
|
522
|
+
this.#layoutStorageService.lastActiveMenuGroupId.set('');
|
|
523
|
+
};
|
|
524
|
+
onUserMenuClosed = () => this.popupUserMenuClosed.emit();
|
|
525
|
+
onUserMenuOpened = () => this.popupUserMenuOpened.emit();
|
|
526
|
+
navigate = (args) => {
|
|
527
|
+
const { path, queryParams } = args;
|
|
528
|
+
if (path.includes('http')) {
|
|
529
|
+
window.open(path);
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
this.#router.navigate([path.split('?')[0]], {
|
|
533
|
+
queryParams,
|
|
534
|
+
state: { switchTab: true },
|
|
535
|
+
});
|
|
536
|
+
if (this.isMobileOrTablet) {
|
|
537
|
+
this.#closeMenu();
|
|
538
|
+
}
|
|
539
|
+
};
|
|
540
|
+
onFilterSearchText = (event) => {
|
|
541
|
+
this.searchText.set(event);
|
|
542
|
+
this.#filterMenuBySearchText(this.menusByGroup());
|
|
543
|
+
};
|
|
544
|
+
onClearSearchText = () => {
|
|
545
|
+
this.searchText.set('');
|
|
546
|
+
this.#filterMenuBySearchText(this.menusByGroup());
|
|
547
|
+
};
|
|
548
|
+
expandMenuGroup = (menuGroupNode) => {
|
|
549
|
+
this.titleMenuGroup.set(menuGroupNode?.tooltipTitle || menuGroupNode?.title);
|
|
550
|
+
// Case 1: Menu không có children
|
|
551
|
+
if (!('children' in menuGroupNode && menuGroupNode.children?.length)) {
|
|
552
|
+
if ('path' in menuGroupNode) {
|
|
553
|
+
this.navigate({ path: menuGroupNode.path, queryParams: menuGroupNode?.queryParams ?? {} });
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
// Case 2: Menu có children
|
|
558
|
+
if ('children' in menuGroupNode && menuGroupNode.children?.length) {
|
|
559
|
+
this.#setMenusByGroup(menuGroupNode.children);
|
|
560
|
+
this.searchText.set('');
|
|
561
|
+
this.onFilterSearchText('');
|
|
562
|
+
this.expandSideBar.emit();
|
|
563
|
+
}
|
|
564
|
+
this.idMenuGroupActive.set(menuGroupNode?.id);
|
|
565
|
+
this.#layoutStorageService.lastActiveMenuGroupId.set(menuGroupNode?.id || '');
|
|
566
|
+
if (!this.currentPath()) {
|
|
567
|
+
this.currentPath.set(window.location.pathname);
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
// ==========================================
|
|
571
|
+
// CỤM HOVER MENU GROUP & NODE
|
|
572
|
+
// ==========================================
|
|
573
|
+
onMouseOverMenuGroupNode = (event, menuNode) => {
|
|
574
|
+
if (this.idMenuGroupActive() !== menuNode?.id) {
|
|
575
|
+
const menuGroup = event.currentTarget;
|
|
576
|
+
const menuGroupIcon = menuGroup.querySelector('.c-menu-group-icon');
|
|
577
|
+
const brandLightColorOpacity = this.#convertColor(this.sidebar()?.brandLightColor, 0.6);
|
|
578
|
+
if (menuGroupIcon) {
|
|
579
|
+
menuGroupIcon.style.transition = 'all 0.15s';
|
|
580
|
+
menuGroupIcon.style.backgroundColor = brandLightColorOpacity || 'rgba(248, 249, 250, 0.6)';
|
|
581
|
+
if (!(menuGroupIcon instanceof HTMLImageElement)) {
|
|
582
|
+
menuGroupIcon.style.color = this.sidebar()?.brandColor || '#2962FF';
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
};
|
|
587
|
+
onMouseLeaveMenuGroupNode = (event, menuNode) => {
|
|
588
|
+
if (this.idMenuGroupActive() !== menuNode?.id) {
|
|
589
|
+
const menuGroup = event.currentTarget;
|
|
590
|
+
const menuGroupIcon = menuGroup.querySelector('.c-menu-group-icon');
|
|
591
|
+
if (menuGroupIcon) {
|
|
592
|
+
menuGroupIcon.style.transition = 'all 0.15s';
|
|
593
|
+
menuGroupIcon.style.backgroundColor = 'transparent';
|
|
594
|
+
if (menuGroupIcon instanceof HTMLImageElement) {
|
|
595
|
+
menuGroupIcon.style.opacity = '0.55';
|
|
596
|
+
}
|
|
597
|
+
else {
|
|
598
|
+
menuGroupIcon.style.color = '#8C8C8C';
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
};
|
|
603
|
+
onMouseOverMenuNode = (event, menuItem) => {
|
|
604
|
+
const menuNode = event.currentTarget;
|
|
605
|
+
const brandColor = this.sidebar()?.brandColor || '#2962FF';
|
|
606
|
+
// Nếu có bật config pin menu
|
|
607
|
+
if (this.sidebar()?.pin?.enabled) {
|
|
608
|
+
const iconPin = menuNode.querySelector('.c-menu-node-description-icon-pin');
|
|
609
|
+
if (iconPin) {
|
|
610
|
+
if (this.#pinIconHoverTimerId()) {
|
|
611
|
+
clearTimeout(this.#pinIconHoverTimerId());
|
|
612
|
+
this.#pinIconHoverTimerId.set(null);
|
|
613
|
+
}
|
|
614
|
+
this.#pinIconHoverTimerId.set(setTimeout(() => {
|
|
615
|
+
this.#hoveredMenuNodeKey.set(this.#getMenuNodeKey(menuItem));
|
|
616
|
+
iconPin.style.color = brandColor;
|
|
617
|
+
iconPin.style.transition = 'all 0.15s';
|
|
618
|
+
iconPin.style.opacity = '1';
|
|
619
|
+
this.#pinIconHoverTimerId.set(null);
|
|
620
|
+
}, this.#pinIconHoverTimerDelay));
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
if (!this.#menuFocusPipe.transform(this.currentPath(), menuItem)) {
|
|
624
|
+
const iconMenu = menuNode.querySelector('.c-menu-node-icon');
|
|
625
|
+
const content = menuNode.querySelector('.c-menu-node-description-content');
|
|
626
|
+
const iconExpand = menuNode.querySelector('.c-menu-node-description-icon-expand');
|
|
627
|
+
const brandLightColorOpacity = this.#convertColor(this.sidebar()?.brandLightColor, 0.6);
|
|
628
|
+
if (menuNode) {
|
|
629
|
+
menuNode.style.transition = 'all 0.15s';
|
|
630
|
+
menuNode.style.backgroundColor = brandLightColorOpacity || 'rgba(248, 249, 250, 0.6)';
|
|
631
|
+
if (iconMenu) {
|
|
632
|
+
iconMenu.style.transition = 'all 0.15s';
|
|
633
|
+
iconMenu.style.color = brandColor;
|
|
634
|
+
}
|
|
635
|
+
if (content) {
|
|
636
|
+
content.style.transition = 'all 0.15s';
|
|
637
|
+
content.style.color = brandColor;
|
|
638
|
+
}
|
|
639
|
+
if (iconExpand) {
|
|
640
|
+
iconExpand.style.transition = 'all 0.15s';
|
|
641
|
+
iconExpand.style.color = brandColor;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
};
|
|
646
|
+
onMouseLeaveMenuNode = (event, menuItem) => {
|
|
647
|
+
const menuNode = event.currentTarget;
|
|
648
|
+
// Nếu có bật config pin menu
|
|
649
|
+
if (this.sidebar()?.pin?.enabled) {
|
|
650
|
+
const iconPin = menuNode.querySelector('.c-menu-node-description-icon-pin');
|
|
651
|
+
if (iconPin) {
|
|
652
|
+
if (this.#pinIconHoverTimerId()) {
|
|
653
|
+
clearTimeout(this.#pinIconHoverTimerId());
|
|
654
|
+
this.#pinIconHoverTimerId.set(null);
|
|
655
|
+
}
|
|
656
|
+
this.#hoveredMenuNodeKey.set(null);
|
|
657
|
+
iconPin.style.transition = 'all 0.15s';
|
|
658
|
+
if (!this.isPinnedNode(menuItem)) {
|
|
659
|
+
iconPin.style.color = '#8C8C8C';
|
|
660
|
+
iconPin.style.opacity = '0';
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
if (!this.#menuFocusPipe.transform(this.currentPath(), menuItem)) {
|
|
665
|
+
const iconMenu = menuNode.querySelector('.c-menu-node-icon');
|
|
666
|
+
const content = menuNode.querySelector('.c-menu-node-description-content');
|
|
667
|
+
const iconExpand = menuNode.querySelector('.c-menu-node-description-icon-expand');
|
|
668
|
+
if (menuNode) {
|
|
669
|
+
menuNode.style.transition = 'all 0.15s';
|
|
670
|
+
menuNode.style.backgroundColor = 'transparent';
|
|
671
|
+
if (iconMenu) {
|
|
672
|
+
iconMenu.style.transition = 'all 0.15s';
|
|
673
|
+
iconMenu.style.color = '#8C8C8C';
|
|
674
|
+
}
|
|
675
|
+
if (content) {
|
|
676
|
+
content.style.transition = 'all 0.15s';
|
|
677
|
+
content.style.color = '#1F1F1F';
|
|
678
|
+
}
|
|
679
|
+
if (iconExpand) {
|
|
680
|
+
iconExpand.style.transition = 'all 0.15s';
|
|
681
|
+
iconExpand.style.color = '#8C8C8C';
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
};
|
|
686
|
+
// ==========================================
|
|
687
|
+
// PRIVATE LOGIC
|
|
688
|
+
// ==========================================
|
|
689
|
+
#setMenusByGroup = (menus) => {
|
|
690
|
+
this.menusByGroup.set(menus);
|
|
691
|
+
this.dataSource.data = menus;
|
|
692
|
+
};
|
|
693
|
+
#getMenuNodeKey = (node) => {
|
|
694
|
+
if (node?.id) {
|
|
695
|
+
return node.id;
|
|
696
|
+
}
|
|
697
|
+
if ('path' in node && node.path) {
|
|
698
|
+
return node.path;
|
|
699
|
+
}
|
|
700
|
+
return node.title || '';
|
|
701
|
+
};
|
|
702
|
+
#getMenuGroupByCurrentPath = (menus, menuGroup) => {
|
|
703
|
+
for (const menu of menus) {
|
|
704
|
+
if ('path' in menu && this.#isMenuPathMatchByCurrentPath(menu.path)) {
|
|
705
|
+
return [menuGroup ?? menu];
|
|
706
|
+
}
|
|
707
|
+
if ('children' in menu && menu.children?.length) {
|
|
708
|
+
const result = this.#getMenuGroupByCurrentPath(menu.children, menuGroup ?? menu);
|
|
709
|
+
if (result?.length) {
|
|
710
|
+
return result;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
return [];
|
|
715
|
+
};
|
|
716
|
+
#bindingMenuGroupByCurrentPath = (menus) => {
|
|
717
|
+
// Chỉ bindingGroup mới khi người dùng không searchText
|
|
718
|
+
if (!this.#getValidSearchText()) {
|
|
719
|
+
const pinnedChildren = this.pinnedMenuGroup()?.children ?? [];
|
|
720
|
+
// Ưu tiên: Current path khớp với item trong pinMenuGroup thì lần đầu vào trang sẽ hiện pinnedMenuGroup
|
|
721
|
+
const isPinnedPathMatchValid = this.sidebar()?.pin?.enabled &&
|
|
722
|
+
pinnedChildren?.length &&
|
|
723
|
+
this.#getMenuGroupByCurrentPath(pinnedChildren)?.length &&
|
|
724
|
+
this.#isFirstBindingMenu() &&
|
|
725
|
+
this.idMenuGroupActive() !== this.pinnedMenuGroup()?.id;
|
|
726
|
+
if (isPinnedPathMatchValid) {
|
|
727
|
+
const pinned = this.pinnedMenuGroup();
|
|
728
|
+
this.idMenuGroupActive.set(pinned.id);
|
|
729
|
+
this.#layoutStorageService.lastActiveMenuGroupId.set(pinned.id ?? '');
|
|
730
|
+
this.titleMenuGroup.set(pinned.title);
|
|
731
|
+
this.#setMenusByGroup(pinnedChildren);
|
|
732
|
+
this.#expandParentNodesByCurrentPath(pinnedChildren);
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
let menuGroupByPath = this.#getMenuGroupByCurrentPath(menus);
|
|
736
|
+
// Nếu không tìm được path nào khớp với menu
|
|
737
|
+
if (!menuGroupByPath?.length) {
|
|
738
|
+
const lastActiveId = this.#layoutStorageService.lastActiveMenuGroupId.get() || '';
|
|
739
|
+
// Nếu có pinned group thì hiện mậc định là pinnedMenuGroup
|
|
740
|
+
if (this.sidebar()?.pin?.enabled && lastActiveId === this.pinnedMenuGroup()?.id && pinnedChildren?.length) {
|
|
741
|
+
const pinned = this.pinnedMenuGroup();
|
|
742
|
+
this.idMenuGroupActive.set(pinned.id);
|
|
743
|
+
this.titleMenuGroup.set(pinned.title);
|
|
744
|
+
this.#setMenusByGroup(pinnedChildren);
|
|
745
|
+
this.#expandParentNodesByCurrentPath(pinnedChildren);
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
// Nếu không có pinnedMenuGroup thì menuGroup lấy từ thao tác cuối cùng của người dùng
|
|
749
|
+
menuGroupByPath = this.menus()?.filter(menu => menu?.id === lastActiveId) || [];
|
|
750
|
+
}
|
|
751
|
+
// Kiểm tra lại menuGroupPath đã thực sự tìm được chưa?
|
|
752
|
+
if (menuGroupByPath?.length) {
|
|
753
|
+
// Nếu user đang ở pinedGroup và curentPath có chứa trong pinnedMenuGroup thì return luôn, không chuyển sang menuGroup mới
|
|
754
|
+
if (this.sidebar()?.pin?.enabled &&
|
|
755
|
+
this.idMenuGroupActive() === this.pinnedMenuGroup()?.id &&
|
|
756
|
+
this.#getMenuGroupByCurrentPath(pinnedChildren)?.length) {
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
else {
|
|
760
|
+
const matchedGroup = menuGroupByPath[0];
|
|
761
|
+
this.idMenuGroupActive.set(matchedGroup?.id);
|
|
762
|
+
this.#layoutStorageService.lastActiveMenuGroupId.set(matchedGroup?.id || '');
|
|
763
|
+
this.titleMenuGroup.set(matchedGroup?.tooltipTitle || matchedGroup?.title);
|
|
764
|
+
if ('children' in matchedGroup && matchedGroup.children?.length) {
|
|
765
|
+
this.menusByGroup.set(matchedGroup.children);
|
|
766
|
+
this.#expandParentNodesByCurrentPath(this.menusByGroup());
|
|
767
|
+
}
|
|
768
|
+
else {
|
|
769
|
+
this.menusByGroup.set([]);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
else {
|
|
774
|
+
this.idMenuGroupActive.set('');
|
|
775
|
+
this.titleMenuGroup.set('');
|
|
776
|
+
this.menusByGroup.set([]);
|
|
777
|
+
}
|
|
778
|
+
this.dataSource.data = this.menusByGroup();
|
|
779
|
+
}
|
|
780
|
+
};
|
|
781
|
+
#expandParentNodesByCurrentPath(menus) {
|
|
782
|
+
let shouldPropagate = false;
|
|
783
|
+
for (const menu of menus) {
|
|
784
|
+
if ('path' in menu && this.#isMenuPathMatchByCurrentPath(menu.path)) {
|
|
785
|
+
shouldPropagate = true;
|
|
786
|
+
}
|
|
787
|
+
if ('children' in menu && menu.children?.length) {
|
|
788
|
+
const childHasMatch = this.#expandParentNodesByCurrentPath(menu.children);
|
|
789
|
+
if (childHasMatch) {
|
|
790
|
+
this.treeControl.expand(menu);
|
|
791
|
+
shouldPropagate = true;
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
return shouldPropagate;
|
|
796
|
+
}
|
|
797
|
+
#filterMenuBySearchText = (menus) => {
|
|
798
|
+
const validSearchText = this.#getValidSearchText();
|
|
799
|
+
if (!validSearchText) {
|
|
800
|
+
this.dataSource.data = menus;
|
|
801
|
+
this.#onCollapseAllMenuNodes(menus);
|
|
802
|
+
this.#expandParentNodesByCurrentPath(menus);
|
|
803
|
+
}
|
|
804
|
+
else {
|
|
805
|
+
const aliasSearchText = StringUtilities.changeAliasLowerCase(validSearchText);
|
|
806
|
+
this.dataSource.data = this.#getMenuByAliasSearchText(menus, aliasSearchText);
|
|
807
|
+
if (this.dataSource.data?.length) {
|
|
808
|
+
this.#onExpandAllMenuNodes(this.dataSource.data);
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
};
|
|
812
|
+
#getMenuByAliasSearchText = (menus, aliasSearchText) => {
|
|
813
|
+
const result = [];
|
|
814
|
+
for (const menu of menus) {
|
|
815
|
+
const aliasTitle = StringUtilities.changeAliasLowerCase(menu.title);
|
|
816
|
+
if (aliasTitle.includes(aliasSearchText)) {
|
|
817
|
+
result.push(menu);
|
|
818
|
+
continue;
|
|
819
|
+
}
|
|
820
|
+
let matchedChildren = [];
|
|
821
|
+
if ('children' in menu && menu.children?.length) {
|
|
822
|
+
matchedChildren = this.#getMenuByAliasSearchText(menu.children, aliasSearchText);
|
|
823
|
+
}
|
|
824
|
+
if (matchedChildren?.length) {
|
|
825
|
+
result.push({ ...menu, children: matchedChildren });
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
return result;
|
|
829
|
+
};
|
|
830
|
+
#isMenuPathMatchByCurrentPath = (path) => {
|
|
831
|
+
if (!path) {
|
|
832
|
+
return false;
|
|
833
|
+
}
|
|
834
|
+
if (this.currentPath() === path) {
|
|
835
|
+
return true;
|
|
836
|
+
}
|
|
837
|
+
return this.#normalizePath(this.currentPath()).startsWith(this.#normalizePath(path));
|
|
838
|
+
};
|
|
839
|
+
#normalizePath = (p) => (p.endsWith('/') ? p : p + '/');
|
|
840
|
+
#closeMenu() {
|
|
841
|
+
this.showSideBar.emit(null);
|
|
842
|
+
}
|
|
843
|
+
#convertColor = (input, opacity = 1) => {
|
|
844
|
+
if (!input) {
|
|
845
|
+
return '';
|
|
846
|
+
}
|
|
847
|
+
input = input.trim();
|
|
848
|
+
const hexRegex = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
|
|
849
|
+
const rgbRegex = /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/i;
|
|
850
|
+
if (hexRegex.test(input)) {
|
|
851
|
+
let hex = input.slice(1);
|
|
852
|
+
if (hex.length === 3) {
|
|
853
|
+
hex = hex
|
|
854
|
+
.split('')
|
|
855
|
+
.map(c => c + c)
|
|
856
|
+
.join('');
|
|
857
|
+
}
|
|
858
|
+
const r = parseInt(hex.substring(0, 2), 16);
|
|
859
|
+
const g = parseInt(hex.substring(2, 4), 16);
|
|
860
|
+
const b = parseInt(hex.substring(4, 6), 16);
|
|
861
|
+
return `rgba(${r}, ${g}, ${b}, ${opacity})`;
|
|
862
|
+
}
|
|
863
|
+
const rgbMatch = input.match(rgbRegex);
|
|
864
|
+
if (rgbMatch) {
|
|
865
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
866
|
+
const [_, r, g, b] = rgbMatch;
|
|
867
|
+
return `rgba(${r}, ${g}, ${b}, ${opacity})`;
|
|
868
|
+
}
|
|
869
|
+
return input;
|
|
870
|
+
};
|
|
871
|
+
#getValidSearchText = () => {
|
|
872
|
+
const normalized = this.#normalizeSearchText(this.searchText());
|
|
873
|
+
return normalized && normalized.length >= 2 ? normalized : '';
|
|
874
|
+
};
|
|
875
|
+
#normalizeSearchText = (searchText) => {
|
|
876
|
+
let str = searchText?.toString() ?? '';
|
|
877
|
+
/* eslint-disable no-useless-escape */
|
|
878
|
+
str = str.replace(/!|@|%|\^|\*|\(|\)|\+|\=|\<|\>|\?|\/|,|\.|\:|\;|\'|\"|\&|\#|\[|\]|~|\$|_|`|-|{|}|\||\\/g, '');
|
|
879
|
+
str = str.replace(/ + /g, ' ');
|
|
880
|
+
return str.trim();
|
|
881
|
+
};
|
|
882
|
+
#getTotalMenus = (menus) => {
|
|
883
|
+
return menus.reduce((total, menu) => total + this.#countMenuChildrenNode(menu), 0);
|
|
884
|
+
};
|
|
885
|
+
#countMenuChildrenNode = (menu) => {
|
|
886
|
+
if (!('children' in menu) || !menu.children?.length) {
|
|
887
|
+
return 0;
|
|
888
|
+
}
|
|
889
|
+
let count = menu.children.length;
|
|
890
|
+
for (const child of menu.children) {
|
|
891
|
+
count += this.#countMenuChildrenNode(child);
|
|
892
|
+
}
|
|
893
|
+
return count;
|
|
894
|
+
};
|
|
895
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SidebarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
896
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: SidebarComponent, isStandalone: true, selector: "sidebar", inputs: { isShowSidebar: { classPropertyName: "isShowSidebar", publicName: "isShowSidebar", isSignal: true, isRequired: true, transformFunction: null }, menus: { classPropertyName: "menus", publicName: "menus", isSignal: true, isRequired: true, transformFunction: null }, userInfo: { classPropertyName: "userInfo", publicName: "userInfo", isSignal: true, isRequired: true, transformFunction: null }, sidebar: { classPropertyName: "sidebar", publicName: "sidebar", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { expandSideBar: "expandSideBar", popupUserMenuClosed: "popupUserMenuClosed", popupUserMenuOpened: "popupUserMenuOpened", showSideBar: "showSideBar" }, ngImport: i0, template: "@let _userInfo = userInfo();\n@let _sidebar = sidebar();\n\n@if (_userInfo && _sidebar) {\n <div class=\"wrapper\" [style.height]=\"isMobileOrTablet ? screenHeight + 'px' : '100%'\">\n <div class=\"c-header\">\n @if (_sidebar.logoUrl) {\n <div class=\"c-logo\">\n <a href=\"javascript:;\" (click)=\"openHomePage()\">\n <img alt=\"logo\" [src]=\"_sidebar.logoUrl\" />\n </a>\n </div>\n }\n <div class=\"c-title-menu-group\">\n <span>{{ titleMenuGroup() || _sidebar.defaultTitle || 'Back Office' }}</span>\n </div>\n </div>\n <div class=\"c-body\">\n <div class=\"c-menu\">\n <div class=\"c-menu-group\">\n @if (_sidebar?.pin?.enabled && pinnedMenuGroup().children?.length) {\n <button\n (mouseenter)=\"onMouseOverMenuGroupNode($event, pinnedMenuGroup())\"\n (mouseleave)=\"onMouseLeaveMenuGroupNode($event, pinnedMenuGroup())\"\n (click)=\"expandPinnedGroup()\"\n [matTooltip]=\"'\u0110\u00E3 ghim'\"\n [matTooltipClass]=\"'c-tooltip-menu-group-7a22ab15-0083-4d4c-9c0c-00a30bc8c140'\"\n [matTooltipPosition]=\"'right'\"\n style=\"padding: 0; margin: 0; border: none; background-color: transparent\">\n <mat-icon\n class=\"c-menu-group-icon\"\n [ngStyle]=\"{\n color: isPinnedMenuGroupActive() ? _sidebar.brandColor || '#2962FF' : '#8C8C8C',\n backgroundColor: isPinnedMenuGroupActive() ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\n }\">\n push_pin\n </mat-icon>\n </button>\n }\n @for (nodeMenuGroup of menus(); track nodeMenuGroup.id) {\n <button\n (mouseenter)=\"onMouseOverMenuGroupNode($event, nodeMenuGroup)\"\n (mouseleave)=\"onMouseLeaveMenuGroupNode($event, nodeMenuGroup)\"\n (click)=\"expandMenuGroup(nodeMenuGroup)\"\n [matTooltip]=\"nodeMenuGroup.tooltipTitle || nodeMenuGroup.title\"\n [matTooltipClass]=\"'c-tooltip-menu-group-7a22ab15-0083-4d4c-9c0c-00a30bc8c140'\"\n [matTooltipPosition]=\"'right'\"\n style=\"padding: 0; margin: 0; border: none; background-color: transparent\">\n @if (nodeMenuGroup.iconUrl) {\n <span\n class=\"c-menu-group-icon\"\n [ngStyle]=\"{\n backgroundColor: idMenuGroupActive() === nodeMenuGroup?.id ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\n }\">\n <img width=\"24px\" height=\"24px\" [src]=\"nodeMenuGroup.iconUrl\" [alt]=\"nodeMenuGroup.title\" />\n </span>\n } @else {\n <mat-icon\n class=\"c-menu-group-icon\"\n [ngStyle]=\"{\n color: idMenuGroupActive() === nodeMenuGroup?.id ? _sidebar.brandColor || '#2962FF' : '#8C8C8C',\n backgroundColor: idMenuGroupActive() === nodeMenuGroup?.id ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\n }\">\n {{ nodeMenuGroup.icon || 'widgets' }}\n </mat-icon>\n }\n </button>\n }\n </div>\n <div class=\"c-menu-tree\">\n @if (totalMenuInMenusByGroup() >= 10) {\n <div style=\"padding: 0px 4px\" class=\"c-menu-tree-search\">\n <sd-input size=\"sm\" [placeholder]=\"'core.module.layout.sidebar.search' | translate\" [model]=\"searchText()\" (sdChange)=\"onFilterSearchText($event)\">\n <ng-template sdSuffixDef>\n @if (searchText()) {\n <mat-icon class=\"c-search-prefix-icon cancel\" (click)=\"onClearSearchText()\">cancel</mat-icon>\n } @else {\n <mat-icon class=\"c-search-prefix-icon search\">search</mat-icon>\n }\n </ng-template>\n </sd-input>\n </div>\n }\n <div class=\"c-menu-tree-container\">\n <mat-tree [dataSource]=\"dataSource\" [treeControl]=\"treeControl\" [style.backgroundColor]=\"'transparent'\">\n <mat-nested-tree-node *matTreeNodeDef=\"let node; when: !hasChild\">\n <li\n class=\"c-menu-node\"\n (mouseenter)=\"onMouseOverMenuNode($event, node)\"\n (mouseleave)=\"onMouseLeaveMenuNode($event, node)\"\n [ngStyle]=\"{\n backgroundColor: (currentPath() | menuFocus: node) ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\n }\">\n <div aria-hidden=\"true\" class=\"c-menu-node-description\" (click)=\"navigate(node)\" [class.d-none]=\"!isShowSidebar()\">\n <div\n class=\"c-menu-node-description-content\"\n [ngStyle]=\"{\n color: (currentPath() | menuFocus: node) ? _sidebar.brandColor || '#2962FF' : '#1F1F1F',\n }\"\n [innerHTML]=\"node.title | highLightSearch: searchText() | sdSafeHtml\"></div>\n\n @if (_sidebar?.pin?.enabled) {\n <mat-icon\n class=\"c-menu-node-description-icon-pin\"\n [fontSet]=\"isPinnedNode(node) ? 'material-icons' : 'material-icons-outlined'\"\n [style.opacity]=\"isPinnedNode(node) || isHoveredNode(node) ? '1' : null\"\n [style.color]=\"isPinnedNode(node) || isHoveredNode(node) ? sidebar().brandColor || '#2962FF' : null\"\n (click)=\"onTogglePin($event, node)\"\n >push_pin\n </mat-icon>\n }\n </div>\n </li>\n </mat-nested-tree-node>\n\n <mat-nested-tree-node\n *matTreeNodeDef=\"let node; when: hasChild\"\n aria-hidden=\"true\"\n [class]=\"{ expanded: treeControl.isExpanded(node), isfocus: currentPath() | menuFocus: node }\">\n <li>\n <div\n class=\"c-menu-node\"\n (mouseenter)=\"onMouseOverMenuNode($event, node)\"\n (mouseleave)=\"onMouseLeaveMenuNode($event, node)\">\n <div class=\"d-flex align-items-center\" style=\"gap: 10px; width: 100%\">\n <div [class.d-none]=\"!isShowSidebar()\" class=\"c-menu-node-description\" (click)=\"onToggleMenuNode(node)\">\n <div\n class=\"c-menu-node-description-content\"\n [innerHTML]=\"node.title | highLightSearch: searchText() | sdSafeHtml\"></div>\n <mat-icon class=\"c-menu-node-description-icon-expand\">\n {{ treeControl.isExpanded(node) ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }}\n </mat-icon>\n </div>\n </div>\n </div>\n <ul class=\"p-0\" [class.d-none]=\"!treeControl.isExpanded(node)\">\n <ng-container matTreeNodeOutlet></ng-container>\n </ul>\n </li>\n </mat-nested-tree-node>\n </mat-tree>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"c-footer\">\n <lib-layout-user\n [userInfo]=\"_userInfo\"\n [isMobileOrTablet]=\"isMobileOrTablet\"\n (menuOpened)=\"onUserMenuOpened()\"\n (menuClosed)=\"onUserMenuClosed()\"\n [isShowSidebar]=\"isShowSidebar()\"\n (toggleMenuLock)=\"toggleMenuLock($event)\">\n </lib-layout-user>\n </div>\n\n <div class=\"c-vertical\"></div>\n </div>\n}\n", styles: ["::ng-deep .mat-mdc-tooltip-panel:has(.c-tooltip-menu-group-7a22ab15-0083-4d4c-9c0c-00a30bc8c140){pointer-events:none}:host ::ng-deep .mat-nested-tree-node ul .c-menu-node-description-content{margin-left:16px!important}:host ::ng-deep .mat-nested-tree-node ul .mat-nested-tree-node ul .c-menu-node-description-content{margin-left:32px!important}:host ::ng-deep .mat-nested-tree-node ul .mat-nested-tree-node ul .mat-nested-tree-node ul .c-menu-node-description-content{margin-left:48px!important}ul,li{margin-top:0;margin-bottom:0;list-style-type:none}.wrapper{display:flex;flex-direction:column;width:290px;background-color:#fff}.wrapper .c-header{display:flex;align-items:center;height:52px;padding:3px;gap:16px}.wrapper .c-header .c-logo{display:flex;justify-content:center;align-items:center;width:52px;height:52px}.wrapper .c-header .c-logo img{width:32px;height:32px;object-fit:cover}.wrapper .c-header .c-title-menu-group{display:flex;align-items:center;font-size:18px;font-weight:500;flex:1}.wrapper .c-body{flex:1;overflow-y:hidden}.wrapper .c-body .c-menu{height:100%;display:flex}.wrapper .c-body .c-menu .c-menu-group{display:flex;flex-direction:column;align-items:center;width:60px;overflow-y:scroll;scrollbar-width:none}.wrapper .c-body .c-menu .c-menu-group .c-menu-group-icon{display:flex;justify-content:center;align-items:center;min-height:50px;width:52px;border-radius:8px;transition:all .15s}.wrapper .c-body .c-menu .c-menu-group .c-menu-group-icon img{height:24px;width:24px;object-fit:contain}.wrapper .c-body .c-menu .c-menu-tree{flex:1;display:flex;flex-direction:column;padding:3px 4px 3px 3px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-search .c-search-prefix-icon{cursor:pointer;color:#757575;padding:0}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-search .c-search-prefix-icon.search{width:20px;height:20px;font-size:18px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-search .c-search-prefix-icon.cancel{width:16px;height:16px;font-size:16px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container{flex:1;overflow-y:scroll;scrollbar-width:none}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node{width:100%;display:flex;cursor:pointer;min-height:44px;padding:8px;border-radius:8px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node .c-menu-node-icon{display:flex;justify-content:center;align-items:center;height:100%}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node .c-menu-node-description{flex:1;display:flex;align-items:center}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node .c-menu-node-description .c-menu-node-description-content{flex:1;display:flex;align-items:center;flex-wrap:wrap;white-space:pre-wrap;font-size:15px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node .c-menu-node-description .c-menu-node-description-icon-expand{display:flex;align-items:center;justify-content:start;background-color:transparent;border:none;font-size:20px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node .c-menu-node-description .c-menu-node-description-icon-pin{display:flex;align-items:center;justify-content:start;background-color:transparent;border:none;font-size:18px;opacity:0}.wrapper .c-footer{height:80px}.wrapper .c-vertical{position:fixed;height:100vh;left:58px;width:2px;background-color:#f8f9fa;pointer-events:none}\n"], dependencies: [{ kind: "component", type: SdInput, selector: "sd-input", inputs: ["autoId", "name", "appearance", "floatLabel", "size", "form", "label", "helperText", "placeholder", "type", "hideInlineError", "blurOnEnter", "required", "readonly", "disabled", "viewed", "minlength", "maxlength", "pattern", "patternErrorMessage", "validator", "inlineError", "hyperlink", "model"], outputs: ["modelChange", "sdChange", "sdFocus", "sdBlur", "keyupEnter", "cleared", "sdFocusForceBlur"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$4.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: RouterModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTreeModule }, { kind: "directive", type: i3.MatNestedTreeNode, selector: "mat-nested-tree-node", inputs: ["matNestedTreeNode", "disabled", "tabIndex"], outputs: ["activation", "expandedChange"], exportAs: ["matNestedTreeNode"] }, { kind: "directive", type: i3.MatTreeNodeDef, selector: "[matTreeNodeDef]", inputs: ["matTreeNodeDefWhen", "matTreeNode"] }, { kind: "component", type: i3.MatTree, selector: "mat-tree", exportAs: ["matTree"] }, { kind: "directive", type: i3.MatTreeNodeOutlet, selector: "[matTreeNodeOutlet]" }, { kind: "pipe", type: SdSafeHtmlPipe, name: "sdSafeHtml" }, { kind: "ngmodule", type: MatInputModule }, { kind: "pipe", type: MenuFocusPipe, name: "menuFocus" }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "pipe", type: HighlightSearchPipe, name: "highLightSearch" }, { kind: "directive", type: SdSuffixDefDirective, selector: "[sdSuffixDef]" }, { kind: "component", type: LayoutUserComponent$1, selector: "lib-layout-user", inputs: ["isMobileOrTablet", "isMenuLock", "isShowSidebar", "userInfo"], outputs: ["menuClosed", "menuOpened", "toggleMenuLock"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
|
|
897
|
+
}
|
|
898
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SidebarComponent, decorators: [{
|
|
899
|
+
type: Component,
|
|
900
|
+
args: [{ selector: 'sidebar', standalone: true, imports: [
|
|
901
|
+
SdInput,
|
|
902
|
+
FormsModule,
|
|
903
|
+
CommonModule,
|
|
904
|
+
RouterModule,
|
|
905
|
+
MatIconModule,
|
|
906
|
+
MatTreeModule,
|
|
907
|
+
SdSafeHtmlPipe,
|
|
908
|
+
MatInputModule,
|
|
909
|
+
MenuFocusPipe,
|
|
910
|
+
MatTooltipModule,
|
|
911
|
+
HighlightSearchPipe,
|
|
912
|
+
SdSuffixDefDirective,
|
|
913
|
+
LayoutUserComponent$1,
|
|
914
|
+
TranslatePipe,
|
|
915
|
+
], template: "@let _userInfo = userInfo();\n@let _sidebar = sidebar();\n\n@if (_userInfo && _sidebar) {\n <div class=\"wrapper\" [style.height]=\"isMobileOrTablet ? screenHeight + 'px' : '100%'\">\n <div class=\"c-header\">\n @if (_sidebar.logoUrl) {\n <div class=\"c-logo\">\n <a href=\"javascript:;\" (click)=\"openHomePage()\">\n <img alt=\"logo\" [src]=\"_sidebar.logoUrl\" />\n </a>\n </div>\n }\n <div class=\"c-title-menu-group\">\n <span>{{ titleMenuGroup() || _sidebar.defaultTitle || 'Back Office' }}</span>\n </div>\n </div>\n <div class=\"c-body\">\n <div class=\"c-menu\">\n <div class=\"c-menu-group\">\n @if (_sidebar?.pin?.enabled && pinnedMenuGroup().children?.length) {\n <button\n (mouseenter)=\"onMouseOverMenuGroupNode($event, pinnedMenuGroup())\"\n (mouseleave)=\"onMouseLeaveMenuGroupNode($event, pinnedMenuGroup())\"\n (click)=\"expandPinnedGroup()\"\n [matTooltip]=\"'\u0110\u00E3 ghim'\"\n [matTooltipClass]=\"'c-tooltip-menu-group-7a22ab15-0083-4d4c-9c0c-00a30bc8c140'\"\n [matTooltipPosition]=\"'right'\"\n style=\"padding: 0; margin: 0; border: none; background-color: transparent\">\n <mat-icon\n class=\"c-menu-group-icon\"\n [ngStyle]=\"{\n color: isPinnedMenuGroupActive() ? _sidebar.brandColor || '#2962FF' : '#8C8C8C',\n backgroundColor: isPinnedMenuGroupActive() ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\n }\">\n push_pin\n </mat-icon>\n </button>\n }\n @for (nodeMenuGroup of menus(); track nodeMenuGroup.id) {\n <button\n (mouseenter)=\"onMouseOverMenuGroupNode($event, nodeMenuGroup)\"\n (mouseleave)=\"onMouseLeaveMenuGroupNode($event, nodeMenuGroup)\"\n (click)=\"expandMenuGroup(nodeMenuGroup)\"\n [matTooltip]=\"nodeMenuGroup.tooltipTitle || nodeMenuGroup.title\"\n [matTooltipClass]=\"'c-tooltip-menu-group-7a22ab15-0083-4d4c-9c0c-00a30bc8c140'\"\n [matTooltipPosition]=\"'right'\"\n style=\"padding: 0; margin: 0; border: none; background-color: transparent\">\n @if (nodeMenuGroup.iconUrl) {\n <span\n class=\"c-menu-group-icon\"\n [ngStyle]=\"{\n backgroundColor: idMenuGroupActive() === nodeMenuGroup?.id ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\n }\">\n <img width=\"24px\" height=\"24px\" [src]=\"nodeMenuGroup.iconUrl\" [alt]=\"nodeMenuGroup.title\" />\n </span>\n } @else {\n <mat-icon\n class=\"c-menu-group-icon\"\n [ngStyle]=\"{\n color: idMenuGroupActive() === nodeMenuGroup?.id ? _sidebar.brandColor || '#2962FF' : '#8C8C8C',\n backgroundColor: idMenuGroupActive() === nodeMenuGroup?.id ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\n }\">\n {{ nodeMenuGroup.icon || 'widgets' }}\n </mat-icon>\n }\n </button>\n }\n </div>\n <div class=\"c-menu-tree\">\n @if (totalMenuInMenusByGroup() >= 10) {\n <div style=\"padding: 0px 4px\" class=\"c-menu-tree-search\">\n <sd-input size=\"sm\" [placeholder]=\"'core.module.layout.sidebar.search' | translate\" [model]=\"searchText()\" (sdChange)=\"onFilterSearchText($event)\">\n <ng-template sdSuffixDef>\n @if (searchText()) {\n <mat-icon class=\"c-search-prefix-icon cancel\" (click)=\"onClearSearchText()\">cancel</mat-icon>\n } @else {\n <mat-icon class=\"c-search-prefix-icon search\">search</mat-icon>\n }\n </ng-template>\n </sd-input>\n </div>\n }\n <div class=\"c-menu-tree-container\">\n <mat-tree [dataSource]=\"dataSource\" [treeControl]=\"treeControl\" [style.backgroundColor]=\"'transparent'\">\n <mat-nested-tree-node *matTreeNodeDef=\"let node; when: !hasChild\">\n <li\n class=\"c-menu-node\"\n (mouseenter)=\"onMouseOverMenuNode($event, node)\"\n (mouseleave)=\"onMouseLeaveMenuNode($event, node)\"\n [ngStyle]=\"{\n backgroundColor: (currentPath() | menuFocus: node) ? _sidebar.brandLightColor || '#F8F9FA' : 'transparent',\n }\">\n <div aria-hidden=\"true\" class=\"c-menu-node-description\" (click)=\"navigate(node)\" [class.d-none]=\"!isShowSidebar()\">\n <div\n class=\"c-menu-node-description-content\"\n [ngStyle]=\"{\n color: (currentPath() | menuFocus: node) ? _sidebar.brandColor || '#2962FF' : '#1F1F1F',\n }\"\n [innerHTML]=\"node.title | highLightSearch: searchText() | sdSafeHtml\"></div>\n\n @if (_sidebar?.pin?.enabled) {\n <mat-icon\n class=\"c-menu-node-description-icon-pin\"\n [fontSet]=\"isPinnedNode(node) ? 'material-icons' : 'material-icons-outlined'\"\n [style.opacity]=\"isPinnedNode(node) || isHoveredNode(node) ? '1' : null\"\n [style.color]=\"isPinnedNode(node) || isHoveredNode(node) ? sidebar().brandColor || '#2962FF' : null\"\n (click)=\"onTogglePin($event, node)\"\n >push_pin\n </mat-icon>\n }\n </div>\n </li>\n </mat-nested-tree-node>\n\n <mat-nested-tree-node\n *matTreeNodeDef=\"let node; when: hasChild\"\n aria-hidden=\"true\"\n [class]=\"{ expanded: treeControl.isExpanded(node), isfocus: currentPath() | menuFocus: node }\">\n <li>\n <div\n class=\"c-menu-node\"\n (mouseenter)=\"onMouseOverMenuNode($event, node)\"\n (mouseleave)=\"onMouseLeaveMenuNode($event, node)\">\n <div class=\"d-flex align-items-center\" style=\"gap: 10px; width: 100%\">\n <div [class.d-none]=\"!isShowSidebar()\" class=\"c-menu-node-description\" (click)=\"onToggleMenuNode(node)\">\n <div\n class=\"c-menu-node-description-content\"\n [innerHTML]=\"node.title | highLightSearch: searchText() | sdSafeHtml\"></div>\n <mat-icon class=\"c-menu-node-description-icon-expand\">\n {{ treeControl.isExpanded(node) ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }}\n </mat-icon>\n </div>\n </div>\n </div>\n <ul class=\"p-0\" [class.d-none]=\"!treeControl.isExpanded(node)\">\n <ng-container matTreeNodeOutlet></ng-container>\n </ul>\n </li>\n </mat-nested-tree-node>\n </mat-tree>\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"c-footer\">\n <lib-layout-user\n [userInfo]=\"_userInfo\"\n [isMobileOrTablet]=\"isMobileOrTablet\"\n (menuOpened)=\"onUserMenuOpened()\"\n (menuClosed)=\"onUserMenuClosed()\"\n [isShowSidebar]=\"isShowSidebar()\"\n (toggleMenuLock)=\"toggleMenuLock($event)\">\n </lib-layout-user>\n </div>\n\n <div class=\"c-vertical\"></div>\n </div>\n}\n", styles: ["::ng-deep .mat-mdc-tooltip-panel:has(.c-tooltip-menu-group-7a22ab15-0083-4d4c-9c0c-00a30bc8c140){pointer-events:none}:host ::ng-deep .mat-nested-tree-node ul .c-menu-node-description-content{margin-left:16px!important}:host ::ng-deep .mat-nested-tree-node ul .mat-nested-tree-node ul .c-menu-node-description-content{margin-left:32px!important}:host ::ng-deep .mat-nested-tree-node ul .mat-nested-tree-node ul .mat-nested-tree-node ul .c-menu-node-description-content{margin-left:48px!important}ul,li{margin-top:0;margin-bottom:0;list-style-type:none}.wrapper{display:flex;flex-direction:column;width:290px;background-color:#fff}.wrapper .c-header{display:flex;align-items:center;height:52px;padding:3px;gap:16px}.wrapper .c-header .c-logo{display:flex;justify-content:center;align-items:center;width:52px;height:52px}.wrapper .c-header .c-logo img{width:32px;height:32px;object-fit:cover}.wrapper .c-header .c-title-menu-group{display:flex;align-items:center;font-size:18px;font-weight:500;flex:1}.wrapper .c-body{flex:1;overflow-y:hidden}.wrapper .c-body .c-menu{height:100%;display:flex}.wrapper .c-body .c-menu .c-menu-group{display:flex;flex-direction:column;align-items:center;width:60px;overflow-y:scroll;scrollbar-width:none}.wrapper .c-body .c-menu .c-menu-group .c-menu-group-icon{display:flex;justify-content:center;align-items:center;min-height:50px;width:52px;border-radius:8px;transition:all .15s}.wrapper .c-body .c-menu .c-menu-group .c-menu-group-icon img{height:24px;width:24px;object-fit:contain}.wrapper .c-body .c-menu .c-menu-tree{flex:1;display:flex;flex-direction:column;padding:3px 4px 3px 3px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-search .c-search-prefix-icon{cursor:pointer;color:#757575;padding:0}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-search .c-search-prefix-icon.search{width:20px;height:20px;font-size:18px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-search .c-search-prefix-icon.cancel{width:16px;height:16px;font-size:16px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container{flex:1;overflow-y:scroll;scrollbar-width:none}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node{width:100%;display:flex;cursor:pointer;min-height:44px;padding:8px;border-radius:8px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node .c-menu-node-icon{display:flex;justify-content:center;align-items:center;height:100%}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node .c-menu-node-description{flex:1;display:flex;align-items:center}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node .c-menu-node-description .c-menu-node-description-content{flex:1;display:flex;align-items:center;flex-wrap:wrap;white-space:pre-wrap;font-size:15px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node .c-menu-node-description .c-menu-node-description-icon-expand{display:flex;align-items:center;justify-content:start;background-color:transparent;border:none;font-size:20px}.wrapper .c-body .c-menu .c-menu-tree .c-menu-tree-container .c-menu-node .c-menu-node-description .c-menu-node-description-icon-pin{display:flex;align-items:center;justify-content:start;background-color:transparent;border:none;font-size:18px;opacity:0}.wrapper .c-footer{height:80px}.wrapper .c-vertical{position:fixed;height:100vh;left:58px;width:2px;background-color:#f8f9fa;pointer-events:none}\n"] }]
|
|
916
|
+
}], ctorParameters: () => [] });
|
|
917
|
+
|
|
918
|
+
class SidebarV1Component {
|
|
919
|
+
// ==========================================
|
|
920
|
+
// INJECT SERVICES
|
|
921
|
+
// ==========================================
|
|
922
|
+
#layoutStorageService = inject(SdLayoutStorageService);
|
|
923
|
+
// ==========================================
|
|
924
|
+
// VIEW CHILD & INPUTS
|
|
925
|
+
// ==========================================
|
|
926
|
+
sidenav = viewChild.required('sidenav');
|
|
927
|
+
menus = input([]);
|
|
928
|
+
userInfo = input.required();
|
|
929
|
+
sidebar = input.required();
|
|
930
|
+
// ==========================================
|
|
931
|
+
// STATE SIGNALS
|
|
932
|
+
// ==========================================
|
|
933
|
+
isMobileOrTablet = signal(BrowserUtilities.isMobile());
|
|
934
|
+
// Trạng thái khóa menu (luôn mở rộng hay không)
|
|
935
|
+
isMenuLock = signal(this.#layoutStorageService.menuLockStatus?.get() ?? true);
|
|
936
|
+
// Trạng thái hiển thị (mở/đóng) của Sidenav
|
|
937
|
+
isShowSidebar = signal(BrowserUtilities.isMobile() ? false : (this.#layoutStorageService.menuLockStatus?.get() ?? true));
|
|
938
|
+
onhover = signal(false);
|
|
939
|
+
// ==========================================
|
|
940
|
+
// PRIVATE TIMERS
|
|
941
|
+
// ==========================================
|
|
942
|
+
#timerMouseInMenu = null;
|
|
943
|
+
constructor() {
|
|
944
|
+
// EFFECT: Tự động đồng bộ isShowSidebar vào storage service mỗi khi nó thay đổi
|
|
945
|
+
effect(() => {
|
|
946
|
+
const isShow = this.isShowSidebar();
|
|
947
|
+
untracked(() => {
|
|
948
|
+
this.#layoutStorageService.isShowSidebar.set(isShow);
|
|
949
|
+
});
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
// ==========================================
|
|
953
|
+
// EVENT HANDLERS
|
|
954
|
+
// ==========================================
|
|
955
|
+
#mouseLeave = () => {
|
|
956
|
+
if (this.#timerMouseInMenu) {
|
|
957
|
+
clearTimeout(this.#timerMouseInMenu);
|
|
958
|
+
}
|
|
959
|
+
if (this.onhover() && this.isShowSidebar()) {
|
|
960
|
+
this.isShowSidebar.set(false);
|
|
961
|
+
this.onhover.set(false);
|
|
962
|
+
}
|
|
963
|
+
};
|
|
964
|
+
#handleMouseLeaveTransition = () => {
|
|
965
|
+
if (!this.isShowSidebar()) {
|
|
966
|
+
const delayTime = 400;
|
|
967
|
+
if (this.#timerMouseInMenu) {
|
|
968
|
+
clearTimeout(this.#timerMouseInMenu);
|
|
969
|
+
}
|
|
970
|
+
setTimeout(() => {
|
|
971
|
+
this.#mouseLeave();
|
|
972
|
+
}, delayTime);
|
|
973
|
+
}
|
|
974
|
+
else {
|
|
975
|
+
this.#mouseLeave();
|
|
976
|
+
}
|
|
977
|
+
};
|
|
978
|
+
openSidebar = () => {
|
|
979
|
+
if (!this.isMobileOrTablet()) {
|
|
980
|
+
return;
|
|
981
|
+
}
|
|
982
|
+
if (!this.isShowSidebar()) {
|
|
983
|
+
this.isShowSidebar.set(true);
|
|
984
|
+
this.onhover.set(true);
|
|
985
|
+
}
|
|
986
|
+
};
|
|
987
|
+
onPopupOfSideBarOpened = () => {
|
|
988
|
+
this.onhover.set(false);
|
|
989
|
+
this.isShowSidebar.set(true);
|
|
990
|
+
};
|
|
991
|
+
onPopupOfSideBarClosed = () => {
|
|
992
|
+
const delayTime = 500;
|
|
993
|
+
if (!this.isMenuLock()) {
|
|
994
|
+
this.onhover.set(true);
|
|
995
|
+
setTimeout(() => {
|
|
996
|
+
this.#mouseLeave();
|
|
997
|
+
}, delayTime);
|
|
998
|
+
}
|
|
999
|
+
};
|
|
1000
|
+
onExpandSideBar = () => {
|
|
1001
|
+
if (this.isMobileOrTablet()) {
|
|
1002
|
+
return;
|
|
1003
|
+
}
|
|
1004
|
+
if (!this.isShowSidebar()) {
|
|
1005
|
+
this.isShowSidebar.set(true);
|
|
1006
|
+
this.onhover.set(true);
|
|
1007
|
+
}
|
|
1008
|
+
};
|
|
1009
|
+
onMouseleaveSideBar = () => {
|
|
1010
|
+
if (this.isMobileOrTablet()) {
|
|
1011
|
+
return;
|
|
1012
|
+
}
|
|
1013
|
+
this.#mouseLeave();
|
|
1014
|
+
};
|
|
1015
|
+
onToggle = (data) => {
|
|
1016
|
+
if (data === null) {
|
|
1017
|
+
this.#handleMouseLeaveTransition();
|
|
1018
|
+
}
|
|
1019
|
+
else {
|
|
1020
|
+
this.#mouseLeave();
|
|
1021
|
+
this.isShowSidebar.set(data);
|
|
1022
|
+
this.isMenuLock.set(data);
|
|
1023
|
+
// Toggle component MatSidenav
|
|
1024
|
+
const sidenavComp = this.sidenav();
|
|
1025
|
+
if (sidenavComp) {
|
|
1026
|
+
data ? sidenavComp.open() : sidenavComp.close();
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
};
|
|
1030
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SidebarV1Component, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1031
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "19.2.21", type: SidebarV1Component, isStandalone: true, selector: "sidebar-v1", inputs: { menus: { classPropertyName: "menus", publicName: "menus", isSignal: true, isRequired: false, transformFunction: null }, userInfo: { classPropertyName: "userInfo", publicName: "userInfo", isSignal: true, isRequired: true, transformFunction: null }, sidebar: { classPropertyName: "sidebar", publicName: "sidebar", isSignal: true, isRequired: true, transformFunction: null } }, viewQueries: [{ propertyName: "sidenav", first: true, predicate: ["sidenav"], descendants: true, isSignal: true }], ngImport: i0, template: "<mat-sidenav-container class=\"c-layout-wrapper\">\n <mat-sidenav\n #sidenav\n [opened]=\"isShowSidebar()\"\n (openedChange)=\"isShowSidebar.set($event)\"\n class=\"c-layout-sidebar\"\n (click)=\"openSidebar()\"\n (mouseleave)=\"onMouseleaveSideBar()\"\n [mode]=\"isMobileOrTablet() ? 'over' : 'side'\"\n [fixedInViewport]=\"isMobileOrTablet()\">\n <sidebar\n [menus]=\"menus()\"\n [userInfo]=\"userInfo()\"\n [sidebar]=\"sidebar()\"\n [isShowSidebar]=\"isShowSidebar()\"\n (showSideBar)=\"onToggle($event)\"\n (expandSideBar)=\"onExpandSideBar()\"\n (popupUserMenuOpened)=\"onPopupOfSideBarOpened()\"\n (popupUserMenuClosed)=\"onPopupOfSideBarClosed()\">\n </sidebar>\n </mat-sidenav>\n\n <mat-sidenav-content class=\"c-layout-content\" [class.isShowSidebar]=\"isMenuLock()\">\n <mat-drawer-container class=\"c-mat-drawer-container\">\n <mat-drawer-content>\n <ng-content></ng-content>\n </mat-drawer-content>\n </mat-drawer-container>\n </mat-sidenav-content>\n</mat-sidenav-container>", styles: [":host ::ng-deep .c-layout-wrapper{width:100%}:host ::ng-deep .c-layout-wrapper .c-layout-sidebar{margin-top:0;width:60px;height:100vh!important;transform:none!important;overflow:hidden!important;visibility:visible!important;transition:width .15s!important;box-shadow:0 0 6px #0003!important}:host ::ng-deep .c-layout-wrapper .c-layout-sidebar .mat-drawer-inner-container{position:relative;overflow:visible;display:block!important}:host ::ng-deep .c-layout-wrapper .c-layout-sidebar.mat-drawer-opened{width:290px;transition:width .15s}:host ::ng-deep .c-layout-wrapper .c-layout-content{background-color:#fff;box-sizing:border-box;height:100vh!important;margin-left:60px!important}:host ::ng-deep .c-layout-wrapper .c-layout-content.isShowSidebar{margin-left:290px!important}:host ::ng-deep .c-layout-wrapper .c-layout-content .c-mat-drawer-container{height:100%}\n"], dependencies: [{ kind: "ngmodule", type: MatSidenavModule }, { kind: "component", type: i1$5.MatDrawerContainer, selector: "mat-drawer-container", inputs: ["autosize", "hasBackdrop"], outputs: ["backdropClick"], exportAs: ["matDrawerContainer"] }, { kind: "component", type: i1$5.MatDrawerContent, selector: "mat-drawer-content" }, { kind: "component", type: i1$5.MatSidenav, selector: "mat-sidenav", inputs: ["fixedInViewport", "fixedTopGap", "fixedBottomGap"], exportAs: ["matSidenav"] }, { kind: "component", type: i1$5.MatSidenavContainer, selector: "mat-sidenav-container", exportAs: ["matSidenavContainer"] }, { kind: "component", type: i1$5.MatSidenavContent, selector: "mat-sidenav-content" }, { kind: "ngmodule", type: CommonModule }, { kind: "component", type: SidebarComponent, selector: "sidebar", inputs: ["isShowSidebar", "menus", "userInfo", "sidebar"], outputs: ["expandSideBar", "popupUserMenuClosed", "popupUserMenuOpened", "showSideBar"] }] });
|
|
1032
|
+
}
|
|
1033
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SidebarV1Component, decorators: [{
|
|
1034
|
+
type: Component,
|
|
1035
|
+
args: [{ selector: 'sidebar-v1', imports: [MatSidenavModule, CommonModule, SidebarComponent], standalone: true, template: "<mat-sidenav-container class=\"c-layout-wrapper\">\n <mat-sidenav\n #sidenav\n [opened]=\"isShowSidebar()\"\n (openedChange)=\"isShowSidebar.set($event)\"\n class=\"c-layout-sidebar\"\n (click)=\"openSidebar()\"\n (mouseleave)=\"onMouseleaveSideBar()\"\n [mode]=\"isMobileOrTablet() ? 'over' : 'side'\"\n [fixedInViewport]=\"isMobileOrTablet()\">\n <sidebar\n [menus]=\"menus()\"\n [userInfo]=\"userInfo()\"\n [sidebar]=\"sidebar()\"\n [isShowSidebar]=\"isShowSidebar()\"\n (showSideBar)=\"onToggle($event)\"\n (expandSideBar)=\"onExpandSideBar()\"\n (popupUserMenuOpened)=\"onPopupOfSideBarOpened()\"\n (popupUserMenuClosed)=\"onPopupOfSideBarClosed()\">\n </sidebar>\n </mat-sidenav>\n\n <mat-sidenav-content class=\"c-layout-content\" [class.isShowSidebar]=\"isMenuLock()\">\n <mat-drawer-container class=\"c-mat-drawer-container\">\n <mat-drawer-content>\n <ng-content></ng-content>\n </mat-drawer-content>\n </mat-drawer-container>\n </mat-sidenav-content>\n</mat-sidenav-container>", styles: [":host ::ng-deep .c-layout-wrapper{width:100%}:host ::ng-deep .c-layout-wrapper .c-layout-sidebar{margin-top:0;width:60px;height:100vh!important;transform:none!important;overflow:hidden!important;visibility:visible!important;transition:width .15s!important;box-shadow:0 0 6px #0003!important}:host ::ng-deep .c-layout-wrapper .c-layout-sidebar .mat-drawer-inner-container{position:relative;overflow:visible;display:block!important}:host ::ng-deep .c-layout-wrapper .c-layout-sidebar.mat-drawer-opened{width:290px;transition:width .15s}:host ::ng-deep .c-layout-wrapper .c-layout-content{background-color:#fff;box-sizing:border-box;height:100vh!important;margin-left:60px!important}:host ::ng-deep .c-layout-wrapper .c-layout-content.isShowSidebar{margin-left:290px!important}:host ::ng-deep .c-layout-wrapper .c-layout-content .c-mat-drawer-container{height:100%}\n"] }]
|
|
1036
|
+
}], ctorParameters: () => [] });
|
|
1037
|
+
|
|
1038
|
+
class LayoutUserComponent {
|
|
1039
|
+
// ==========================================
|
|
1040
|
+
// INJECT SERVICES
|
|
1041
|
+
// ==========================================
|
|
1042
|
+
#layoutConfiguration = inject(SD_LAYOUT_CONFIGURATION);
|
|
1043
|
+
// ==========================================
|
|
1044
|
+
// SIGNAL INPUTS & OUTPUTS
|
|
1045
|
+
// ==========================================
|
|
1046
|
+
isMobileOrTablet = input(false);
|
|
1047
|
+
isMenuLock = input(false);
|
|
1048
|
+
isShowSidebar = input(false);
|
|
1049
|
+
userInfo = input.required();
|
|
1050
|
+
menuClosed = output();
|
|
1051
|
+
menuOpened = output();
|
|
1052
|
+
toggleMenuLock = output();
|
|
1053
|
+
// Config actions
|
|
1054
|
+
singoutLayoutConfig = this.#layoutConfiguration.signout;
|
|
1055
|
+
changePasswordLayoutConfig = this.#layoutConfiguration?.changePassword;
|
|
1056
|
+
// Accordion state for mobile inline expand
|
|
1057
|
+
isExpanded = signal(false);
|
|
1058
|
+
// ==========================================
|
|
1059
|
+
// EVENT HANDLERS
|
|
1060
|
+
// ==========================================
|
|
1061
|
+
onMenuOpened = () => {
|
|
1062
|
+
this.menuOpened.emit();
|
|
1063
|
+
};
|
|
1064
|
+
onMenuClosed = () => {
|
|
1065
|
+
this.menuClosed.emit();
|
|
1066
|
+
};
|
|
1067
|
+
keepOpenWhenClickInsideMenu = (event) => {
|
|
1068
|
+
event.stopPropagation();
|
|
1069
|
+
};
|
|
1070
|
+
toggleExpanded = () => {
|
|
1071
|
+
this.isExpanded.update(v => !v);
|
|
1072
|
+
if (this.isExpanded()) {
|
|
1073
|
+
this.menuOpened.emit();
|
|
1074
|
+
}
|
|
1075
|
+
else {
|
|
1076
|
+
this.menuClosed.emit();
|
|
1077
|
+
}
|
|
1078
|
+
};
|
|
1079
|
+
logout = () => {
|
|
1080
|
+
this.singoutLayoutConfig();
|
|
1081
|
+
};
|
|
1082
|
+
changePassword = () => {
|
|
1083
|
+
this.changePasswordLayoutConfig?.();
|
|
1084
|
+
};
|
|
1085
|
+
onToggleMenuLock = (event) => {
|
|
1086
|
+
this.toggleMenuLock.emit(event);
|
|
1087
|
+
};
|
|
1088
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LayoutUserComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1089
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: LayoutUserComponent, isStandalone: true, selector: "lib-layout-user", inputs: { isMobileOrTablet: { classPropertyName: "isMobileOrTablet", publicName: "isMobileOrTablet", isSignal: true, isRequired: false, transformFunction: null }, isMenuLock: { classPropertyName: "isMenuLock", publicName: "isMenuLock", isSignal: true, isRequired: false, transformFunction: null }, isShowSidebar: { classPropertyName: "isShowSidebar", publicName: "isShowSidebar", isSignal: true, isRequired: false, transformFunction: null }, userInfo: { classPropertyName: "userInfo", publicName: "userInfo", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { menuClosed: "menuClosed", menuOpened: "menuOpened", toggleMenuLock: "toggleMenuLock" }, ngImport: i0, template: "@let _userInfo = userInfo();\n@let avatar = _userInfo?.avatar || _userInfo?.fullName || _userInfo?.username || _userInfo?.email;\n\n@if (isMobileOrTablet()) {\n <!-- Mobile: accordion inline expand -->\n <div class=\"m-user-card\">\n <button class=\"m-user-row\" (click)=\"toggleExpanded()\">\n <sd-avatar [src]=\"avatar\" [size]=\"44\"></sd-avatar>\n <div class=\"m-user-info\">\n <span class=\"m-user-name\">{{ _userInfo?.fullName || _userInfo?.username }}</span>\n @if (_userInfo?.email) {\n <span class=\"m-user-email\">{{ _userInfo?.email }}</span>\n }\n </div>\n <mat-icon class=\"m-expand-icon\" [class.m-expand-icon--open]=\"isExpanded()\">\n keyboard_arrow_down\n </mat-icon>\n </button>\n\n @if (isExpanded()) {\n <div class=\"m-user-body\">\n @if (changePasswordLayoutConfig) {\n <button class=\"m-user-action\" (click)=\"changePassword()\">\n <mat-icon>lock_outline</mat-icon>\n <span>{{ 'core.module.layout.user.change-password' | translate }}</span>\n </button>\n }\n <button class=\"m-user-action m-user-action--logout\" (click)=\"logout()\">\n <mat-icon>logout</mat-icon>\n <span>{{ 'core.module.layout.user.logout' | translate }}</span>\n </button>\n </div>\n }\n </div>\n} @else {\n <!-- Desktop: ch\u1EC9 hi\u1EC3n th\u1ECB avatar + n\u00FAt toggle -->\n <div class=\"c-layout-user-wrapper\">\n <div class=\"c-layout-user-avatar\" [matMenuTriggerFor]=\"userMenu\" (menuClosed)=\"onMenuClosed()\" (menuOpened)=\"onMenuOpened()\">\n <sd-avatar [src]=\"avatar\" [size]=\"32\"></sd-avatar>\n </div>\n\n <div aria-hidden=\"true\" mat-mini-fab class=\"c-layout-icon-toggle\" (click)=\"onToggleMenuLock($event)\">\n <mat-icon style=\"color: #8c8c8c\">\n {{ isShowSidebar() ? 'keyboard_arrow_right' : 'keyboard_arrow_left' }}\n </mat-icon>\n </div>\n </div>\n}\n\n<mat-menu #userMenu=\"matMenu\" xPosition=\"before\" backdropClass=\"c-user-menu-backdrop-f90ce131-fa4c-4f71-a49b-ab7fa374fdd0\">\n <div aria-hidden=\"true\" class=\"c-user-menu-wrapper\" (click)=\"keepOpenWhenClickInsideMenu($event)\">\n <div class=\"c-user-info-wrapper\">\n <div class=\"c-user-avatar\">\n <sd-avatar [src]=\"avatar\" [size]=\"40\"></sd-avatar>\n </div>\n <span class=\"c-user-name\">{{ _userInfo?.fullName || _userInfo?.username }}</span>\n <span class=\"c-user-email\">{{ _userInfo?.email }}</span>\n </div>\n\n @if (changePasswordLayoutConfig) {\n <div class=\"c-sign-button-wrapper\">\n <button class=\"c-account-options\" (click)=\"changePassword()\">\n <mat-icon fontSet=\"material-icons-outlined\">lock</mat-icon>\n <span>{{ 'core.module.layout.user.change-password' | translate }}</span>\n </button>\n </div>\n }\n\n <div class=\"c-sign-button-wrapper\">\n <button class=\"c-sign-button\" mat-flat-button (click)=\"logout()\">{{ 'core.module.layout.user.logout' | translate }}</button>\n </div>\n </div>\n</mat-menu>\n", styles: ["@media(min-width:1024px){::ng-deep .c-user-menu-backdrop-f90ce131-fa4c-4f71-a49b-ab7fa374fdd0+* .cdk-overlay-pane{transform:translate(277px,83px)}}.m-user-card{width:100%}.m-user-row{display:flex;align-items:center;gap:12px;width:100%;padding:0;border:none;background:transparent;cursor:pointer;text-align:left;-webkit-tap-highlight-color:transparent}.m-user-info{flex:1;display:flex;flex-direction:column;gap:2px;overflow:hidden}.m-user-name{font-size:15px;font-weight:600;color:#1f1f1f;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.m-user-email{font-size:13px;color:#8c8c8c;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.m-expand-icon{color:#8c8c8c;flex-shrink:0;transition:transform .2s ease}.m-expand-icon--open{transform:rotate(180deg)}.m-user-body{margin-top:8px;border-top:1px solid #EBEBEB;padding-top:4px;display:flex;flex-direction:column}.m-user-action{display:flex;align-items:center;gap:12px;width:100%;padding:12px 4px;border:none;background:transparent;cursor:pointer;font-size:15px;color:#1f1f1f;-webkit-tap-highlight-color:transparent}.m-user-action mat-icon{color:#8c8c8c;font-size:20px;width:20px;height:20px}.m-user-action:active{background-color:#f5f5f5}.m-user-action--logout{color:#e53935}.m-user-action--logout mat-icon{color:#e53935}.c-layout-user-wrapper{display:flex;flex-direction:column;align-items:center;width:60px;height:80px}.c-layout-user-wrapper .c-layout-user-avatar{width:32px;height:32px;display:flex;align-items:center;justify-content:center;cursor:pointer}.c-layout-user-wrapper .c-layout-icon-toggle{background-color:transparent;border-top:1px solid #f0f0f0;box-shadow:none;margin-top:10px;width:32px;height:40px;display:flex;justify-content:center;align-items:center;cursor:pointer}.c-user-menu-wrapper .c-user-info-wrapper{width:250px;padding:16px;display:flex;flex-direction:column;align-items:center;gap:8px}.c-user-menu-wrapper .c-user-info-wrapper .c-user-avatar{width:40px;height:40px}.c-user-menu-wrapper .c-user-info-wrapper .c-user-name{font-size:16px;font-weight:700;text-align:center}.c-user-menu-wrapper .c-user-info-wrapper .c-user-email{font-size:14px;color:#7a7a7a;text-align:center}.c-user-menu-wrapper .c-sign-button-wrapper{text-align:center;padding:16px 16px 8px;width:100%;border-top:1px solid #dee2e6}.c-user-menu-wrapper .c-sign-button-wrapper .c-account-options{all:unset;cursor:pointer;font-size:14px;display:flex;align-items:center;gap:8px}.c-user-menu-wrapper .c-sign-button-wrapper .c-account-options mat-icon{font-size:21px;width:21px;height:21px;color:#8c8c8c}.c-user-menu-wrapper .c-sign-button-wrapper .c-sign-button{width:100%;color:#000;padding:16px;font-weight:700;background-color:#eef0f2}.c-avatar{max-width:100%;object-fit:cover}\n"], dependencies: [{ kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i1$2.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "directive", type: i1$2.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "component", type: SdAvatar, selector: "sd-avatar", inputs: ["src", "size"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
|
|
1090
|
+
}
|
|
1091
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: LayoutUserComponent, decorators: [{
|
|
1092
|
+
type: Component,
|
|
1093
|
+
args: [{ selector: 'lib-layout-user', imports: [MatMenuModule, MatButtonModule, MatIconModule, MatTooltipModule, SdAvatar, TranslatePipe], standalone: true, template: "@let _userInfo = userInfo();\n@let avatar = _userInfo?.avatar || _userInfo?.fullName || _userInfo?.username || _userInfo?.email;\n\n@if (isMobileOrTablet()) {\n <!-- Mobile: accordion inline expand -->\n <div class=\"m-user-card\">\n <button class=\"m-user-row\" (click)=\"toggleExpanded()\">\n <sd-avatar [src]=\"avatar\" [size]=\"44\"></sd-avatar>\n <div class=\"m-user-info\">\n <span class=\"m-user-name\">{{ _userInfo?.fullName || _userInfo?.username }}</span>\n @if (_userInfo?.email) {\n <span class=\"m-user-email\">{{ _userInfo?.email }}</span>\n }\n </div>\n <mat-icon class=\"m-expand-icon\" [class.m-expand-icon--open]=\"isExpanded()\">\n keyboard_arrow_down\n </mat-icon>\n </button>\n\n @if (isExpanded()) {\n <div class=\"m-user-body\">\n @if (changePasswordLayoutConfig) {\n <button class=\"m-user-action\" (click)=\"changePassword()\">\n <mat-icon>lock_outline</mat-icon>\n <span>{{ 'core.module.layout.user.change-password' | translate }}</span>\n </button>\n }\n <button class=\"m-user-action m-user-action--logout\" (click)=\"logout()\">\n <mat-icon>logout</mat-icon>\n <span>{{ 'core.module.layout.user.logout' | translate }}</span>\n </button>\n </div>\n }\n </div>\n} @else {\n <!-- Desktop: ch\u1EC9 hi\u1EC3n th\u1ECB avatar + n\u00FAt toggle -->\n <div class=\"c-layout-user-wrapper\">\n <div class=\"c-layout-user-avatar\" [matMenuTriggerFor]=\"userMenu\" (menuClosed)=\"onMenuClosed()\" (menuOpened)=\"onMenuOpened()\">\n <sd-avatar [src]=\"avatar\" [size]=\"32\"></sd-avatar>\n </div>\n\n <div aria-hidden=\"true\" mat-mini-fab class=\"c-layout-icon-toggle\" (click)=\"onToggleMenuLock($event)\">\n <mat-icon style=\"color: #8c8c8c\">\n {{ isShowSidebar() ? 'keyboard_arrow_right' : 'keyboard_arrow_left' }}\n </mat-icon>\n </div>\n </div>\n}\n\n<mat-menu #userMenu=\"matMenu\" xPosition=\"before\" backdropClass=\"c-user-menu-backdrop-f90ce131-fa4c-4f71-a49b-ab7fa374fdd0\">\n <div aria-hidden=\"true\" class=\"c-user-menu-wrapper\" (click)=\"keepOpenWhenClickInsideMenu($event)\">\n <div class=\"c-user-info-wrapper\">\n <div class=\"c-user-avatar\">\n <sd-avatar [src]=\"avatar\" [size]=\"40\"></sd-avatar>\n </div>\n <span class=\"c-user-name\">{{ _userInfo?.fullName || _userInfo?.username }}</span>\n <span class=\"c-user-email\">{{ _userInfo?.email }}</span>\n </div>\n\n @if (changePasswordLayoutConfig) {\n <div class=\"c-sign-button-wrapper\">\n <button class=\"c-account-options\" (click)=\"changePassword()\">\n <mat-icon fontSet=\"material-icons-outlined\">lock</mat-icon>\n <span>{{ 'core.module.layout.user.change-password' | translate }}</span>\n </button>\n </div>\n }\n\n <div class=\"c-sign-button-wrapper\">\n <button class=\"c-sign-button\" mat-flat-button (click)=\"logout()\">{{ 'core.module.layout.user.logout' | translate }}</button>\n </div>\n </div>\n</mat-menu>\n", styles: ["@media(min-width:1024px){::ng-deep .c-user-menu-backdrop-f90ce131-fa4c-4f71-a49b-ab7fa374fdd0+* .cdk-overlay-pane{transform:translate(277px,83px)}}.m-user-card{width:100%}.m-user-row{display:flex;align-items:center;gap:12px;width:100%;padding:0;border:none;background:transparent;cursor:pointer;text-align:left;-webkit-tap-highlight-color:transparent}.m-user-info{flex:1;display:flex;flex-direction:column;gap:2px;overflow:hidden}.m-user-name{font-size:15px;font-weight:600;color:#1f1f1f;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.m-user-email{font-size:13px;color:#8c8c8c;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.m-expand-icon{color:#8c8c8c;flex-shrink:0;transition:transform .2s ease}.m-expand-icon--open{transform:rotate(180deg)}.m-user-body{margin-top:8px;border-top:1px solid #EBEBEB;padding-top:4px;display:flex;flex-direction:column}.m-user-action{display:flex;align-items:center;gap:12px;width:100%;padding:12px 4px;border:none;background:transparent;cursor:pointer;font-size:15px;color:#1f1f1f;-webkit-tap-highlight-color:transparent}.m-user-action mat-icon{color:#8c8c8c;font-size:20px;width:20px;height:20px}.m-user-action:active{background-color:#f5f5f5}.m-user-action--logout{color:#e53935}.m-user-action--logout mat-icon{color:#e53935}.c-layout-user-wrapper{display:flex;flex-direction:column;align-items:center;width:60px;height:80px}.c-layout-user-wrapper .c-layout-user-avatar{width:32px;height:32px;display:flex;align-items:center;justify-content:center;cursor:pointer}.c-layout-user-wrapper .c-layout-icon-toggle{background-color:transparent;border-top:1px solid #f0f0f0;box-shadow:none;margin-top:10px;width:32px;height:40px;display:flex;justify-content:center;align-items:center;cursor:pointer}.c-user-menu-wrapper .c-user-info-wrapper{width:250px;padding:16px;display:flex;flex-direction:column;align-items:center;gap:8px}.c-user-menu-wrapper .c-user-info-wrapper .c-user-avatar{width:40px;height:40px}.c-user-menu-wrapper .c-user-info-wrapper .c-user-name{font-size:16px;font-weight:700;text-align:center}.c-user-menu-wrapper .c-user-info-wrapper .c-user-email{font-size:14px;color:#7a7a7a;text-align:center}.c-user-menu-wrapper .c-sign-button-wrapper{text-align:center;padding:16px 16px 8px;width:100%;border-top:1px solid #dee2e6}.c-user-menu-wrapper .c-sign-button-wrapper .c-account-options{all:unset;cursor:pointer;font-size:14px;display:flex;align-items:center;gap:8px}.c-user-menu-wrapper .c-sign-button-wrapper .c-account-options mat-icon{font-size:21px;width:21px;height:21px;color:#8c8c8c}.c-user-menu-wrapper .c-sign-button-wrapper .c-sign-button{width:100%;color:#000;padding:16px;font-weight:700;background-color:#eef0f2}.c-avatar{max-width:100%;object-fit:cover}\n"] }]
|
|
1094
|
+
}] });
|
|
1095
|
+
|
|
1096
|
+
class SidebarMobileOverlayComponent {
|
|
1097
|
+
#router = inject(Router);
|
|
1098
|
+
#destroyRef = inject(DestroyRef);
|
|
1099
|
+
#layoutStorageService = inject(SdLayoutStorageService);
|
|
1100
|
+
// ==========================================
|
|
1101
|
+
// INPUTS & OUTPUTS
|
|
1102
|
+
// ==========================================
|
|
1103
|
+
isShowSidebar = input(false);
|
|
1104
|
+
menus = input.required();
|
|
1105
|
+
userInfo = input.required();
|
|
1106
|
+
sidebar = input.required();
|
|
1107
|
+
// showSideBar(null) = đóng sidebar (tương thích với onToggle của main component)
|
|
1108
|
+
showSideBar = output();
|
|
1109
|
+
expandSideBar = output();
|
|
1110
|
+
popupUserMenuOpened = output();
|
|
1111
|
+
popupUserMenuClosed = output();
|
|
1112
|
+
titleMenuGroupChanged = output();
|
|
1113
|
+
// ==========================================
|
|
1114
|
+
// STATE SIGNALS
|
|
1115
|
+
// ==========================================
|
|
1116
|
+
titleMenuGroup = signal('');
|
|
1117
|
+
currentPath = signal(window.location.pathname);
|
|
1118
|
+
// Lưu danh sách ID các menu group đang được mở
|
|
1119
|
+
expandedMobileGroups = signal(new Set());
|
|
1120
|
+
constructor() {
|
|
1121
|
+
// Bind title khi menus thay đổi
|
|
1122
|
+
effect(() => {
|
|
1123
|
+
const currentMenus = this.menus();
|
|
1124
|
+
untracked(() => {
|
|
1125
|
+
const lastActiveMenuGroupId = this.#layoutStorageService.lastActiveMenuGroupId.get();
|
|
1126
|
+
if (!lastActiveMenuGroupId) {
|
|
1127
|
+
this.#layoutStorageService.lastActiveMenuGroupId.set(currentMenus?.[0]?.id ?? '');
|
|
1128
|
+
}
|
|
1129
|
+
this.#bindingMenuGroupByCurrentPath(currentMenus);
|
|
1130
|
+
});
|
|
1131
|
+
});
|
|
1132
|
+
// Bind title khi điều hướng
|
|
1133
|
+
this.#router.events.pipe(takeUntilDestroyed(this.#destroyRef)).subscribe(event => {
|
|
1134
|
+
if (event instanceof NavigationEnd) {
|
|
1135
|
+
if (this.currentPath() !== window.location.pathname) {
|
|
1136
|
+
this.currentPath.set(window.location.pathname);
|
|
1137
|
+
this.#bindingMenuGroupByCurrentPath(this.menus());
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
});
|
|
1141
|
+
}
|
|
1142
|
+
// ==========================================
|
|
1143
|
+
// EVENT HANDLERS
|
|
1144
|
+
// ==========================================
|
|
1145
|
+
toggleMobileGroup(groupId) {
|
|
1146
|
+
if (!groupId)
|
|
1147
|
+
return;
|
|
1148
|
+
this.expandedMobileGroups.update(groups => {
|
|
1149
|
+
const newGroups = new Set(groups);
|
|
1150
|
+
if (newGroups.has(groupId)) {
|
|
1151
|
+
newGroups.delete(groupId);
|
|
1152
|
+
}
|
|
1153
|
+
else {
|
|
1154
|
+
newGroups.add(groupId);
|
|
1155
|
+
}
|
|
1156
|
+
return newGroups;
|
|
1157
|
+
});
|
|
1158
|
+
}
|
|
1159
|
+
isExpanded(groupId) {
|
|
1160
|
+
if (!groupId)
|
|
1161
|
+
return false;
|
|
1162
|
+
return this.expandedMobileGroups().has(groupId);
|
|
1163
|
+
}
|
|
1164
|
+
navigate(args) {
|
|
1165
|
+
const { path, queryParams } = args;
|
|
1166
|
+
if (!path)
|
|
1167
|
+
return;
|
|
1168
|
+
if (path.includes('http')) {
|
|
1169
|
+
window.open(path);
|
|
1170
|
+
return;
|
|
1171
|
+
}
|
|
1172
|
+
this.#router.navigate([path.split('?')[0]], {
|
|
1173
|
+
queryParams: queryParams ?? {},
|
|
1174
|
+
state: { switchTab: true },
|
|
1175
|
+
});
|
|
1176
|
+
// Sau khi điều hướng trên mobile, tự động đóng sidebar
|
|
1177
|
+
this.onClose();
|
|
1178
|
+
}
|
|
1179
|
+
onClose() {
|
|
1180
|
+
this.showSideBar.emit(null);
|
|
1181
|
+
}
|
|
1182
|
+
// Kiểm tra menu có children (là SdLayoutChildrenMenu)
|
|
1183
|
+
hasChildren(menu) {
|
|
1184
|
+
return 'children' in menu && !!menu.children?.length;
|
|
1185
|
+
}
|
|
1186
|
+
// Lấy danh sách children an toàn (type-safe)
|
|
1187
|
+
getChildren(menu) {
|
|
1188
|
+
return 'children' in menu ? (menu.children ?? []) : [];
|
|
1189
|
+
}
|
|
1190
|
+
// Lấy path an toàn từ leaf menu (SdLayoutRootMenu)
|
|
1191
|
+
getPath(menu) {
|
|
1192
|
+
return 'path' in menu ? menu.path : undefined;
|
|
1193
|
+
}
|
|
1194
|
+
// Lấy queryParams an toàn từ leaf menu
|
|
1195
|
+
getQueryParams(menu) {
|
|
1196
|
+
return ('queryParams' in menu ? menu.queryParams : undefined) ?? {};
|
|
1197
|
+
}
|
|
1198
|
+
onUserMenuOpened = () => this.popupUserMenuOpened.emit();
|
|
1199
|
+
onUserMenuClosed = () => this.popupUserMenuClosed.emit();
|
|
1200
|
+
// ==========================================
|
|
1201
|
+
// PRIVATE LOGIC
|
|
1202
|
+
// ==========================================
|
|
1203
|
+
#bindingMenuGroupByCurrentPath = (menus) => {
|
|
1204
|
+
let menuGroupByPath = this.#getMenuGroupByCurrentPath(menus);
|
|
1205
|
+
if (!menuGroupByPath?.length) {
|
|
1206
|
+
const lastActiveId = this.#layoutStorageService.lastActiveMenuGroupId.get() || '';
|
|
1207
|
+
menuGroupByPath = menus?.filter(menu => menu?.id === lastActiveId) || [];
|
|
1208
|
+
}
|
|
1209
|
+
if (menuGroupByPath?.length) {
|
|
1210
|
+
const matchedGroup = menuGroupByPath[0];
|
|
1211
|
+
this.#layoutStorageService.lastActiveMenuGroupId.set(matchedGroup?.id || '');
|
|
1212
|
+
const title = matchedGroup?.tooltipTitle || matchedGroup?.title;
|
|
1213
|
+
this.titleMenuGroup.set(title);
|
|
1214
|
+
this.titleMenuGroupChanged.emit(title);
|
|
1215
|
+
}
|
|
1216
|
+
else {
|
|
1217
|
+
this.titleMenuGroup.set('');
|
|
1218
|
+
this.titleMenuGroupChanged.emit('');
|
|
1219
|
+
}
|
|
1220
|
+
};
|
|
1221
|
+
#getMenuGroupByCurrentPath = (menus, menuGroup) => {
|
|
1222
|
+
for (const menu of menus) {
|
|
1223
|
+
if ('path' in menu && this.#isMenuPathMatchByCurrentPath(menu.path)) {
|
|
1224
|
+
return [menuGroup ?? menu];
|
|
1225
|
+
}
|
|
1226
|
+
if ('children' in menu && menu.children?.length) {
|
|
1227
|
+
const result = this.#getMenuGroupByCurrentPath(menu.children, menuGroup ?? menu);
|
|
1228
|
+
if (result?.length)
|
|
1229
|
+
return result;
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
return [];
|
|
1233
|
+
};
|
|
1234
|
+
#isMenuPathMatchByCurrentPath = (path) => {
|
|
1235
|
+
if (!path)
|
|
1236
|
+
return false;
|
|
1237
|
+
if (this.currentPath() === path)
|
|
1238
|
+
return true;
|
|
1239
|
+
return this.#normalizePath(this.currentPath()).startsWith(this.#normalizePath(path));
|
|
1240
|
+
};
|
|
1241
|
+
#normalizePath = (p) => p.endsWith('/') ? p : p + '/';
|
|
1242
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SidebarMobileOverlayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1243
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: SidebarMobileOverlayComponent, isStandalone: true, selector: "sd-sidebar-mobile-overlay", inputs: { isShowSidebar: { classPropertyName: "isShowSidebar", publicName: "isShowSidebar", isSignal: true, isRequired: false, transformFunction: null }, menus: { classPropertyName: "menus", publicName: "menus", isSignal: true, isRequired: true, transformFunction: null }, userInfo: { classPropertyName: "userInfo", publicName: "userInfo", isSignal: true, isRequired: true, transformFunction: null }, sidebar: { classPropertyName: "sidebar", publicName: "sidebar", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { showSideBar: "showSideBar", expandSideBar: "expandSideBar", popupUserMenuOpened: "popupUserMenuOpened", popupUserMenuClosed: "popupUserMenuClosed", titleMenuGroupChanged: "titleMenuGroupChanged" }, ngImport: i0, template: "@let _userInfo = userInfo();\n@let _sidebar = sidebar();\n\n@if (_userInfo && _sidebar) {\n <div\n class=\"m-backdrop\"\n [class.m-backdrop--visible]=\"isShowSidebar()\"\n role=\"button\"\n tabindex=\"0\"\n (click)=\"onClose()\"\n (keydown.escape)=\"onClose()\">\n </div>\n\n <div class=\"m-wrapper\" [class.m-wrapper--open]=\"isShowSidebar()\">\n <div class=\"m-header\">\n <div class=\"m-title-group\">\n @if (_sidebar.logoUrl) {\n <img class=\"m-logo\" alt=\"logo\" [src]=\"_sidebar.logoUrl\" />\n }\n <span class=\"m-title\">{{ titleMenuGroup() || _sidebar.defaultTitle || 'Back Office' }}</span>\n </div>\n <button class=\"m-close-btn\" (click)=\"onClose()\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n\n <div class=\"m-user-section\">\n <lib-layout-user\n [userInfo]=\"_userInfo\"\n [isMobileOrTablet]=\"true\"\n (menuOpened)=\"onUserMenuOpened()\"\n (menuClosed)=\"onUserMenuClosed()\">\n </lib-layout-user>\n </div>\n\n <div class=\"m-menu-list\">\n @for (group of menus(); track group.id) {\n <div class=\"m-menu-card\">\n <button class=\"m-card-header\" (click)=\"toggleMobileGroup(group.id)\">\n <div class=\"m-card-header-left\">\n @if (group.iconUrl) {\n <img class=\"m-group-icon\" [src]=\"group.iconUrl\" [alt]=\"group.title\" />\n } @else {\n <mat-icon class=\"m-group-icon\">{{ group.icon || 'widgets' }}</mat-icon>\n }\n <span class=\"m-group-title\">{{ group.title }}</span>\n </div>\n <mat-icon class=\"m-expand-icon\">\n {{ expandedMobileGroups().has(group.id ?? '') ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }}\n </mat-icon>\n </button>\n\n @if (expandedMobileGroups().has(group.id ?? '') && hasChildren(group)) {\n <div class=\"m-card-body\">\n @for (child of getChildren(group); track child.id) {\n @if (hasChildren(child)) {\n <div class=\"m-sub-group\">\n <button class=\"m-sub-group-header\" (click)=\"toggleMobileGroup(child.id)\">\n <div class=\"m-item-left\">\n @if (child.iconUrl) {\n <img class=\"m-item-icon-img\" [src]=\"child.iconUrl\" alt=\"icon\" />\n } @else {\n <mat-icon class=\"m-item-icon\">{{ child.icon || 'folder' }}</mat-icon>\n }\n <span class=\"m-item-title\">{{ child.title }}</span>\n </div>\n <mat-icon class=\"m-expand-icon\">\n {{ expandedMobileGroups().has(child.id ?? '') ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }}\n </mat-icon>\n </button>\n @if (expandedMobileGroups().has(child.id ?? '')) {\n @for (subChild of getChildren(child); track subChild.id) {\n <button class=\"m-menu-item m-menu-item--indented\"\n (click)=\"navigate({ path: getPath(subChild), queryParams: getQueryParams(subChild) })\">\n <div class=\"m-item-left\">\n @if (subChild.iconUrl) {\n <img class=\"m-item-icon-img\" [src]=\"subChild.iconUrl\" alt=\"icon\" />\n } @else {\n <mat-icon class=\"m-item-icon\">{{ subChild.icon || 'insert_drive_file' }}</mat-icon>\n }\n <span class=\"m-item-title\">{{ subChild.title }}</span>\n </div>\n <mat-icon class=\"m-nav-icon\">chevron_right</mat-icon>\n </button>\n }\n }\n </div>\n } @else {\n <button class=\"m-menu-item\" (click)=\"navigate({ path: getPath(child), queryParams: getQueryParams(child) })\">\n <div class=\"m-item-left\">\n @if (child.iconUrl) {\n <img class=\"m-item-icon-img\" [src]=\"child.iconUrl\" alt=\"icon\" />\n } @else {\n <mat-icon class=\"m-item-icon\">{{ child.icon || 'insert_drive_file' }}</mat-icon>\n }\n <span class=\"m-item-title\">{{ child.title }}</span>\n </div>\n <mat-icon class=\"m-nav-icon\">chevron_right</mat-icon>\n </button>\n }\n }\n </div>\n }\n </div>\n }\n </div>\n </div>\n}\n", styles: [":host{display:block;position:fixed;inset:0;z-index:1000;pointer-events:none}.m-backdrop{position:absolute;inset:0;background:#0006;opacity:0;pointer-events:none;transition:opacity .3s ease;cursor:pointer;outline:none}.m-backdrop--visible{opacity:1;pointer-events:auto}.m-wrapper{display:flex;flex-direction:column;position:absolute;inset:0;background-color:#f2f2f6;padding:16px;box-sizing:border-box;overflow-y:auto;pointer-events:none;padding-top:max(16px,env(safe-area-inset-top));padding-bottom:max(16px,env(safe-area-inset-bottom));transform:translate(-100%);transition:transform .3s cubic-bezier(.4,0,.2,1)}.m-wrapper--open{transform:translate(0);pointer-events:auto}.m-wrapper .m-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:24px}.m-wrapper .m-header .m-title-group{display:flex;align-items:center;gap:12px}.m-wrapper .m-header .m-title-group .m-logo{width:32px;height:32px;object-fit:contain}.m-wrapper .m-header .m-title-group .m-title{font-size:18px;font-weight:600;color:#1f1f1f}.m-wrapper .m-header .m-close-btn{background:transparent;border:none;padding:0;color:#1f1f1f;display:flex;align-items:center;justify-content:center;cursor:pointer}.m-wrapper .m-header .m-close-btn mat-icon{font-size:28px;width:28px;height:28px}.m-wrapper .m-user-section{background-color:#fff;border-radius:12px;padding:12px 16px;margin-bottom:24px;box-shadow:0 1px 2px #00000005;border:1px solid #EBEBEB}.m-wrapper .m-user-section lib-layout-user{display:block;width:100%}.m-wrapper .m-menu-list{display:flex;flex-direction:column;gap:16px}.m-wrapper .m-menu-card{background-color:#fff;border-radius:12px;border:1px solid #EBEBEB;overflow:hidden}.m-wrapper .m-menu-card .m-card-header{display:flex;justify-content:space-between;align-items:center;width:100%;padding:16px;cursor:pointer;-webkit-user-select:none;user-select:none;border:none;background:transparent;-webkit-tap-highlight-color:transparent}.m-wrapper .m-menu-card .m-card-header .m-card-header-left{display:flex;align-items:center;gap:16px}.m-wrapper .m-menu-card .m-card-header .m-card-header-left .m-group-icon{font-size:24px;width:24px;height:24px;color:#1f1f1f;object-fit:contain}.m-wrapper .m-menu-card .m-card-header .m-card-header-left .m-group-title{font-size:16px;font-weight:600;color:#1f1f1f}.m-wrapper .m-menu-card .m-card-header .m-expand-icon{color:#1f1f1f;transition:transform .2s ease}.m-wrapper .m-menu-card .m-card-body{display:flex;flex-direction:column;padding-bottom:8px}.m-wrapper .m-menu-card .m-card-body .m-menu-item{display:flex;justify-content:space-between;align-items:center;width:100%;padding:12px 16px 12px 24px;cursor:pointer;border:none;background:transparent;transition:background-color .2s;-webkit-tap-highlight-color:transparent}.m-wrapper .m-menu-card .m-card-body .m-menu-item:active{background-color:#f5f5f5}.m-wrapper .m-menu-card .m-card-body .m-menu-item--indented{padding-left:48px}.m-wrapper .m-menu-card .m-card-body .m-menu-item .m-item-left{display:flex;align-items:center;gap:12px}.m-wrapper .m-menu-card .m-card-body .m-menu-item .m-item-left .m-item-icon{font-size:20px;width:20px;height:20px;color:#8c8c8c}.m-wrapper .m-menu-card .m-card-body .m-menu-item .m-item-left .m-item-icon-img{width:20px;height:20px;object-fit:contain;opacity:.7}.m-wrapper .m-menu-card .m-card-body .m-menu-item .m-item-left .m-item-title{font-size:15px;color:#333}.m-wrapper .m-menu-card .m-card-body .m-menu-item .m-nav-icon{color:#8c8c8c;font-size:20px;width:20px;height:20px}.m-wrapper .m-menu-card .m-card-body .m-sub-group{border-top:1px solid #EBEBEB}.m-wrapper .m-menu-card .m-card-body .m-sub-group:first-child{border-top:none}.m-wrapper .m-menu-card .m-card-body .m-sub-group .m-sub-group-header{display:flex;justify-content:space-between;align-items:center;width:100%;padding:12px 16px 12px 24px;cursor:pointer;border:none;background:#fafafa;-webkit-tap-highlight-color:transparent}.m-wrapper .m-menu-card .m-card-body .m-sub-group .m-sub-group-header:active{background-color:#f0f0f0}.m-wrapper .m-menu-card .m-card-body .m-sub-group .m-sub-group-header .m-item-left{display:flex;align-items:center;gap:12px}.m-wrapper .m-menu-card .m-card-body .m-sub-group .m-sub-group-header .m-item-left .m-item-icon{font-size:20px;width:20px;height:20px;color:#8c8c8c}.m-wrapper .m-menu-card .m-card-body .m-sub-group .m-sub-group-header .m-item-left .m-item-icon-img{width:20px;height:20px;object-fit:contain;opacity:.7}.m-wrapper .m-menu-card .m-card-body .m-sub-group .m-sub-group-header .m-item-left .m-item-title{font-size:15px;font-weight:500;color:#333}.m-wrapper .m-menu-card .m-card-body .m-sub-group .m-sub-group-header .m-expand-icon{color:#8c8c8c;font-size:20px;width:20px;height:20px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: RouterModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: LayoutUserComponent, selector: "lib-layout-user", inputs: ["isMobileOrTablet", "isMenuLock", "isShowSidebar", "userInfo"], outputs: ["menuClosed", "menuOpened", "toggleMenuLock"] }] });
|
|
1244
|
+
}
|
|
1245
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SidebarMobileOverlayComponent, decorators: [{
|
|
1246
|
+
type: Component,
|
|
1247
|
+
args: [{ selector: 'sd-sidebar-mobile-overlay', standalone: true, imports: [
|
|
1248
|
+
CommonModule,
|
|
1249
|
+
RouterModule,
|
|
1250
|
+
MatIconModule,
|
|
1251
|
+
LayoutUserComponent,
|
|
1252
|
+
], template: "@let _userInfo = userInfo();\n@let _sidebar = sidebar();\n\n@if (_userInfo && _sidebar) {\n <div\n class=\"m-backdrop\"\n [class.m-backdrop--visible]=\"isShowSidebar()\"\n role=\"button\"\n tabindex=\"0\"\n (click)=\"onClose()\"\n (keydown.escape)=\"onClose()\">\n </div>\n\n <div class=\"m-wrapper\" [class.m-wrapper--open]=\"isShowSidebar()\">\n <div class=\"m-header\">\n <div class=\"m-title-group\">\n @if (_sidebar.logoUrl) {\n <img class=\"m-logo\" alt=\"logo\" [src]=\"_sidebar.logoUrl\" />\n }\n <span class=\"m-title\">{{ titleMenuGroup() || _sidebar.defaultTitle || 'Back Office' }}</span>\n </div>\n <button class=\"m-close-btn\" (click)=\"onClose()\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n\n <div class=\"m-user-section\">\n <lib-layout-user\n [userInfo]=\"_userInfo\"\n [isMobileOrTablet]=\"true\"\n (menuOpened)=\"onUserMenuOpened()\"\n (menuClosed)=\"onUserMenuClosed()\">\n </lib-layout-user>\n </div>\n\n <div class=\"m-menu-list\">\n @for (group of menus(); track group.id) {\n <div class=\"m-menu-card\">\n <button class=\"m-card-header\" (click)=\"toggleMobileGroup(group.id)\">\n <div class=\"m-card-header-left\">\n @if (group.iconUrl) {\n <img class=\"m-group-icon\" [src]=\"group.iconUrl\" [alt]=\"group.title\" />\n } @else {\n <mat-icon class=\"m-group-icon\">{{ group.icon || 'widgets' }}</mat-icon>\n }\n <span class=\"m-group-title\">{{ group.title }}</span>\n </div>\n <mat-icon class=\"m-expand-icon\">\n {{ expandedMobileGroups().has(group.id ?? '') ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }}\n </mat-icon>\n </button>\n\n @if (expandedMobileGroups().has(group.id ?? '') && hasChildren(group)) {\n <div class=\"m-card-body\">\n @for (child of getChildren(group); track child.id) {\n @if (hasChildren(child)) {\n <div class=\"m-sub-group\">\n <button class=\"m-sub-group-header\" (click)=\"toggleMobileGroup(child.id)\">\n <div class=\"m-item-left\">\n @if (child.iconUrl) {\n <img class=\"m-item-icon-img\" [src]=\"child.iconUrl\" alt=\"icon\" />\n } @else {\n <mat-icon class=\"m-item-icon\">{{ child.icon || 'folder' }}</mat-icon>\n }\n <span class=\"m-item-title\">{{ child.title }}</span>\n </div>\n <mat-icon class=\"m-expand-icon\">\n {{ expandedMobileGroups().has(child.id ?? '') ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }}\n </mat-icon>\n </button>\n @if (expandedMobileGroups().has(child.id ?? '')) {\n @for (subChild of getChildren(child); track subChild.id) {\n <button class=\"m-menu-item m-menu-item--indented\"\n (click)=\"navigate({ path: getPath(subChild), queryParams: getQueryParams(subChild) })\">\n <div class=\"m-item-left\">\n @if (subChild.iconUrl) {\n <img class=\"m-item-icon-img\" [src]=\"subChild.iconUrl\" alt=\"icon\" />\n } @else {\n <mat-icon class=\"m-item-icon\">{{ subChild.icon || 'insert_drive_file' }}</mat-icon>\n }\n <span class=\"m-item-title\">{{ subChild.title }}</span>\n </div>\n <mat-icon class=\"m-nav-icon\">chevron_right</mat-icon>\n </button>\n }\n }\n </div>\n } @else {\n <button class=\"m-menu-item\" (click)=\"navigate({ path: getPath(child), queryParams: getQueryParams(child) })\">\n <div class=\"m-item-left\">\n @if (child.iconUrl) {\n <img class=\"m-item-icon-img\" [src]=\"child.iconUrl\" alt=\"icon\" />\n } @else {\n <mat-icon class=\"m-item-icon\">{{ child.icon || 'insert_drive_file' }}</mat-icon>\n }\n <span class=\"m-item-title\">{{ child.title }}</span>\n </div>\n <mat-icon class=\"m-nav-icon\">chevron_right</mat-icon>\n </button>\n }\n }\n </div>\n }\n </div>\n }\n </div>\n </div>\n}\n", styles: [":host{display:block;position:fixed;inset:0;z-index:1000;pointer-events:none}.m-backdrop{position:absolute;inset:0;background:#0006;opacity:0;pointer-events:none;transition:opacity .3s ease;cursor:pointer;outline:none}.m-backdrop--visible{opacity:1;pointer-events:auto}.m-wrapper{display:flex;flex-direction:column;position:absolute;inset:0;background-color:#f2f2f6;padding:16px;box-sizing:border-box;overflow-y:auto;pointer-events:none;padding-top:max(16px,env(safe-area-inset-top));padding-bottom:max(16px,env(safe-area-inset-bottom));transform:translate(-100%);transition:transform .3s cubic-bezier(.4,0,.2,1)}.m-wrapper--open{transform:translate(0);pointer-events:auto}.m-wrapper .m-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:24px}.m-wrapper .m-header .m-title-group{display:flex;align-items:center;gap:12px}.m-wrapper .m-header .m-title-group .m-logo{width:32px;height:32px;object-fit:contain}.m-wrapper .m-header .m-title-group .m-title{font-size:18px;font-weight:600;color:#1f1f1f}.m-wrapper .m-header .m-close-btn{background:transparent;border:none;padding:0;color:#1f1f1f;display:flex;align-items:center;justify-content:center;cursor:pointer}.m-wrapper .m-header .m-close-btn mat-icon{font-size:28px;width:28px;height:28px}.m-wrapper .m-user-section{background-color:#fff;border-radius:12px;padding:12px 16px;margin-bottom:24px;box-shadow:0 1px 2px #00000005;border:1px solid #EBEBEB}.m-wrapper .m-user-section lib-layout-user{display:block;width:100%}.m-wrapper .m-menu-list{display:flex;flex-direction:column;gap:16px}.m-wrapper .m-menu-card{background-color:#fff;border-radius:12px;border:1px solid #EBEBEB;overflow:hidden}.m-wrapper .m-menu-card .m-card-header{display:flex;justify-content:space-between;align-items:center;width:100%;padding:16px;cursor:pointer;-webkit-user-select:none;user-select:none;border:none;background:transparent;-webkit-tap-highlight-color:transparent}.m-wrapper .m-menu-card .m-card-header .m-card-header-left{display:flex;align-items:center;gap:16px}.m-wrapper .m-menu-card .m-card-header .m-card-header-left .m-group-icon{font-size:24px;width:24px;height:24px;color:#1f1f1f;object-fit:contain}.m-wrapper .m-menu-card .m-card-header .m-card-header-left .m-group-title{font-size:16px;font-weight:600;color:#1f1f1f}.m-wrapper .m-menu-card .m-card-header .m-expand-icon{color:#1f1f1f;transition:transform .2s ease}.m-wrapper .m-menu-card .m-card-body{display:flex;flex-direction:column;padding-bottom:8px}.m-wrapper .m-menu-card .m-card-body .m-menu-item{display:flex;justify-content:space-between;align-items:center;width:100%;padding:12px 16px 12px 24px;cursor:pointer;border:none;background:transparent;transition:background-color .2s;-webkit-tap-highlight-color:transparent}.m-wrapper .m-menu-card .m-card-body .m-menu-item:active{background-color:#f5f5f5}.m-wrapper .m-menu-card .m-card-body .m-menu-item--indented{padding-left:48px}.m-wrapper .m-menu-card .m-card-body .m-menu-item .m-item-left{display:flex;align-items:center;gap:12px}.m-wrapper .m-menu-card .m-card-body .m-menu-item .m-item-left .m-item-icon{font-size:20px;width:20px;height:20px;color:#8c8c8c}.m-wrapper .m-menu-card .m-card-body .m-menu-item .m-item-left .m-item-icon-img{width:20px;height:20px;object-fit:contain;opacity:.7}.m-wrapper .m-menu-card .m-card-body .m-menu-item .m-item-left .m-item-title{font-size:15px;color:#333}.m-wrapper .m-menu-card .m-card-body .m-menu-item .m-nav-icon{color:#8c8c8c;font-size:20px;width:20px;height:20px}.m-wrapper .m-menu-card .m-card-body .m-sub-group{border-top:1px solid #EBEBEB}.m-wrapper .m-menu-card .m-card-body .m-sub-group:first-child{border-top:none}.m-wrapper .m-menu-card .m-card-body .m-sub-group .m-sub-group-header{display:flex;justify-content:space-between;align-items:center;width:100%;padding:12px 16px 12px 24px;cursor:pointer;border:none;background:#fafafa;-webkit-tap-highlight-color:transparent}.m-wrapper .m-menu-card .m-card-body .m-sub-group .m-sub-group-header:active{background-color:#f0f0f0}.m-wrapper .m-menu-card .m-card-body .m-sub-group .m-sub-group-header .m-item-left{display:flex;align-items:center;gap:12px}.m-wrapper .m-menu-card .m-card-body .m-sub-group .m-sub-group-header .m-item-left .m-item-icon{font-size:20px;width:20px;height:20px;color:#8c8c8c}.m-wrapper .m-menu-card .m-card-body .m-sub-group .m-sub-group-header .m-item-left .m-item-icon-img{width:20px;height:20px;object-fit:contain;opacity:.7}.m-wrapper .m-menu-card .m-card-body .m-sub-group .m-sub-group-header .m-item-left .m-item-title{font-size:15px;font-weight:500;color:#333}.m-wrapper .m-menu-card .m-card-body .m-sub-group .m-sub-group-header .m-expand-icon{color:#8c8c8c;font-size:20px;width:20px;height:20px}\n"] }]
|
|
1253
|
+
}], ctorParameters: () => [] });
|
|
1254
|
+
|
|
1255
|
+
class SidebarMobileV1Component {
|
|
1256
|
+
#layoutStorageService = inject(SdLayoutStorageService);
|
|
1257
|
+
menus = input([]);
|
|
1258
|
+
userInfo = input.required();
|
|
1259
|
+
sidebar = input.required();
|
|
1260
|
+
// Sidebar luôn bắt đầu đóng trên mobile
|
|
1261
|
+
isShowSidebar = signal(false);
|
|
1262
|
+
titleMenuGroup = signal('');
|
|
1263
|
+
constructor() {
|
|
1264
|
+
effect(() => {
|
|
1265
|
+
const isShow = this.isShowSidebar();
|
|
1266
|
+
untracked(() => {
|
|
1267
|
+
this.#layoutStorageService.isShowSidebar.set(isShow);
|
|
1268
|
+
});
|
|
1269
|
+
});
|
|
1270
|
+
}
|
|
1271
|
+
openSidebar = () => {
|
|
1272
|
+
this.isShowSidebar.set(true);
|
|
1273
|
+
};
|
|
1274
|
+
onToggle = (_data) => {
|
|
1275
|
+
this.isShowSidebar.set(false);
|
|
1276
|
+
};
|
|
1277
|
+
onPopupOfSideBarOpened = () => { };
|
|
1278
|
+
onPopupOfSideBarClosed = () => { };
|
|
1279
|
+
onExpandSideBar = () => { };
|
|
1280
|
+
onMouseleaveSideBar = () => { };
|
|
1281
|
+
onTitleMenuGroupChanged = (title) => {
|
|
1282
|
+
this.titleMenuGroup.set(title);
|
|
1283
|
+
};
|
|
1284
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SidebarMobileV1Component, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1285
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: SidebarMobileV1Component, isStandalone: true, selector: "sidebar-mobile-v1", inputs: { menus: { classPropertyName: "menus", publicName: "menus", isSignal: true, isRequired: false, transformFunction: null }, userInfo: { classPropertyName: "userInfo", publicName: "userInfo", isSignal: true, isRequired: true, transformFunction: null }, sidebar: { classPropertyName: "sidebar", publicName: "sidebar", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"c-mobile-layout\">\n <div class=\"c-mobile-topbar\">\n <div class=\"c-topbar-brand\">\n @if (sidebar().logoUrl) {\n <img class=\"c-topbar-logo\" [src]=\"sidebar().logoUrl\" alt=\"logo\" />\n }\n <span class=\"c-topbar-title\">{{ titleMenuGroup() || sidebar().defaultTitle || 'Back Office' }}</span>\n </div>\n <button class=\"c-hamburger-btn\" (click)=\"openSidebar()\">\n <mat-icon>menu</mat-icon>\n </button>\n </div>\n\n <div class=\"c-mobile-content\">\n <ng-content></ng-content>\n </div>\n\n <sd-sidebar-mobile-overlay\n [menus]=\"menus()\"\n [userInfo]=\"userInfo()\"\n [sidebar]=\"sidebar()\"\n [isShowSidebar]=\"isShowSidebar()\"\n (showSideBar)=\"onToggle($event)\"\n (expandSideBar)=\"onExpandSideBar()\"\n (popupUserMenuOpened)=\"onPopupOfSideBarOpened()\"\n (popupUserMenuClosed)=\"onPopupOfSideBarClosed()\"\n (titleMenuGroupChanged)=\"onTitleMenuGroupChanged($event)\">\n </sd-sidebar-mobile-overlay>\n</div>\n", styles: [":host{display:block;height:100vh;position:relative;overflow:hidden}.c-mobile-layout{display:flex;flex-direction:column;height:100%;position:relative}.c-mobile-topbar{display:flex;align-items:center;justify-content:space-between;padding:0 16px;height:56px;background-color:#fff;border-bottom:1px solid #e0e0e0;flex-shrink:0}.c-mobile-topbar .c-topbar-brand{display:flex;align-items:center;gap:10px;overflow:hidden}.c-mobile-topbar .c-topbar-brand .c-topbar-logo{width:28px;height:28px;object-fit:contain;flex-shrink:0}.c-mobile-topbar .c-topbar-brand .c-topbar-title{font-size:16px;font-weight:600;color:#1f1f1f;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.c-mobile-topbar .c-hamburger-btn{display:flex;align-items:center;justify-content:center;background:none;border:none;cursor:pointer;padding:6px;border-radius:50%;color:#333;flex-shrink:0}.c-mobile-topbar .c-hamburger-btn:hover{background-color:#0000000f}.c-mobile-content{flex:1;overflow-y:auto}\n"], dependencies: [{ kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: CommonModule }, { kind: "component", type: SidebarMobileOverlayComponent, selector: "sd-sidebar-mobile-overlay", inputs: ["isShowSidebar", "menus", "userInfo", "sidebar"], outputs: ["showSideBar", "expandSideBar", "popupUserMenuOpened", "popupUserMenuClosed", "titleMenuGroupChanged"] }] });
|
|
1286
|
+
}
|
|
1287
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SidebarMobileV1Component, decorators: [{
|
|
1288
|
+
type: Component,
|
|
1289
|
+
args: [{ selector: 'sidebar-mobile-v1', imports: [MatIconModule, CommonModule, SidebarMobileOverlayComponent], standalone: true, template: "<div class=\"c-mobile-layout\">\n <div class=\"c-mobile-topbar\">\n <div class=\"c-topbar-brand\">\n @if (sidebar().logoUrl) {\n <img class=\"c-topbar-logo\" [src]=\"sidebar().logoUrl\" alt=\"logo\" />\n }\n <span class=\"c-topbar-title\">{{ titleMenuGroup() || sidebar().defaultTitle || 'Back Office' }}</span>\n </div>\n <button class=\"c-hamburger-btn\" (click)=\"openSidebar()\">\n <mat-icon>menu</mat-icon>\n </button>\n </div>\n\n <div class=\"c-mobile-content\">\n <ng-content></ng-content>\n </div>\n\n <sd-sidebar-mobile-overlay\n [menus]=\"menus()\"\n [userInfo]=\"userInfo()\"\n [sidebar]=\"sidebar()\"\n [isShowSidebar]=\"isShowSidebar()\"\n (showSideBar)=\"onToggle($event)\"\n (expandSideBar)=\"onExpandSideBar()\"\n (popupUserMenuOpened)=\"onPopupOfSideBarOpened()\"\n (popupUserMenuClosed)=\"onPopupOfSideBarClosed()\"\n (titleMenuGroupChanged)=\"onTitleMenuGroupChanged($event)\">\n </sd-sidebar-mobile-overlay>\n</div>\n", styles: [":host{display:block;height:100vh;position:relative;overflow:hidden}.c-mobile-layout{display:flex;flex-direction:column;height:100%;position:relative}.c-mobile-topbar{display:flex;align-items:center;justify-content:space-between;padding:0 16px;height:56px;background-color:#fff;border-bottom:1px solid #e0e0e0;flex-shrink:0}.c-mobile-topbar .c-topbar-brand{display:flex;align-items:center;gap:10px;overflow:hidden}.c-mobile-topbar .c-topbar-brand .c-topbar-logo{width:28px;height:28px;object-fit:contain;flex-shrink:0}.c-mobile-topbar .c-topbar-brand .c-topbar-title{font-size:16px;font-weight:600;color:#1f1f1f;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.c-mobile-topbar .c-hamburger-btn{display:flex;align-items:center;justify-content:center;background:none;border:none;cursor:pointer;padding:6px;border-radius:50%;color:#333;flex-shrink:0}.c-mobile-topbar .c-hamburger-btn:hover{background-color:#0000000f}.c-mobile-content{flex:1;overflow-y:auto}\n"] }]
|
|
1290
|
+
}], ctorParameters: () => [] });
|
|
1291
|
+
|
|
1292
|
+
class SdLayoutComponent {
|
|
1293
|
+
// ==========================================
|
|
1294
|
+
// INJECT SERVICES
|
|
1295
|
+
// ==========================================
|
|
1296
|
+
#menuPipe = inject(MenuPipe);
|
|
1297
|
+
#layoutService = inject(SdLayoutService);
|
|
1298
|
+
// ==========================================
|
|
1299
|
+
// SIGNAL INPUTS
|
|
1300
|
+
// ==========================================
|
|
1301
|
+
menusInput = input([], { alias: 'menus' });
|
|
1302
|
+
menus = computed(() => this.#menuPipe.transform(this.menusInput() || []));
|
|
1303
|
+
// ==========================================
|
|
1304
|
+
// CONSUME SHARED STATE
|
|
1305
|
+
// ==========================================
|
|
1306
|
+
userInfo = this.#layoutService.userInfo;
|
|
1307
|
+
sidebar = this.#layoutService.sidebar;
|
|
1308
|
+
isMobileOrTablet = signal(BrowserUtilities.isMobile());
|
|
1309
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1310
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: SdLayoutComponent, isStandalone: true, selector: "sd-layout", inputs: { menusInput: { classPropertyName: "menusInput", publicName: "menus", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<ng-template #projectedContent>\n <ng-content></ng-content>\n</ng-template>\n\n@let _userInfo = userInfo();\n@let _sidebar = sidebar();\n\n@if (_userInfo && _sidebar?.version === 1) {\n @if (!isMobileOrTablet()) {\n <sidebar-v1 [menus]=\"menus()\" [userInfo]=\"_userInfo\" [sidebar]=\"_sidebar!\">\n <ng-container [ngTemplateOutlet]=\"projectedContent\"></ng-container>\n </sidebar-v1>\n } @else {\n <sidebar-mobile-v1 [menus]=\"menus()\" [userInfo]=\"_userInfo\" [sidebar]=\"_sidebar!\">\n <ng-container [ngTemplateOutlet]=\"projectedContent\"></ng-container>\n </sidebar-mobile-v1>\n }\n}\n", styles: [""], dependencies: [{ kind: "component", type: SidebarV1Component, selector: "sidebar-v1", inputs: ["menus", "userInfo", "sidebar"] }, { kind: "component", type: SidebarMobileV1Component, selector: "sidebar-mobile-v1", inputs: ["menus", "userInfo", "sidebar"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
|
|
1311
|
+
}
|
|
1312
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdLayoutComponent, decorators: [{
|
|
1313
|
+
type: Component,
|
|
1314
|
+
args: [{ selector: 'sd-layout', imports: [SidebarV1Component, SidebarMobileV1Component, NgTemplateOutlet], standalone: true, template: "<ng-template #projectedContent>\n <ng-content></ng-content>\n</ng-template>\n\n@let _userInfo = userInfo();\n@let _sidebar = sidebar();\n\n@if (_userInfo && _sidebar?.version === 1) {\n @if (!isMobileOrTablet()) {\n <sidebar-v1 [menus]=\"menus()\" [userInfo]=\"_userInfo\" [sidebar]=\"_sidebar!\">\n <ng-container [ngTemplateOutlet]=\"projectedContent\"></ng-container>\n </sidebar-v1>\n } @else {\n <sidebar-mobile-v1 [menus]=\"menus()\" [userInfo]=\"_userInfo\" [sidebar]=\"_sidebar!\">\n <ng-container [ngTemplateOutlet]=\"projectedContent\"></ng-container>\n </sidebar-mobile-v1>\n }\n}\n" }]
|
|
1315
|
+
}] });
|
|
1316
|
+
|
|
1317
|
+
// End
|
|
1318
|
+
let HomePageComponent = class HomePageComponent {
|
|
1319
|
+
// ==========================================
|
|
1320
|
+
// INJECT SERVICES (Modern Angular)
|
|
1321
|
+
// ==========================================
|
|
1322
|
+
#layoutService = inject(SdLayoutService);
|
|
1323
|
+
#i18n = inject(I18nService);
|
|
1324
|
+
// Map Language code → BCP 47 locale tag dùng cho Intl date formatting
|
|
1325
|
+
// WHY: must be declared before todayInfo — field init runs top-to-bottom; #getTodayInfo reads #localeMap.
|
|
1326
|
+
#localeMap = {
|
|
1327
|
+
vi: 'vi-VN',
|
|
1328
|
+
en: 'en-US',
|
|
1329
|
+
ja: 'ja-JP',
|
|
1330
|
+
ko: 'ko-KR',
|
|
1331
|
+
zh: 'zh-CN',
|
|
1332
|
+
};
|
|
1333
|
+
// ==========================================
|
|
1334
|
+
// SIGNALS (STATE)
|
|
1335
|
+
// ==========================================
|
|
1336
|
+
// Lấy snapshot một lần lúc khởi tạo và đưa vào signal
|
|
1337
|
+
todayInfo = signal(this.#getTodayInfo(new Date()));
|
|
1338
|
+
userInfo = this.#layoutService.userInfo;
|
|
1339
|
+
// WHY: static data, không cần signal. `storage` + `schema` thay cho `database` + `account_tree`
|
|
1340
|
+
// để đảm bảo render trên mọi version của Material Icons mặc định.
|
|
1341
|
+
features = [
|
|
1342
|
+
{ icon: 'storage', key: 'core.module.layout.home.feature.data', area: 'data' },
|
|
1343
|
+
{ icon: 'insights', key: 'core.module.layout.home.feature.reports', area: 'report' },
|
|
1344
|
+
{ icon: 'group', key: 'core.module.layout.home.feature.users', area: 'users' },
|
|
1345
|
+
{ icon: 'schema', key: 'core.module.layout.home.feature.workflow', area: 'flow' },
|
|
1346
|
+
{ icon: 'verified_user', key: 'core.module.layout.home.feature.audit', area: 'audit' },
|
|
1347
|
+
{ icon: 'hub', key: 'core.module.layout.home.feature.integration', area: 'integ' },
|
|
1348
|
+
];
|
|
1349
|
+
// ==========================================
|
|
1350
|
+
// PRIVATE METHODS
|
|
1351
|
+
// ==========================================
|
|
1352
|
+
#getTimezone() {
|
|
1353
|
+
const now = new Date();
|
|
1354
|
+
const timezoneOffset = now.getTimezoneOffset();
|
|
1355
|
+
const offsetHours = -timezoneOffset / 60;
|
|
1356
|
+
const sign = offsetHours >= 0 ? '+' : '';
|
|
1357
|
+
const simpleGmtString = `GMT${sign}${offsetHours}`;
|
|
1358
|
+
return simpleGmtString;
|
|
1359
|
+
}
|
|
1360
|
+
#getTodayInfo(date) {
|
|
1361
|
+
// WHY: weekday names i18n hóa qua key core.module.layout.weekday.<0..6>
|
|
1362
|
+
const weekday = this.#i18n.t(`core.module.layout.weekday.${date.getDay()}`);
|
|
1363
|
+
// WHY: dùng locale theo ngôn ngữ hiện tại để định dạng số (dd/mm/yyyy vs mm/dd/yyyy ...)
|
|
1364
|
+
const locale = this.#localeMap[this.#i18n.language()] ?? 'vi-VN';
|
|
1365
|
+
const dateStr = date.toLocaleDateString(locale, {
|
|
1366
|
+
day: '2-digit',
|
|
1367
|
+
month: '2-digit',
|
|
1368
|
+
year: 'numeric',
|
|
1369
|
+
});
|
|
1370
|
+
const formatted = this.#i18n.t('core.module.layout.today-info.format', { weekday, date: dateStr });
|
|
1371
|
+
return `${formatted} (${this.#getTimezone()})`;
|
|
1372
|
+
}
|
|
1373
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HomePageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1374
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.21", type: HomePageComponent, isStandalone: true, selector: "app-home-page", ngImport: i0, template: "@let _userInfo = userInfo();\n<sd-page>\n <div class=\"d-flex flex-column\" headerLeft>\n <div class=\"font-weight-medium fs-20\">\n {{ 'core.module.layout.greeting.hello' | translate: { name: _userInfo?.fullName ?? _userInfo?.email ?? _userInfo?.username ?? '' } }}\n </div>\n <span class=\"T12R text-secondary\">{{ todayInfo() }}</span>\n </div>\n\n <div class=\"wrapper\">\n <div class=\"bento\">\n <!-- Hero -->\n <div class=\"card hero-card\">\n <div class=\"hero-ring ring-3\"></div>\n <div class=\"hero-ring ring-2\"></div>\n <div class=\"hero-ring ring-1\"></div>\n <div class=\"hero-core\">\n <mat-icon class=\"hero-icon\">space_dashboard</mat-icon>\n </div>\n <div class=\"hero-decoration\">\n <span class=\"dot d1\"></span>\n <span class=\"dot d2\"></span>\n <span class=\"dot d3\"></span>\n </div>\n </div>\n\n <!-- Features -->\n @for (feature of features; track feature.key; let i = $index) {\n <div\n class=\"card feature-card\"\n [class.feature-wide]=\"feature.area === 'audit' || feature.area === 'integ'\"\n [style.gridArea]=\"feature.area\"\n [style.animation-delay.ms]=\"(i + 1) * 80\"\n >\n <div class=\"feature-accent\"></div>\n <div class=\"feature-content\">\n <div class=\"feature-icon-wrap\">\n <mat-icon class=\"feature-icon\">{{ feature.icon }}</mat-icon>\n </div>\n <span class=\"feature-label\">{{ feature.key | translate }}</span>\n </div>\n </div>\n }\n </div>\n </div>\n</sd-page>\n", styles: [":host{display:contents}.wrapper{display:flex;align-items:center;justify-content:center;padding:32px 24px;height:100%;width:100%;background:radial-gradient(circle at 15% 25%,color-mix(in srgb,var(--mat-sys-primary, #1f49bf) 14%,transparent),transparent 55%),radial-gradient(circle at 85% 75%,color-mix(in srgb,var(--mat-sys-primary, #1f49bf) 10%,transparent),transparent 55%),linear-gradient(135deg,#fafbfc,#f4f6fa);overflow:auto}.bento{display:grid;width:100%;max-width:1080px;gap:16px;grid-template-columns:repeat(4,1fr);grid-template-rows:repeat(3,minmax(140px,1fr));grid-template-areas:\"hero hero data report\" \"hero hero users flow\" \"audit audit integ integ\"}.card{position:relative;background:#fff;border:1px solid rgba(0,0,0,.06);border-radius:20px;overflow:hidden;opacity:0;transform:translateY(8px);animation:card-in .5s ease-out forwards;transition:transform .3s ease,box-shadow .3s ease}.card:hover{transform:translateY(-4px);box-shadow:0 16px 40px color-mix(in srgb,var(--mat-sys-primary, #1f49bf) 18%,transparent),0 4px 12px #0000000f}.hero-card{grid-area:hero;display:flex;align-items:center;justify-content:center;background:radial-gradient(circle at 30% 30%,color-mix(in srgb,var(--mat-sys-primary, #1f49bf) 18%,white),#fff 60%),#fff;border:1px solid color-mix(in srgb,var(--mat-sys-primary, #1f49bf) 15%,transparent)}.hero-card .hero-ring{position:absolute;border-radius:50%;border:1px solid color-mix(in srgb,var(--mat-sys-primary, #1f49bf) 25%,transparent);animation:hero-pulse 3s ease-in-out infinite;pointer-events:none}.hero-card .hero-ring.ring-1{inset:calc(50% - 70px);animation-delay:0s}.hero-card .hero-ring.ring-2{inset:calc(50% - 105px);animation-delay:.6s}.hero-card .hero-ring.ring-3{inset:calc(50% - 140px);animation-delay:1.2s}.hero-card .hero-core{position:relative;z-index:1;width:140px;height:140px;border-radius:50%;display:flex;align-items:center;justify-content:center;background:radial-gradient(circle,color-mix(in srgb,var(--mat-sys-primary, #1f49bf) 22%,white),#fff);box-shadow:0 0 60px color-mix(in srgb,var(--mat-sys-primary, #1f49bf) 30%,transparent),0 10px 30px color-mix(in srgb,var(--mat-sys-primary, #1f49bf) 20%,transparent)}.hero-card .hero-icon{font-size:72px;width:72px;height:72px;color:var(--mat-sys-primary, #1f49bf)}.hero-card .hero-decoration{position:absolute;inset:0;pointer-events:none}.hero-card .hero-decoration .dot{position:absolute;width:8px;height:8px;border-radius:50%;background:color-mix(in srgb,var(--mat-sys-primary, #1f49bf) 50%,transparent);animation:dot-float 4s ease-in-out infinite}.hero-card .hero-decoration .d1{top:16%;left:12%;animation-delay:0s}.hero-card .hero-decoration .d2{bottom:20%;right:14%;animation-delay:1s}.hero-card .hero-decoration .d3{top:60%;left:80%;animation-delay:2s;width:5px;height:5px}.feature-card{display:flex;align-items:stretch;cursor:default}.feature-card .feature-accent{position:absolute;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,color-mix(in srgb,var(--mat-sys-primary, #1f49bf) 60%,transparent),var(--mat-sys-primary, #1f49bf),color-mix(in srgb,var(--mat-sys-primary, #1f49bf) 60%,transparent))}.feature-card .feature-content{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:24px 16px 18px;gap:10px}.feature-card .feature-icon-wrap{width:56px;height:56px;border-radius:50%;background:color-mix(in srgb,var(--mat-sys-primary, #1f49bf) 12%,white);display:flex;align-items:center;justify-content:center}.feature-card .feature-icon{font-size:28px;width:28px;height:28px;color:var(--mat-sys-primary, #1f49bf)}.feature-card .feature-label{font-size:14px;font-weight:500;text-align:center;color:#000000c7;line-height:20px}.feature-card.feature-wide .feature-content{flex-direction:row;justify-content:flex-start;padding:18px 24px;gap:18px}.feature-card.feature-wide .feature-icon-wrap{width:64px;height:64px}.feature-card.feature-wide .feature-icon{font-size:32px;width:32px;height:32px}.feature-card.feature-wide .feature-label{text-align:left;font-size:16px}@keyframes card-in{to{opacity:1;transform:translateY(0)}}@keyframes hero-pulse{0%,to{transform:scale(1);opacity:.7}50%{transform:scale(1.06);opacity:.3}}@keyframes dot-float{0%,to{transform:translateY(0);opacity:.8}50%{transform:translateY(-8px);opacity:.4}}@media(max-width:1024px){.bento{grid-template-columns:repeat(3,1fr);grid-template-rows:repeat(4,minmax(120px,1fr));grid-template-areas:\"hero hero data\" \"hero hero report\" \"users flow audit\" \"integ integ integ\"}.hero-card .hero-core{width:120px;height:120px}.hero-card .hero-icon{font-size:60px;width:60px;height:60px}}@media(max-width:640px){.wrapper{padding:16px 12px}.bento{grid-template-columns:1fr;grid-template-rows:auto;grid-template-areas:\"hero\" \"data\" \"report\" \"users\" \"flow\" \"audit\" \"integ\";gap:12px}.hero-card{min-height:220px}.hero-card .hero-core{width:100px;height:100px}.hero-card .hero-icon{font-size:52px;width:52px;height:52px}}@media(prefers-reduced-motion:reduce){.card{animation:none;opacity:1;transform:none}.hero-card .hero-ring{animation:none;opacity:.4}.hero-card .hero-decoration .dot{animation:none}}\n"], dependencies: [{ kind: "component", type: SdPageComponent, selector: "sd-page", inputs: ["title", "description", "noHeader"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1$3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }] });
|
|
1375
|
+
};
|
|
1376
|
+
HomePageComponent = __decorate([
|
|
1377
|
+
SdTabComponent({
|
|
1378
|
+
component: HomePageComponent,
|
|
1379
|
+
// WHY: decorator chạy trước Angular DI, nên không inject được I18nService.
|
|
1380
|
+
// Đọc ngôn ngữ hiện tại trực tiếp từ localStorage + I18N_MESSAGES để có giá trị đã dịch.
|
|
1381
|
+
name: () => {
|
|
1382
|
+
const lang = (() => {
|
|
1383
|
+
try {
|
|
1384
|
+
const stored = localStorage.getItem(I18N_STORAGE_KEY);
|
|
1385
|
+
if (stored)
|
|
1386
|
+
return stored;
|
|
1387
|
+
}
|
|
1388
|
+
catch { /* ignore */ }
|
|
1389
|
+
return 'vi';
|
|
1390
|
+
})();
|
|
1391
|
+
return I18N_MESSAGES[lang]?.['core.module.layout.home.tab-name'] ?? I18N_MESSAGES.vi['core.module.layout.home.tab-name'];
|
|
1392
|
+
},
|
|
1393
|
+
icon: 'home',
|
|
1394
|
+
color: 'primary',
|
|
1395
|
+
})
|
|
1396
|
+
], HomePageComponent);
|
|
1397
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HomePageComponent, decorators: [{
|
|
1398
|
+
type: Component,
|
|
1399
|
+
args: [{ selector: 'app-home-page', imports: [SdPageComponent, TranslatePipe, MatIconModule], standalone: true, template: "@let _userInfo = userInfo();\n<sd-page>\n <div class=\"d-flex flex-column\" headerLeft>\n <div class=\"font-weight-medium fs-20\">\n {{ 'core.module.layout.greeting.hello' | translate: { name: _userInfo?.fullName ?? _userInfo?.email ?? _userInfo?.username ?? '' } }}\n </div>\n <span class=\"T12R text-secondary\">{{ todayInfo() }}</span>\n </div>\n\n <div class=\"wrapper\">\n <div class=\"bento\">\n <!-- Hero -->\n <div class=\"card hero-card\">\n <div class=\"hero-ring ring-3\"></div>\n <div class=\"hero-ring ring-2\"></div>\n <div class=\"hero-ring ring-1\"></div>\n <div class=\"hero-core\">\n <mat-icon class=\"hero-icon\">space_dashboard</mat-icon>\n </div>\n <div class=\"hero-decoration\">\n <span class=\"dot d1\"></span>\n <span class=\"dot d2\"></span>\n <span class=\"dot d3\"></span>\n </div>\n </div>\n\n <!-- Features -->\n @for (feature of features; track feature.key; let i = $index) {\n <div\n class=\"card feature-card\"\n [class.feature-wide]=\"feature.area === 'audit' || feature.area === 'integ'\"\n [style.gridArea]=\"feature.area\"\n [style.animation-delay.ms]=\"(i + 1) * 80\"\n >\n <div class=\"feature-accent\"></div>\n <div class=\"feature-content\">\n <div class=\"feature-icon-wrap\">\n <mat-icon class=\"feature-icon\">{{ feature.icon }}</mat-icon>\n </div>\n <span class=\"feature-label\">{{ feature.key | translate }}</span>\n </div>\n </div>\n }\n </div>\n </div>\n</sd-page>\n", styles: [":host{display:contents}.wrapper{display:flex;align-items:center;justify-content:center;padding:32px 24px;height:100%;width:100%;background:radial-gradient(circle at 15% 25%,color-mix(in srgb,var(--mat-sys-primary, #1f49bf) 14%,transparent),transparent 55%),radial-gradient(circle at 85% 75%,color-mix(in srgb,var(--mat-sys-primary, #1f49bf) 10%,transparent),transparent 55%),linear-gradient(135deg,#fafbfc,#f4f6fa);overflow:auto}.bento{display:grid;width:100%;max-width:1080px;gap:16px;grid-template-columns:repeat(4,1fr);grid-template-rows:repeat(3,minmax(140px,1fr));grid-template-areas:\"hero hero data report\" \"hero hero users flow\" \"audit audit integ integ\"}.card{position:relative;background:#fff;border:1px solid rgba(0,0,0,.06);border-radius:20px;overflow:hidden;opacity:0;transform:translateY(8px);animation:card-in .5s ease-out forwards;transition:transform .3s ease,box-shadow .3s ease}.card:hover{transform:translateY(-4px);box-shadow:0 16px 40px color-mix(in srgb,var(--mat-sys-primary, #1f49bf) 18%,transparent),0 4px 12px #0000000f}.hero-card{grid-area:hero;display:flex;align-items:center;justify-content:center;background:radial-gradient(circle at 30% 30%,color-mix(in srgb,var(--mat-sys-primary, #1f49bf) 18%,white),#fff 60%),#fff;border:1px solid color-mix(in srgb,var(--mat-sys-primary, #1f49bf) 15%,transparent)}.hero-card .hero-ring{position:absolute;border-radius:50%;border:1px solid color-mix(in srgb,var(--mat-sys-primary, #1f49bf) 25%,transparent);animation:hero-pulse 3s ease-in-out infinite;pointer-events:none}.hero-card .hero-ring.ring-1{inset:calc(50% - 70px);animation-delay:0s}.hero-card .hero-ring.ring-2{inset:calc(50% - 105px);animation-delay:.6s}.hero-card .hero-ring.ring-3{inset:calc(50% - 140px);animation-delay:1.2s}.hero-card .hero-core{position:relative;z-index:1;width:140px;height:140px;border-radius:50%;display:flex;align-items:center;justify-content:center;background:radial-gradient(circle,color-mix(in srgb,var(--mat-sys-primary, #1f49bf) 22%,white),#fff);box-shadow:0 0 60px color-mix(in srgb,var(--mat-sys-primary, #1f49bf) 30%,transparent),0 10px 30px color-mix(in srgb,var(--mat-sys-primary, #1f49bf) 20%,transparent)}.hero-card .hero-icon{font-size:72px;width:72px;height:72px;color:var(--mat-sys-primary, #1f49bf)}.hero-card .hero-decoration{position:absolute;inset:0;pointer-events:none}.hero-card .hero-decoration .dot{position:absolute;width:8px;height:8px;border-radius:50%;background:color-mix(in srgb,var(--mat-sys-primary, #1f49bf) 50%,transparent);animation:dot-float 4s ease-in-out infinite}.hero-card .hero-decoration .d1{top:16%;left:12%;animation-delay:0s}.hero-card .hero-decoration .d2{bottom:20%;right:14%;animation-delay:1s}.hero-card .hero-decoration .d3{top:60%;left:80%;animation-delay:2s;width:5px;height:5px}.feature-card{display:flex;align-items:stretch;cursor:default}.feature-card .feature-accent{position:absolute;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,color-mix(in srgb,var(--mat-sys-primary, #1f49bf) 60%,transparent),var(--mat-sys-primary, #1f49bf),color-mix(in srgb,var(--mat-sys-primary, #1f49bf) 60%,transparent))}.feature-card .feature-content{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:24px 16px 18px;gap:10px}.feature-card .feature-icon-wrap{width:56px;height:56px;border-radius:50%;background:color-mix(in srgb,var(--mat-sys-primary, #1f49bf) 12%,white);display:flex;align-items:center;justify-content:center}.feature-card .feature-icon{font-size:28px;width:28px;height:28px;color:var(--mat-sys-primary, #1f49bf)}.feature-card .feature-label{font-size:14px;font-weight:500;text-align:center;color:#000000c7;line-height:20px}.feature-card.feature-wide .feature-content{flex-direction:row;justify-content:flex-start;padding:18px 24px;gap:18px}.feature-card.feature-wide .feature-icon-wrap{width:64px;height:64px}.feature-card.feature-wide .feature-icon{font-size:32px;width:32px;height:32px}.feature-card.feature-wide .feature-label{text-align:left;font-size:16px}@keyframes card-in{to{opacity:1;transform:translateY(0)}}@keyframes hero-pulse{0%,to{transform:scale(1);opacity:.7}50%{transform:scale(1.06);opacity:.3}}@keyframes dot-float{0%,to{transform:translateY(0);opacity:.8}50%{transform:translateY(-8px);opacity:.4}}@media(max-width:1024px){.bento{grid-template-columns:repeat(3,1fr);grid-template-rows:repeat(4,minmax(120px,1fr));grid-template-areas:\"hero hero data\" \"hero hero report\" \"users flow audit\" \"integ integ integ\"}.hero-card .hero-core{width:120px;height:120px}.hero-card .hero-icon{font-size:60px;width:60px;height:60px}}@media(max-width:640px){.wrapper{padding:16px 12px}.bento{grid-template-columns:1fr;grid-template-rows:auto;grid-template-areas:\"hero\" \"data\" \"report\" \"users\" \"flow\" \"audit\" \"integ\";gap:12px}.hero-card{min-height:220px}.hero-card .hero-core{width:100px;height:100px}.hero-card .hero-icon{font-size:52px;width:52px;height:52px}}@media(prefers-reduced-motion:reduce){.card{animation:none;opacity:1;transform:none}.hero-card .hero-ring{animation:none;opacity:.4}.hero-card .hero-decoration .dot{animation:none}}\n"] }]
|
|
1400
|
+
}] });
|
|
1401
|
+
|
|
1402
|
+
class HomeRedirectGuard {
|
|
1403
|
+
router;
|
|
1404
|
+
layoutConfiguration;
|
|
1405
|
+
constructor(router, layoutConfiguration) {
|
|
1406
|
+
this.router = router;
|
|
1407
|
+
this.layoutConfiguration = layoutConfiguration;
|
|
1408
|
+
}
|
|
1409
|
+
async canActivate() {
|
|
1410
|
+
const homeUrl = this.layoutConfiguration?.homeUrl;
|
|
1411
|
+
if (homeUrl) {
|
|
1412
|
+
// Nếu có config homeUrl, tạo một UrlTree để redirect
|
|
1413
|
+
// Đây là cách redirect chính thống từ trong guard
|
|
1414
|
+
return this.router.createUrlTree([homeUrl]);
|
|
1415
|
+
}
|
|
1416
|
+
// Nếu không có homeUrl, cho phép kích hoạt route
|
|
1417
|
+
return true;
|
|
1418
|
+
}
|
|
1419
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HomeRedirectGuard, deps: [{ token: i1$6.Router }, { token: SD_LAYOUT_CONFIGURATION }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1420
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HomeRedirectGuard, providedIn: 'root' });
|
|
1421
|
+
}
|
|
1422
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HomeRedirectGuard, decorators: [{
|
|
1423
|
+
type: Injectable,
|
|
1424
|
+
args: [{
|
|
1425
|
+
providedIn: 'root',
|
|
1426
|
+
}]
|
|
1427
|
+
}], ctorParameters: () => [{ type: i1$6.Router }, { type: undefined, decorators: [{
|
|
1428
|
+
type: Inject,
|
|
1429
|
+
args: [SD_LAYOUT_CONFIGURATION]
|
|
1430
|
+
}] }] });
|
|
1431
|
+
|
|
1432
|
+
const routes = [
|
|
1433
|
+
{
|
|
1434
|
+
path: '',
|
|
1435
|
+
canActivate: [HomeRedirectGuard],
|
|
1436
|
+
component: HomePageComponent,
|
|
1437
|
+
},
|
|
1438
|
+
];
|
|
1439
|
+
class HomeRoutingModule {
|
|
1440
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HomeRoutingModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
1441
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.21", ngImport: i0, type: HomeRoutingModule, imports: [i1$6.RouterModule], exports: [RouterModule] });
|
|
1442
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HomeRoutingModule, imports: [RouterModule.forChild(routes), RouterModule] });
|
|
1443
|
+
}
|
|
1444
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HomeRoutingModule, decorators: [{
|
|
1445
|
+
type: NgModule,
|
|
1446
|
+
args: [{
|
|
1447
|
+
imports: [RouterModule.forChild(routes)],
|
|
1448
|
+
exports: [RouterModule],
|
|
1449
|
+
}]
|
|
1450
|
+
}] });
|
|
1451
|
+
|
|
1452
|
+
class HomeModule {
|
|
1453
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HomeModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
1454
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.21", ngImport: i0, type: HomeModule, imports: [CommonModule, HomeRoutingModule] });
|
|
1455
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HomeModule, imports: [CommonModule, HomeRoutingModule] });
|
|
1456
|
+
}
|
|
1457
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HomeModule, decorators: [{
|
|
1458
|
+
type: NgModule,
|
|
1459
|
+
args: [{
|
|
1460
|
+
declarations: [],
|
|
1461
|
+
imports: [CommonModule, HomeRoutingModule],
|
|
1462
|
+
}]
|
|
1463
|
+
}] });
|
|
1464
|
+
|
|
1465
|
+
var index$2 = /*#__PURE__*/Object.freeze({
|
|
1466
|
+
__proto__: null,
|
|
1467
|
+
HomeModule: HomeModule
|
|
1468
|
+
});
|
|
1469
|
+
|
|
1470
|
+
// End
|
|
1471
|
+
let RootComponent$1 = class RootComponent {
|
|
1472
|
+
// ==========================================
|
|
1473
|
+
// INJECT SERVICES (Modern Angular)
|
|
1474
|
+
// ==========================================
|
|
1475
|
+
#route = inject(ActivatedRoute);
|
|
1476
|
+
#layoutService = inject(SdLayoutService);
|
|
1477
|
+
#i18n = inject(I18nService);
|
|
1478
|
+
// ==========================================
|
|
1479
|
+
// SIGNALS (STATE)
|
|
1480
|
+
// ==========================================
|
|
1481
|
+
// Lấy snapshot một lần lúc khởi tạo và đưa vào signal
|
|
1482
|
+
url = signal(this.#route.snapshot.queryParams?.['url'] || '');
|
|
1483
|
+
todayInfo = signal(this.#getTodayInfo(new Date()));
|
|
1484
|
+
userInfo = this.#layoutService.userInfo;
|
|
1485
|
+
// ==========================================
|
|
1486
|
+
// PRIVATE METHODS
|
|
1487
|
+
// ==========================================
|
|
1488
|
+
#getTodayInfo(date) {
|
|
1489
|
+
// WHY: weekday names i18n hóa qua key core.module.layout.weekday.<0..6>
|
|
1490
|
+
const weekday = this.#i18n.t(`core.module.layout.weekday.${date.getDay()}`);
|
|
1491
|
+
const dateStr = date.toLocaleDateString('vi-VN', {
|
|
1492
|
+
day: '2-digit',
|
|
1493
|
+
month: '2-digit',
|
|
1494
|
+
year: 'numeric',
|
|
1495
|
+
});
|
|
1496
|
+
return this.#i18n.t('core.module.layout.today-info.format', { weekday, date: dateStr });
|
|
1497
|
+
}
|
|
1498
|
+
// ==========================================
|
|
1499
|
+
// PUBLIC METHODS
|
|
1500
|
+
// ==========================================
|
|
1501
|
+
reload() {
|
|
1502
|
+
window.location.href = '';
|
|
1503
|
+
}
|
|
1504
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: RootComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1505
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.21", type: RootComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: "@let _userInfo = userInfo();\n<sd-page>\n <div class=\"d-flex flex-column\" headerLeft>\n <div class=\"font-weight-medium fs-20\">{{ 'core.module.layout.greeting.hello' | translate: { name: _userInfo?.fullName ?? _userInfo?.email ?? _userInfo?.username ?? '' } }}</div>\n <span class=\"T12R text-secondary\">{{ todayInfo() }}</span>\n </div>\n\n <div class=\"h-full d-flex flex-column align-items-center\">\n <div class=\"h-full d-flex flex-column align-items-center justify-content-center text-center wrapper\">\n <img alt=\"not-found\" class=\"sd-image-not-found\" />\n <span class=\"T16M mt-24\">{{ 'core.module.layout.not-found.title' | translate }}</span>\n <span class=\"T16R text-secondary mt-4\">\n {{ 'core.module.layout.not-found.message' | translate }}\n </span>\n <sd-button class=\"mt-16\" type=\"fill\" color=\"primary\" (click)=\"reload()\" [title]=\"'core.module.layout.not-found.back' | translate\" prefixIcon=\"arrow_back\"> </sd-button>\n </div>\n </div>\n</sd-page>\n", styles: [".wrapper{width:300px}\n"], dependencies: [{ kind: "component", type: SdButton, selector: "sd-button", inputs: ["autoId", "type", "color", "size", "fontSet", "title", "width", "tooltip", "prefixIcon", "suffixIcon", "disabled", "loading", "block", "htmlType"], outputs: ["click"] }, { kind: "component", type: SdPageComponent, selector: "sd-page", inputs: ["title", "description", "noHeader"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
|
|
1506
|
+
};
|
|
1507
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: RootComponent$1, decorators: [{
|
|
1508
|
+
type: Component,
|
|
1509
|
+
args: [{ imports: [SdButton, SdPageComponent, TranslatePipe], template: "@let _userInfo = userInfo();\n<sd-page>\n <div class=\"d-flex flex-column\" headerLeft>\n <div class=\"font-weight-medium fs-20\">{{ 'core.module.layout.greeting.hello' | translate: { name: _userInfo?.fullName ?? _userInfo?.email ?? _userInfo?.username ?? '' } }}</div>\n <span class=\"T12R text-secondary\">{{ todayInfo() }}</span>\n </div>\n\n <div class=\"h-full d-flex flex-column align-items-center\">\n <div class=\"h-full d-flex flex-column align-items-center justify-content-center text-center wrapper\">\n <img alt=\"not-found\" class=\"sd-image-not-found\" />\n <span class=\"T16M mt-24\">{{ 'core.module.layout.not-found.title' | translate }}</span>\n <span class=\"T16R text-secondary mt-4\">\n {{ 'core.module.layout.not-found.message' | translate }}\n </span>\n <sd-button class=\"mt-16\" type=\"fill\" color=\"primary\" (click)=\"reload()\" [title]=\"'core.module.layout.not-found.back' | translate\" prefixIcon=\"arrow_back\"> </sd-button>\n </div>\n </div>\n</sd-page>\n", styles: [".wrapper{width:300px}\n"] }]
|
|
1510
|
+
}] });
|
|
1511
|
+
|
|
1512
|
+
const Routes$2 = [{ path: '', component: RootComponent$1 }];
|
|
1513
|
+
|
|
1514
|
+
class NotFoundModule {
|
|
1515
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: NotFoundModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
1516
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.21", ngImport: i0, type: NotFoundModule, imports: [CommonModule, i1$6.RouterModule] });
|
|
1517
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: NotFoundModule, imports: [CommonModule, RouterModule.forChild(Routes$2)] });
|
|
1518
|
+
}
|
|
1519
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: NotFoundModule, decorators: [{
|
|
1520
|
+
type: NgModule,
|
|
1521
|
+
args: [{
|
|
1522
|
+
imports: [CommonModule, RouterModule.forChild(Routes$2)],
|
|
1523
|
+
exports: [],
|
|
1524
|
+
}]
|
|
1525
|
+
}] });
|
|
1526
|
+
|
|
1527
|
+
var index$1 = /*#__PURE__*/Object.freeze({
|
|
1528
|
+
__proto__: null,
|
|
1529
|
+
NotFoundModule: NotFoundModule
|
|
1530
|
+
});
|
|
1531
|
+
|
|
1532
|
+
// End
|
|
1533
|
+
class RootComponent {
|
|
1534
|
+
// ==========================================
|
|
1535
|
+
// INJECT SERVICES (Modern Angular)
|
|
1536
|
+
// ==========================================
|
|
1537
|
+
#route = inject(ActivatedRoute);
|
|
1538
|
+
#layoutService = inject(SdLayoutService);
|
|
1539
|
+
#i18n = inject(I18nService);
|
|
1540
|
+
// ==========================================
|
|
1541
|
+
// SIGNALS (STATE)
|
|
1542
|
+
// ==========================================
|
|
1543
|
+
// Lấy snapshot một lần lúc khởi tạo và đưa vào signal
|
|
1544
|
+
url = signal(this.#route.snapshot.queryParams?.['url'] || '');
|
|
1545
|
+
todayInfo = signal(this.#getTodayInfo(new Date()));
|
|
1546
|
+
userInfo = this.#layoutService.userInfo;
|
|
1547
|
+
// ==========================================
|
|
1548
|
+
// PRIVATE METHODS
|
|
1549
|
+
// ==========================================
|
|
1550
|
+
#getTodayInfo(date) {
|
|
1551
|
+
// WHY: weekday names i18n hóa qua key core.module.layout.weekday.<0..6>
|
|
1552
|
+
const weekday = this.#i18n.t(`core.module.layout.weekday.${date.getDay()}`);
|
|
1553
|
+
const dateStr = date.toLocaleDateString('vi-VN', {
|
|
1554
|
+
day: '2-digit',
|
|
1555
|
+
month: '2-digit',
|
|
1556
|
+
year: 'numeric',
|
|
1557
|
+
});
|
|
1558
|
+
return this.#i18n.t('core.module.layout.today-info.format', { weekday, date: dateStr });
|
|
1559
|
+
}
|
|
1560
|
+
// ==========================================
|
|
1561
|
+
// PUBLIC METHODS
|
|
1562
|
+
// ==========================================
|
|
1563
|
+
reload() {
|
|
1564
|
+
window.location.href = '';
|
|
1565
|
+
}
|
|
1566
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: RootComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1567
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.21", type: RootComponent, isStandalone: true, selector: "ng-component", ngImport: i0, template: "@let _userInfo = userInfo();\n<sd-page>\n <div class=\"d-flex flex-column\" headerLeft>\n <div class=\"font-weight-medium fs-20\">{{ 'core.module.layout.greeting.hello' | translate: { name: _userInfo?.fullName ?? _userInfo?.email ?? _userInfo?.username ?? '' } }}</div>\n <span class=\"T12R text-secondary\">{{ todayInfo() }}</span>\n </div>\n <div class=\"h-full d-flex flex-column align-items-center\">\n <div class=\"h-full d-flex flex-column align-items-center justify-content-center text-center wrapper\">\n <img alt=\"forbidden\" class=\"sd-image-forbidden\" />\n <span class=\"T16M mt-24\">{{ 'core.module.layout.forbidden.title' | translate }}</span>\n <span class=\"T14R text-secondary mt-4\"\n >{{ 'core.module.layout.forbidden.message' | translate }}</span\n >\n <sd-button class=\"mt-16\" type=\"fill\" color=\"primary\" (click)=\"reload()\" [title]=\"'core.module.layout.forbidden.back-home' | translate\"> </sd-button>\n </div>\n </div>\n</sd-page>\n", styles: [".wrapper{width:300px}\n"], dependencies: [{ kind: "component", type: SdButton, selector: "sd-button", inputs: ["autoId", "type", "color", "size", "fontSet", "title", "width", "tooltip", "prefixIcon", "suffixIcon", "disabled", "loading", "block", "htmlType"], outputs: ["click"] }, { kind: "component", type: SdPageComponent, selector: "sd-page", inputs: ["title", "description", "noHeader"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
|
|
1568
|
+
}
|
|
1569
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: RootComponent, decorators: [{
|
|
1570
|
+
type: Component,
|
|
1571
|
+
args: [{ imports: [SdButton, SdPageComponent, TranslatePipe], template: "@let _userInfo = userInfo();\n<sd-page>\n <div class=\"d-flex flex-column\" headerLeft>\n <div class=\"font-weight-medium fs-20\">{{ 'core.module.layout.greeting.hello' | translate: { name: _userInfo?.fullName ?? _userInfo?.email ?? _userInfo?.username ?? '' } }}</div>\n <span class=\"T12R text-secondary\">{{ todayInfo() }}</span>\n </div>\n <div class=\"h-full d-flex flex-column align-items-center\">\n <div class=\"h-full d-flex flex-column align-items-center justify-content-center text-center wrapper\">\n <img alt=\"forbidden\" class=\"sd-image-forbidden\" />\n <span class=\"T16M mt-24\">{{ 'core.module.layout.forbidden.title' | translate }}</span>\n <span class=\"T14R text-secondary mt-4\"\n >{{ 'core.module.layout.forbidden.message' | translate }}</span\n >\n <sd-button class=\"mt-16\" type=\"fill\" color=\"primary\" (click)=\"reload()\" [title]=\"'core.module.layout.forbidden.back-home' | translate\"> </sd-button>\n </div>\n </div>\n</sd-page>\n", styles: [".wrapper{width:300px}\n"] }]
|
|
1572
|
+
}] });
|
|
1573
|
+
|
|
1574
|
+
const Routes$1 = [{ path: '', component: RootComponent }];
|
|
1575
|
+
|
|
1576
|
+
class ForbiddenModule {
|
|
1577
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ForbiddenModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
1578
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.21", ngImport: i0, type: ForbiddenModule, imports: [CommonModule, i1$6.RouterModule] });
|
|
1579
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ForbiddenModule, imports: [CommonModule, RouterModule.forChild(Routes$1)] });
|
|
1580
|
+
}
|
|
1581
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: ForbiddenModule, decorators: [{
|
|
1582
|
+
type: NgModule,
|
|
1583
|
+
args: [{
|
|
1584
|
+
imports: [CommonModule, RouterModule.forChild(Routes$1)],
|
|
1585
|
+
exports: [],
|
|
1586
|
+
}]
|
|
1587
|
+
}] });
|
|
1588
|
+
|
|
1589
|
+
var index = /*#__PURE__*/Object.freeze({
|
|
1590
|
+
__proto__: null,
|
|
1591
|
+
ForbiddenModule: ForbiddenModule
|
|
1592
|
+
});
|
|
1593
|
+
|
|
1594
|
+
const Routes = [
|
|
1595
|
+
{
|
|
1596
|
+
path: '',
|
|
1597
|
+
pathMatch: 'full',
|
|
1598
|
+
redirectTo: 'not-found',
|
|
1599
|
+
},
|
|
1600
|
+
{
|
|
1601
|
+
path: 'home',
|
|
1602
|
+
loadChildren: () => Promise.resolve().then(function () { return index$2; }).then(m => m.HomeModule),
|
|
1603
|
+
},
|
|
1604
|
+
{
|
|
1605
|
+
path: 'not-found',
|
|
1606
|
+
loadChildren: () => Promise.resolve().then(function () { return index$1; }).then(m => m.NotFoundModule),
|
|
1607
|
+
},
|
|
1608
|
+
{
|
|
1609
|
+
path: 'forbidden',
|
|
1610
|
+
loadChildren: () => Promise.resolve().then(function () { return index; }).then(m => m.ForbiddenModule),
|
|
1611
|
+
},
|
|
1612
|
+
];
|
|
1613
|
+
|
|
1614
|
+
class SdLayoutModule {
|
|
1615
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdLayoutModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
1616
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.21", ngImport: i0, type: SdLayoutModule, imports: [i1$6.RouterModule] });
|
|
1617
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdLayoutModule, imports: [RouterModule.forChild(Routes)] });
|
|
1618
|
+
}
|
|
1619
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: SdLayoutModule, decorators: [{
|
|
1620
|
+
type: NgModule,
|
|
1621
|
+
args: [{
|
|
1622
|
+
declarations: [],
|
|
1623
|
+
imports: [RouterModule.forChild(Routes)],
|
|
1624
|
+
providers: [],
|
|
1625
|
+
}]
|
|
1626
|
+
}] });
|
|
1627
|
+
|
|
1628
|
+
/**
|
|
1629
|
+
* Generated bundle index. Do not edit.
|
|
1630
|
+
*/
|
|
1631
|
+
|
|
1632
|
+
export { ForbiddenModule, HomeModule, NotFoundModule, SD_LAYOUT_CONFIGURATION, SdLayoutComponent, SdLayoutModule, SdLayoutService, SdLayoutStorageService, SdPageComponent, SidebarMobileOverlayComponent, SidebarMobileV1Component };
|
|
1633
|
+
//# sourceMappingURL=sdcorejs-angular-modules-layout.mjs.map
|