From 162688cdb55ed1701ec5d7c77708b71354ff8464 Mon Sep 17 00:00:00 2001 From: Juergen Kunz Date: Tue, 27 Jan 2026 10:57:42 +0000 Subject: [PATCH] feat(components): add large set of new UI components and demos, reorganize groups, and bump a few dependencies --- changelog.md | 14 + package.json | 4 +- pnpm-lock.yaml | 53 +- readme.hints.md | 136 +++- ts_web/00_commitinfo_data.ts | 2 +- .../dees-appui-activitylog.ts | 6 +- .../dees-appui-appbar/component.ts | 6 +- .../dees-appui-bottombar.ts | 6 +- .../dees-appui-maincontent.ts | 2 +- .../dees-appui-mainmenu.ts | 4 +- .../dees-appui-profiledropdown.ts | 2 +- .../dees-appui-secondarymenu.ts | 6 +- .../dees-appui-tabs/dees-appui-tabs.ts | 2 +- .../dees-appui/dees-appui.demo.ts | 4 +- .../00group-appui/dees-appui/dees-appui.ts | 2 +- .../dees-mobilenavigation.demo.ts | 2 +- .../dees-mobilenavigation.ts | 13 +- .../dees-mobilenavigation/index.ts | 0 ts_web/elements/00group-appui/index.ts | 1 + .../dees-button-exit/dees-button-exit.ts | 2 +- .../dees-button-group/dees-button-group.ts | 2 +- .../dees-button/dees-button.demo.ts | 4 +- .../00group-button/dees-button/dees-button.ts | 2 +- .../dees-chart-area/component.ts | 2 +- .../dees-chart-log/dees-chart-log.ts | 2 +- .../dees-dataview-codebox.ts | 6 +- .../dees-dataview-statusobject.ts | 4 +- .../dees-statsgrid/dees-statsgrid.demo.ts | 2 +- .../dees-statsgrid/dees-statsgrid.ts | 13 +- .../dees-statsgrid/index.ts | 0 .../{ => 00group-dataview}/dees-table/data.ts | 0 .../dees-table/dees-table.demo.ts | 2 +- .../dees-table/dees-table.ts | 9 +- .../dees-table/index.ts | 0 .../dees-table/lucene.ts | 0 .../dees-table/styles.ts | 4 +- .../dees-table/types.ts | 2 +- ts_web/elements/00group-dataview/index.ts | 2 + .../dees-actionbar/actionbar.interfaces.ts | 0 .../dees-actionbar/dees-actionbar.ts | 5 +- .../dees-actionbar/index.ts | 0 .../dees-badge/dees-badge.demo.ts | 0 .../dees-badge/dees-badge.ts | 3 +- .../dees-badge/index.ts | 0 .../dees-hint/dees-hint.demo.ts | 0 .../dees-hint/dees-hint.ts | 3 +- .../{ => 00group-feedback}/dees-hint/index.ts | 0 .../dees-progressbar/dees-progressbar.demo.ts | 0 .../dees-progressbar/dees-progressbar.ts | 7 +- .../dees-progressbar/index.ts | 0 .../dees-spinner/dees-spinner.ts | 3 +- .../dees-spinner/index.ts | 0 .../dees-toast/dees-toast.demo.ts | 2 +- .../dees-toast/dees-toast.ts | 7 +- .../dees-toast/index.ts | 0 ts_web/elements/00group-feedback/index.ts | 7 + .../dees-form-submit/dees-form-submit.ts | 2 +- .../00group-form/dees-form/dees-form.ts | 4 +- .../dees-input-checkbox.demo.ts | 2 +- .../dees-input-checkbox.ts | 2 +- .../dees-input-code/dees-input-code.ts | 8 +- .../dees-input-datepicker/component.ts | 6 +- .../dees-input-datepicker/demo.ts | 2 +- .../dees-input-dropdown.demo.ts | 2 +- .../dees-input-dropdown.ts | 2 +- .../dees-input-fileupload/component.ts | 6 +- .../dees-input-fileupload/demo.ts | 2 +- .../dees-input-iban/dees-input-iban.ts | 2 +- .../dees-input-list/dees-input-list.demo.ts | 2 +- .../dees-input-list/dees-input-list.ts | 4 +- .../dees-input-multitoggle.ts | 2 +- .../dees-input-phone/dees-input-phone.ts | 2 +- .../dees-input-quantityselector.demo.ts | 2 +- .../dees-input-quantityselector.ts | 2 +- .../dees-input-radiogroup.demo.ts | 2 +- .../dees-input-radiogroup.ts | 2 +- .../dees-input-richtext/component.ts | 4 +- .../00group-input/dees-input-richtext/demo.ts | 2 +- .../dees-input-tags/dees-input-tags.demo.ts | 2 +- .../dees-input-tags/dees-input-tags.ts | 4 +- .../dees-input-text/dees-input-text.demo.ts | 2 +- .../dees-input-text/dees-input-text.ts | 2 +- .../dees-input-toggle.demo.ts | 2 +- .../dees-input-toggle/dees-input-toggle.ts | 2 +- .../dees-input-typelist.ts | 2 +- .../00group-input/dees-input-wysiwyg.demo.ts | 2 +- .../dees-input-wysiwyg/dees-input-wysiwyg.ts | 4 +- .../dees-input-wysiwyg/dees-slash-menu.ts | 2 +- .../dees-input-wysiwyg/dees-wysiwyg-block.ts | 2 +- .../wysiwyg.modalmanager.ts | 2 +- .../dees-input-profilepicture.demo.ts | 2 +- .../dees-input-profilepicture.ts | 6 +- .../profilepicture/profilepicture.modal.ts | 6 +- .../dees-chips/dees-chips.demo.ts | 0 .../dees-chips/dees-chips.ts | 3 +- .../{ => 00group-layout}/dees-chips/index.ts | 0 .../dees-dashboardgrid/README.md | 0 .../dees-dashboardgrid/contextmenu.ts | 4 +- .../dees-dashboardgrid.demo.ts | 0 .../dees-dashboardgrid/dees-dashboardgrid.ts | 5 +- .../dees-dashboardgrid/index.ts | 0 .../dees-dashboardgrid/interaction.ts | 0 .../dees-dashboardgrid/layout.ts | 0 .../dees-dashboardgrid/styles.ts | 0 .../dees-dashboardgrid/types.ts | 0 .../dees-heading/dees-heading.demo.ts | 0 .../dees-heading/dees-heading.ts | 5 +- .../dees-heading/index.ts | 0 .../dees-label/dees-label.demo.ts | 0 .../dees-label/dees-label.ts | 7 +- .../{ => 00group-layout}/dees-label/index.ts | 0 .../dees-pagination/dees-pagination.demo.ts | 0 .../dees-pagination/dees-pagination.ts | 3 +- .../dees-pagination/index.ts | 0 .../dees-panel/dees-panel.demo.ts | 0 .../dees-panel/dees-panel.ts | 5 +- .../{ => 00group-layout}/dees-panel/index.ts | 0 .../dees-stepper/dees-stepper.demo.ts | 0 .../dees-stepper/dees-stepper.ts | 7 +- .../dees-stepper/index.ts | 0 ts_web/elements/00group-layout/index.ts | 8 + .../dees-audio-viewer/component.ts | 611 ++++++++++++++++++ .../00group-media/dees-audio-viewer/demo.ts | 69 ++ .../dees-audio-viewer}/index.ts | 0 .../dees-image-viewer/component.ts | 410 ++++++++++++ .../00group-media/dees-image-viewer/demo.ts | 84 +++ .../dees-image-viewer}/index.ts | 0 .../dees-pdf-preview/component.ts | 24 + .../dees-pdf-preview/demo.ts | 0 .../dees-pdf-preview}/index.ts | 0 .../dees-pdf-preview/styles.ts | 0 .../dees-pdf-shared/CanvasPool.ts | 0 .../dees-pdf-shared/PdfManager.ts | 0 .../dees-pdf-shared/index.ts | 0 .../dees-pdf-shared/utils.ts | 0 .../dees-pdf-viewer/component.ts | 4 +- .../dees-pdf-viewer/demo.ts | 0 .../00group-media/dees-pdf-viewer/index.ts | 1 + .../dees-pdf-viewer/styles.ts | 0 .../dees-pdf/component.ts | 10 +- .../elements/00group-media/dees-pdf/index.ts | 1 + .../dees-preview/dees-preview.demo.ts | 122 ++++ .../dees-preview/dees-preview.ts | 507 +++++++++++++++ .../{ => 00group-media}/dees-preview/index.ts | 0 .../dees-tile-audio/component.ts | 344 ++++++++++ .../00group-media/dees-tile-audio/demo.ts | 77 +++ .../00group-media/dees-tile-audio/index.ts | 1 + .../dees-tile-folder/component.ts | 181 ++++++ .../00group-media/dees-tile-folder/demo.ts | 122 ++++ .../00group-media/dees-tile-folder/index.ts | 1 + .../dees-tile-image/component.ts | 172 +++++ .../00group-media/dees-tile-image/demo.ts | 84 +++ .../00group-media/dees-tile-image/index.ts | 1 + .../00group-media/dees-tile-note/component.ts | 231 +++++++ .../00group-media/dees-tile-note/demo.ts | 135 ++++ .../00group-media/dees-tile-note/index.ts | 1 + .../dees-tile-pdf}/component.ts | 279 +++----- .../00group-media/dees-tile-pdf/demo.ts | 128 ++++ .../00group-media/dees-tile-pdf/index.ts | 1 + .../00group-media/dees-tile-pdf/styles.ts | 61 ++ .../dees-tile-shared/DeesTileBase.ts | 130 ++++ .../00group-media/dees-tile-shared/index.ts | 2 + .../00group-media/dees-tile-shared/styles.ts | 213 ++++++ .../dees-tile-video/component.ts | 317 +++++++++ .../00group-media/dees-tile-video/demo.ts | 79 +++ .../00group-media/dees-tile-video/index.ts | 1 + .../dees-video-viewer/component.ts | 506 +++++++++++++++ .../00group-media/dees-video-viewer/demo.ts | 63 ++ .../00group-media/dees-video-viewer/index.ts | 1 + ts_web/elements/00group-media/index.ts | 20 + .../dees-contextmenu/dees-contextmenu.demo.ts | 2 +- .../dees-contextmenu/dees-contextmenu.ts | 9 +- .../dees-contextmenu/index.ts | 0 .../dees-modal/dees-modal.demo.ts | 0 .../dees-modal/dees-modal.ts | 13 +- .../{ => 00group-overlay}/dees-modal/index.ts | 0 .../dees-speechbubble.demo.ts | 0 .../dees-speechbubble/dees-speechbubble.ts | 7 +- .../dees-speechbubble/index.ts | 0 .../dees-windowlayer/dees-windowlayer.ts | 3 +- .../dees-windowlayer/index.ts | 0 ts_web/elements/00group-overlay/index.ts | 5 + ts_web/elements/00group-pdf/index.ts | 5 - .../dees-shopping-productcard.demo.ts | 2 +- .../dees-shopping-productcard.ts | 3 +- .../dees-shopping-productcard/index.ts | 0 .../dees-simple-appdash.demo.ts | 4 +- .../dees-simple-appdash.ts | 4 +- .../dees-simple-login/dees-simple-login.ts | 2 +- ts_web/elements/00group-simple/index.ts | 1 + .../dees-icon/dees-icon.demo.ts | 0 .../dees-icon/dees-icon.ts | 3 +- .../{ => 00group-utility}/dees-icon/index.ts | 0 .../dees-searchbar/dees-searchbar.demo.ts | 0 .../dees-searchbar/dees-searchbar.ts | 5 +- .../dees-searchbar/index.ts | 0 .../dees-theme/dees-theme.demo.ts | 0 .../dees-theme/dees-theme.ts | 3 +- .../{ => 00group-utility}/dees-theme/index.ts | 0 .../dees-updater/dees-updater.demo.ts | 0 .../dees-updater/dees-updater.ts | 5 +- .../dees-updater/index.ts | 0 .../dees-windowcontrols.ts | 3 +- .../dees-windowcontrols/index.ts | 0 ts_web/elements/00group-utility/index.ts | 6 + .../dees-workspace-bottombar.ts | 4 +- .../dees-workspace-diff-editor.ts | 2 +- .../dees-workspace-filetree.ts | 10 +- .../dees-workspace-markdown.ts | 2 +- .../dees-workspace-markdownoutlet.demo.ts | 2 +- .../dees-workspace-markdownoutlet.ts | 2 +- .../dees-workspace-monaco.ts | 2 +- .../dees-workspace-terminal-preview.ts | 2 +- .../dees-workspace-terminal.ts | 8 +- .../dees-workspace/dees-workspace.ts | 10 +- ts_web/elements/dees-preview/dees-preview.ts | 0 ts_web/elements/index.ts | 37 +- ts_web/pages/zindex-showcase.ts | 8 +- 218 files changed, 5223 insertions(+), 458 deletions(-) rename ts_web/elements/{ => 00group-appui}/dees-mobilenavigation/dees-mobilenavigation.demo.ts (99%) rename ts_web/elements/{ => 00group-appui}/dees-mobilenavigation/dees-mobilenavigation.ts (95%) rename ts_web/elements/{ => 00group-appui}/dees-mobilenavigation/index.ts (100%) rename ts_web/elements/{ => 00group-dataview}/dees-statsgrid/dees-statsgrid.demo.ts (99%) rename ts_web/elements/{ => 00group-dataview}/dees-statsgrid/dees-statsgrid.ts (98%) rename ts_web/elements/{ => 00group-dataview}/dees-statsgrid/index.ts (100%) rename ts_web/elements/{ => 00group-dataview}/dees-table/data.ts (100%) rename ts_web/elements/{ => 00group-dataview}/dees-table/dees-table.demo.ts (99%) rename ts_web/elements/{ => 00group-dataview}/dees-table/dees-table.ts (98%) rename ts_web/elements/{ => 00group-dataview}/dees-table/index.ts (100%) rename ts_web/elements/{ => 00group-dataview}/dees-table/lucene.ts (100%) rename ts_web/elements/{ => 00group-dataview}/dees-table/styles.ts (99%) rename ts_web/elements/{ => 00group-dataview}/dees-table/types.ts (93%) rename ts_web/elements/{ => 00group-feedback}/dees-actionbar/actionbar.interfaces.ts (100%) rename ts_web/elements/{ => 00group-feedback}/dees-actionbar/dees-actionbar.ts (98%) rename ts_web/elements/{ => 00group-feedback}/dees-actionbar/index.ts (100%) rename ts_web/elements/{ => 00group-feedback}/dees-badge/dees-badge.demo.ts (100%) rename ts_web/elements/{ => 00group-feedback}/dees-badge/dees-badge.ts (95%) rename ts_web/elements/{ => 00group-feedback}/dees-badge/index.ts (100%) rename ts_web/elements/{ => 00group-feedback}/dees-hint/dees-hint.demo.ts (100%) rename ts_web/elements/{ => 00group-feedback}/dees-hint/dees-hint.ts (89%) rename ts_web/elements/{ => 00group-feedback}/dees-hint/index.ts (100%) rename ts_web/elements/{ => 00group-feedback}/dees-progressbar/dees-progressbar.demo.ts (100%) rename ts_web/elements/{ => 00group-feedback}/dees-progressbar/dees-progressbar.ts (92%) rename ts_web/elements/{ => 00group-feedback}/dees-progressbar/index.ts (100%) rename ts_web/elements/{ => 00group-feedback}/dees-spinner/dees-spinner.ts (97%) rename ts_web/elements/{ => 00group-feedback}/dees-spinner/index.ts (100%) rename ts_web/elements/{ => 00group-feedback}/dees-toast/dees-toast.demo.ts (99%) rename ts_web/elements/{ => 00group-feedback}/dees-toast/dees-toast.ts (97%) rename ts_web/elements/{ => 00group-feedback}/dees-toast/index.ts (100%) create mode 100644 ts_web/elements/00group-feedback/index.ts rename ts_web/elements/{ => 00group-layout}/dees-chips/dees-chips.demo.ts (100%) rename ts_web/elements/{ => 00group-layout}/dees-chips/dees-chips.ts (98%) rename ts_web/elements/{ => 00group-layout}/dees-chips/index.ts (100%) rename ts_web/elements/{ => 00group-layout}/dees-dashboardgrid/README.md (100%) rename ts_web/elements/{ => 00group-layout}/dees-dashboardgrid/contextmenu.ts (82%) rename ts_web/elements/{ => 00group-layout}/dees-dashboardgrid/dees-dashboardgrid.demo.ts (100%) rename ts_web/elements/{ => 00group-layout}/dees-dashboardgrid/dees-dashboardgrid.ts (99%) rename ts_web/elements/{ => 00group-layout}/dees-dashboardgrid/index.ts (100%) rename ts_web/elements/{ => 00group-layout}/dees-dashboardgrid/interaction.ts (100%) rename ts_web/elements/{ => 00group-layout}/dees-dashboardgrid/layout.ts (100%) rename ts_web/elements/{ => 00group-layout}/dees-dashboardgrid/styles.ts (100%) rename ts_web/elements/{ => 00group-layout}/dees-dashboardgrid/types.ts (100%) rename ts_web/elements/{ => 00group-layout}/dees-heading/dees-heading.demo.ts (100%) rename ts_web/elements/{ => 00group-layout}/dees-heading/dees-heading.ts (95%) rename ts_web/elements/{ => 00group-layout}/dees-heading/index.ts (100%) rename ts_web/elements/{ => 00group-layout}/dees-label/dees-label.demo.ts (100%) rename ts_web/elements/{ => 00group-layout}/dees-label/dees-label.ts (91%) rename ts_web/elements/{ => 00group-layout}/dees-label/index.ts (100%) rename ts_web/elements/{ => 00group-layout}/dees-pagination/dees-pagination.demo.ts (100%) rename ts_web/elements/{ => 00group-layout}/dees-pagination/dees-pagination.ts (97%) rename ts_web/elements/{ => 00group-layout}/dees-pagination/index.ts (100%) rename ts_web/elements/{ => 00group-layout}/dees-panel/dees-panel.demo.ts (100%) rename ts_web/elements/{ => 00group-layout}/dees-panel/dees-panel.ts (97%) rename ts_web/elements/{ => 00group-layout}/dees-panel/index.ts (100%) rename ts_web/elements/{ => 00group-layout}/dees-stepper/dees-stepper.demo.ts (100%) rename ts_web/elements/{ => 00group-layout}/dees-stepper/dees-stepper.ts (97%) rename ts_web/elements/{ => 00group-layout}/dees-stepper/index.ts (100%) create mode 100644 ts_web/elements/00group-layout/index.ts create mode 100644 ts_web/elements/00group-media/dees-audio-viewer/component.ts create mode 100644 ts_web/elements/00group-media/dees-audio-viewer/demo.ts rename ts_web/elements/{00group-pdf/dees-pdf-preview => 00group-media/dees-audio-viewer}/index.ts (100%) create mode 100644 ts_web/elements/00group-media/dees-image-viewer/component.ts create mode 100644 ts_web/elements/00group-media/dees-image-viewer/demo.ts rename ts_web/elements/{00group-pdf/dees-pdf-viewer => 00group-media/dees-image-viewer}/index.ts (100%) create mode 100644 ts_web/elements/00group-media/dees-pdf-preview/component.ts rename ts_web/elements/{00group-pdf => 00group-media}/dees-pdf-preview/demo.ts (100%) rename ts_web/elements/{00group-pdf/dees-pdf => 00group-media/dees-pdf-preview}/index.ts (100%) rename ts_web/elements/{00group-pdf => 00group-media}/dees-pdf-preview/styles.ts (100%) rename ts_web/elements/{00group-pdf => 00group-media}/dees-pdf-shared/CanvasPool.ts (100%) rename ts_web/elements/{00group-pdf => 00group-media}/dees-pdf-shared/PdfManager.ts (100%) rename ts_web/elements/{00group-pdf => 00group-media}/dees-pdf-shared/index.ts (100%) rename ts_web/elements/{00group-pdf => 00group-media}/dees-pdf-shared/utils.ts (100%) rename ts_web/elements/{00group-pdf => 00group-media}/dees-pdf-viewer/component.ts (99%) rename ts_web/elements/{00group-pdf => 00group-media}/dees-pdf-viewer/demo.ts (100%) create mode 100644 ts_web/elements/00group-media/dees-pdf-viewer/index.ts rename ts_web/elements/{00group-pdf => 00group-media}/dees-pdf-viewer/styles.ts (100%) rename ts_web/elements/{00group-pdf => 00group-media}/dees-pdf/component.ts (92%) create mode 100644 ts_web/elements/00group-media/dees-pdf/index.ts create mode 100644 ts_web/elements/00group-media/dees-preview/dees-preview.demo.ts create mode 100644 ts_web/elements/00group-media/dees-preview/dees-preview.ts rename ts_web/elements/{ => 00group-media}/dees-preview/index.ts (100%) create mode 100644 ts_web/elements/00group-media/dees-tile-audio/component.ts create mode 100644 ts_web/elements/00group-media/dees-tile-audio/demo.ts create mode 100644 ts_web/elements/00group-media/dees-tile-audio/index.ts create mode 100644 ts_web/elements/00group-media/dees-tile-folder/component.ts create mode 100644 ts_web/elements/00group-media/dees-tile-folder/demo.ts create mode 100644 ts_web/elements/00group-media/dees-tile-folder/index.ts create mode 100644 ts_web/elements/00group-media/dees-tile-image/component.ts create mode 100644 ts_web/elements/00group-media/dees-tile-image/demo.ts create mode 100644 ts_web/elements/00group-media/dees-tile-image/index.ts create mode 100644 ts_web/elements/00group-media/dees-tile-note/component.ts create mode 100644 ts_web/elements/00group-media/dees-tile-note/demo.ts create mode 100644 ts_web/elements/00group-media/dees-tile-note/index.ts rename ts_web/elements/{00group-pdf/dees-pdf-preview => 00group-media/dees-tile-pdf}/component.ts (57%) create mode 100644 ts_web/elements/00group-media/dees-tile-pdf/demo.ts create mode 100644 ts_web/elements/00group-media/dees-tile-pdf/index.ts create mode 100644 ts_web/elements/00group-media/dees-tile-pdf/styles.ts create mode 100644 ts_web/elements/00group-media/dees-tile-shared/DeesTileBase.ts create mode 100644 ts_web/elements/00group-media/dees-tile-shared/index.ts create mode 100644 ts_web/elements/00group-media/dees-tile-shared/styles.ts create mode 100644 ts_web/elements/00group-media/dees-tile-video/component.ts create mode 100644 ts_web/elements/00group-media/dees-tile-video/demo.ts create mode 100644 ts_web/elements/00group-media/dees-tile-video/index.ts create mode 100644 ts_web/elements/00group-media/dees-video-viewer/component.ts create mode 100644 ts_web/elements/00group-media/dees-video-viewer/demo.ts create mode 100644 ts_web/elements/00group-media/dees-video-viewer/index.ts create mode 100644 ts_web/elements/00group-media/index.ts rename ts_web/elements/{ => 00group-overlay}/dees-contextmenu/dees-contextmenu.demo.ts (99%) rename ts_web/elements/{ => 00group-overlay}/dees-contextmenu/dees-contextmenu.ts (98%) rename ts_web/elements/{ => 00group-overlay}/dees-contextmenu/index.ts (100%) rename ts_web/elements/{ => 00group-overlay}/dees-modal/dees-modal.demo.ts (100%) rename ts_web/elements/{ => 00group-overlay}/dees-modal/dees-modal.ts (97%) rename ts_web/elements/{ => 00group-overlay}/dees-modal/index.ts (100%) rename ts_web/elements/{ => 00group-overlay}/dees-speechbubble/dees-speechbubble.demo.ts (100%) rename ts_web/elements/{ => 00group-overlay}/dees-speechbubble/dees-speechbubble.ts (96%) rename ts_web/elements/{ => 00group-overlay}/dees-speechbubble/index.ts (100%) rename ts_web/elements/{ => 00group-overlay}/dees-windowlayer/dees-windowlayer.ts (97%) rename ts_web/elements/{ => 00group-overlay}/dees-windowlayer/index.ts (100%) create mode 100644 ts_web/elements/00group-overlay/index.ts delete mode 100644 ts_web/elements/00group-pdf/index.ts rename ts_web/elements/{ => 00group-simple}/dees-shopping-productcard/dees-shopping-productcard.demo.ts (99%) rename ts_web/elements/{ => 00group-simple}/dees-shopping-productcard/dees-shopping-productcard.ts (98%) rename ts_web/elements/{ => 00group-simple}/dees-shopping-productcard/index.ts (100%) rename ts_web/elements/{ => 00group-utility}/dees-icon/dees-icon.demo.ts (100%) rename ts_web/elements/{ => 00group-utility}/dees-icon/dees-icon.ts (99%) rename ts_web/elements/{ => 00group-utility}/dees-icon/index.ts (100%) rename ts_web/elements/{ => 00group-utility}/dees-searchbar/dees-searchbar.demo.ts (100%) rename ts_web/elements/{ => 00group-utility}/dees-searchbar/dees-searchbar.ts (96%) rename ts_web/elements/{ => 00group-utility}/dees-searchbar/index.ts (100%) rename ts_web/elements/{ => 00group-utility}/dees-theme/dees-theme.demo.ts (100%) rename ts_web/elements/{ => 00group-utility}/dees-theme/dees-theme.ts (98%) rename ts_web/elements/{ => 00group-utility}/dees-theme/index.ts (100%) rename ts_web/elements/{ => 00group-utility}/dees-updater/dees-updater.demo.ts (100%) rename ts_web/elements/{ => 00group-utility}/dees-updater/dees-updater.ts (93%) rename ts_web/elements/{ => 00group-utility}/dees-updater/index.ts (100%) rename ts_web/elements/{ => 00group-utility}/dees-windowcontrols/dees-windowcontrols.ts (95%) rename ts_web/elements/{ => 00group-utility}/dees-windowcontrols/index.ts (100%) create mode 100644 ts_web/elements/00group-utility/index.ts delete mode 100644 ts_web/elements/dees-preview/dees-preview.ts diff --git a/changelog.md b/changelog.md index c7128ed..7083199 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,19 @@ # Changelog +## 2026-01-27 - 3.39.0 - feat(components) +add large set of new UI components and demos, reorganize groups, and bump a few dependencies + +- Add Media viewers: dees-image-viewer, dees-audio-viewer, dees-video-viewer, DeesPdf/DeesPdfViewer and related PDF utilities (CanvasPool, PdfManager) and demos +- Introduce dees-preview composite that auto-detects content and delegates to appropriate viewers +- New Tile system (DeesTileBase) and tile components: dees-tile-pdf, dees-tile-image, dees-tile-audio, dees-tile-video, dees-tile-note, dees-tile-folder plus demos +- Add dashboard/grid system: dees-dashboardgrid with drag/resize, collision resolution, layout helpers, demos and utilities +- Data view additions: dees-table with lucene-like query parser, column utilities, and dees-statsgrid enhancements (including cpuCores visualization) +- New feedback & overlay components: dees-toast, dees-actionbar, dees-progressbar, dees-spinner, dees-badge and supporting demos/interfaces +- Many layout and utility components added or improved: dees-panel, dees-chips, dees-heading, dees-label, dees-pagination, dees-stepper, and associated demos +- Refactor project structure: components organized into 00group-* directories and demo metadata migrated from demoGroup to demoGroups (string[]); many import path updates to match new grouping +- Deprecations/notes: dees-pdf-preview and legacy dees-pdf marked as deprecated in favor of new viewers/tiles +- Dependency bumps in package.json: @design.estate/dees-wcctools -> ^3.8.0, @git.zone/tstest -> ^3.1.8 + ## 2026-01-26 - 3.38.0 - feat(appui) add app shell and bottom bar APIs, new input components, and update README component listings and docs diff --git a/package.json b/package.json index b6d341c..fdd254f 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "dependencies": { "@design.estate/dees-domtools": "^2.3.7", "@design.estate/dees-element": "^2.1.5", - "@design.estate/dees-wcctools": "^3.7.1", + "@design.estate/dees-wcctools": "^3.8.0", "@fortawesome/fontawesome-svg-core": "^7.1.0", "@fortawesome/free-brands-svg-icons": "^7.1.0", "@fortawesome/free-regular-svg-icons": "^7.1.0", @@ -46,7 +46,7 @@ "devDependencies": { "@git.zone/tsbuild": "^4.1.2", "@git.zone/tsbundle": "^2.8.3", - "@git.zone/tstest": "^3.1.7", + "@git.zone/tstest": "^3.1.8", "@git.zone/tswatch": "^3.0.1", "@push.rocks/projectinfo": "^5.0.2", "@types/node": "^25.0.10" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ada3ed5..7bc3289 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,8 +15,8 @@ importers: specifier: ^2.1.5 version: 2.1.5 '@design.estate/dees-wcctools': - specifier: ^3.7.1 - version: 3.7.1 + specifier: ^3.8.0 + version: 3.8.0 '@fortawesome/fontawesome-svg-core': specifier: ^7.1.0 version: 7.1.0 @@ -94,8 +94,8 @@ importers: specifier: ^2.8.3 version: 2.8.3 '@git.zone/tstest': - specifier: ^3.1.7 - version: 3.1.7(@push.rocks/smartserve@2.0.1)(socks@2.8.7)(typescript@5.9.3) + specifier: ^3.1.8 + version: 3.1.8(@push.rocks/smartserve@2.0.1)(socks@2.8.7)(typescript@5.9.3) '@git.zone/tswatch': specifier: ^3.0.1 version: 3.0.1(@tiptap/pm@2.27.2) @@ -340,6 +340,9 @@ packages: '@cloudflare/workers-types@4.20260124.0': resolution: {integrity: sha512-h6TJlew6AtGuEXFc+k5ifalk+tg3fkg0lla6XbMAb2AKKfJGwlFNTwW2xyT/Ha92KY631CIJ+Ace08DPdFohdA==} + '@cloudflare/workers-types@4.20260127.0': + resolution: {integrity: sha512-4M1HLcWViSdT/pAeDGEB5x5P3sqW7UIi34QrBRnxXbqjAY9if8vBU/lWRWnM+UqKzxWGB2LYjEVOzZrp0jZL+w==} + '@configvault.io/interfaces@1.0.17': resolution: {integrity: sha512-bEcCUR2VBDJsTin8HQh8Uw/mlYl2v8A3jMIaQ+MTB9Hrqd6CZL2dL7iJdWyFl/3EIX+LDxWFR+Oq7liIq7w+1Q==} @@ -355,8 +358,8 @@ packages: '@design.estate/dees-element@2.1.5': resolution: {integrity: sha512-czUOFvBiUKi34I+/keDRDc71fuORZS0NfbSuD2jJ4D1ODiTPjaZ6A6SkdQ2QqCEzVsx73XF99Pu8pxPnaOLnHg==} - '@design.estate/dees-wcctools@3.7.1': - resolution: {integrity: sha512-BiNWghUoC05RTQOGVCTK+wis6d18LyLY+2p8vHC0q2OBw9hrPoY8k9EplpQgY40MvP0sTXWUwaa7VPXra8ASjA==} + '@design.estate/dees-wcctools@3.8.0': + resolution: {integrity: sha512-CC14iVKUrguzD9jIrdPBd9fZ4egVJEZMxl5y8iy0l7WLumeoYvGsoXj5INVkRPLRVLqziIdi4Je1hXqHt2NU+g==} '@emnapi/core@1.8.1': resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==} @@ -559,8 +562,8 @@ packages: resolution: {integrity: sha512-NEcnsjvlC1o3Z6SS3VhKCf6Ev+Sh4EAinmggslrIR/ppMrvjDbXNFXoyr3PB+GLeSAR0JRZ1fGvVYjpEzjBdIg==} hasBin: true - '@git.zone/tstest@3.1.7': - resolution: {integrity: sha512-YCDA+65LJhoY3WJxrNduKlpGf37aq4bFe+fdRqE0dZ2W1f7j3sUunBaBzckShSHKRjkMdPZKr0W0sXFXUK/PcA==} + '@git.zone/tstest@3.1.8': + resolution: {integrity: sha512-nmiLGeOkKMkLDyIk5BUBLx5ExskFbKHKlPdrWCARPVFkU4cAAiuIyJWVfLwISoS0TO/zSInLqArPwIc76yvaNw==} hasBin: true '@git.zone/tswatch@3.0.1': @@ -851,8 +854,8 @@ packages: '@push.rocks/smartbucket@3.3.10': resolution: {integrity: sha512-0H2MioALspC8Aj0Q1FPCs2w4k2u9oJg7Q5yM8+1TZo7aRfrdxgM5HQ7z3apUaqC3ZEDewW6vSlttjHFHhMEC3A==} - '@push.rocks/smartbucket@4.3.1': - resolution: {integrity: sha512-fMA8w98/E+usaaLkLm6wDj1XSpR0shTtG8AxTdwWIlH1YemQj/aCf4wReezDxUFVoUpC3HMzzV2RTFtQvHndeQ==} + '@push.rocks/smartbucket@4.4.1': + resolution: {integrity: sha512-68GFLgJKW+LXvuN+yuV8O/FozGMecraoT+PkI5whdRPFe7N3u2iYIHWAUjvQvVU4ygpdJv0kih2JDf5k3PYycw==} '@push.rocks/smartbuffer@3.0.5': resolution: {integrity: sha512-pWYF08Mn8s/KF/9nHRk7pZPzuMjmYVQay2c5gGexdayxn1W4eCSYYhWH73vR2JBfGeGq/izbRNuUuEaIEeTIKA==} @@ -1927,8 +1930,8 @@ packages: asynckit@0.4.0: resolution: {integrity: sha1-x57Zf380y48robyXkLzDZkdLS3k=} - axios@1.13.2: - resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} + axios@1.13.3: + resolution: {integrity: sha512-ERT8kdX7DZjtUm7IitEyV7InTHAF42iJuMArIiDIV5YtPanJkgw4hw5Dyg9fh0mihdWNn1GKaeIWErfe56UQ1g==} b4a@1.7.3: resolution: {integrity: sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==} @@ -1952,8 +1955,8 @@ packages: bare-abort-controller: optional: true - bare-fs@4.5.2: - resolution: {integrity: sha512-veTnRzkb6aPHOvSKIOy60KzURfBdUflr5VReI+NSaPL6xf+XLdONQgZgpYvUuZLVQ8dCqxpBAudaOM1+KpAUxw==} + bare-fs@4.5.3: + resolution: {integrity: sha512-9+kwVx8QYvt3hPWnmb19tPnh38c6Nihz8Lx3t0g9+4GoIf3/fTgYwM4Z6NxgI+B9elLQA7mLE9PpqcWtOMRDiQ==} engines: {bare: '>=1.16.0'} peerDependencies: bare-buffer: '*' @@ -4048,7 +4051,7 @@ snapshots: '@api.global/typedrequest': 3.2.5 '@api.global/typedrequest-interfaces': 3.0.19 '@api.global/typedsocket': 3.1.1(@push.rocks/smartserve@2.0.1) - '@cloudflare/workers-types': 4.20260124.0 + '@cloudflare/workers-types': 4.20260127.0 '@design.estate/dees-comms': 1.0.30 '@push.rocks/lik': 6.2.2 '@push.rocks/smartchok': 1.2.0 @@ -4719,6 +4722,8 @@ snapshots: '@cloudflare/workers-types@4.20260124.0': {} + '@cloudflare/workers-types@4.20260127.0': {} + '@configvault.io/interfaces@1.0.17': dependencies: '@api.global/typedrequest-interfaces': 3.0.19 @@ -4727,7 +4732,7 @@ snapshots: dependencies: '@design.estate/dees-domtools': 2.3.7 '@design.estate/dees-element': 2.1.5 - '@design.estate/dees-wcctools': 3.7.1 + '@design.estate/dees-wcctools': 3.8.0 '@fortawesome/fontawesome-svg-core': 7.1.0 '@fortawesome/free-brands-svg-icons': 7.1.0 '@fortawesome/free-regular-svg-icons': 7.1.0 @@ -4803,7 +4808,7 @@ snapshots: - supports-color - vue - '@design.estate/dees-wcctools@3.7.1': + '@design.estate/dees-wcctools@3.8.0': dependencies: '@design.estate/dees-domtools': 2.3.7 '@design.estate/dees-element': 2.1.5 @@ -5002,7 +5007,7 @@ snapshots: '@push.rocks/smartshell': 3.3.0 tsx: 4.21.0 - '@git.zone/tstest@3.1.7(@push.rocks/smartserve@2.0.1)(socks@2.8.7)(typescript@5.9.3)': + '@git.zone/tstest@3.1.8(@push.rocks/smartserve@2.0.1)(socks@2.8.7)(typescript@5.9.3)': dependencies: '@api.global/typedserver': 3.0.80(@push.rocks/smartserve@2.0.1) '@git.zone/tsbundle': 2.8.3 @@ -5572,7 +5577,7 @@ snapshots: transitivePeerDependencies: - aws-crt - '@push.rocks/smartbucket@4.3.1': + '@push.rocks/smartbucket@4.4.1': dependencies: '@aws-sdk/client-s3': 3.975.0 '@push.rocks/smartmime': 2.0.4 @@ -6023,7 +6028,7 @@ snapshots: '@push.rocks/smarts3@3.0.3': dependencies: - '@push.rocks/smartbucket': 4.3.1 + '@push.rocks/smartbucket': 4.4.1 '@push.rocks/smartfs': 1.3.1 '@push.rocks/smartpath': 6.0.0 '@push.rocks/smartxml': 2.0.0 @@ -7112,7 +7117,7 @@ snapshots: dependencies: '@peculiar/x509': 1.14.3 asn1js: 3.0.7 - axios: 1.13.2(debug@4.4.3) + axios: 1.13.3(debug@4.4.3) debug: 4.4.3 node-forge: 1.3.3 transitivePeerDependencies: @@ -7171,7 +7176,7 @@ snapshots: asynckit@0.4.0: {} - axios@1.13.2(debug@4.4.3): + axios@1.13.3(debug@4.4.3): dependencies: follow-redirects: 1.15.11(debug@4.4.3) form-data: 4.0.5 @@ -7187,7 +7192,7 @@ snapshots: bare-events@2.8.2: {} - bare-fs@4.5.2: + bare-fs@4.5.3: dependencies: bare-events: 2.8.2 bare-path: 3.0.0 @@ -9403,7 +9408,7 @@ snapshots: pump: 3.0.3 tar-stream: 3.1.7 optionalDependencies: - bare-fs: 4.5.2 + bare-fs: 4.5.3 bare-path: 3.0.0 transitivePeerDependencies: - bare-abort-controller diff --git a/readme.hints.md b/readme.hints.md index ea6b639..4d0cccf 100644 --- a/readme.hints.md +++ b/readme.hints.md @@ -912,6 +912,93 @@ appui.getBottomBarVisible(); - `ts_web/elements/00group-appui/dees-appui-bottombar/dees-appui-bottombar.demo.ts` - Demo - `ts_web/elements/interfaces/appconfig.ts` - New interfaces added +## Media Components (2026-01-26) + +New media viewer components and a unified preview composite component. + +### Directory: `ts_web/elements/00group-media/` + +#### dees-image-viewer +- Image display with zoom, pan, fit, and download controls +- Properties: `src`, `alt`, `fit` ('contain'|'cover'|'actual'), `showToolbar` +- Features: mouse wheel zoom, click-drag pan, double-click toggle, checkerboard transparency background +- Toolbar matches PDF viewer pattern (48px height, 32px buttons, 16px icons, 6px border-radius) + +#### dees-audio-viewer +- Audio player with waveform visualization via Web Audio API +- Properties: `src`, `title`, `artist`, `showWaveform`, `autoplay`, `loop` +- Features: canvas waveform rendering, play/pause, seek, volume control, mute toggle, loop toggle +- Uses `HTMLAudioElement` for playback, `AudioContext.decodeAudioData` for waveform data + +#### dees-video-viewer +- Video player with custom overlay controls +- Properties: `src`, `poster`, `showControls`, `autoplay`, `loop`, `muted` +- Features: custom controls bar with gradient, seekbar, volume slider, fullscreen toggle, auto-hide controls, 16:9 aspect ratio + +### dees-preview (Composite Component) +- Auto-detects content type and delegates to the appropriate viewer +- Directory: `ts_web/elements/dees-preview/` +- Properties: `url`, `file` (File object), `base64`, `textContent`, `contentType` (override), `language`, `mimeType`, `filename`, `showToolbar`, `showFilename` +- Content type detection priority: explicit override → MIME type → file extension → fallback +- Renders: image→DeesImageViewer, pdf→DeesPdfViewer, code→DeesDataviewCodebox, audio→DeesAudioViewer, video→DeesVideoViewer, text→pre, unknown→placeholder +- Header bar with file type icon, filename, and type badge + +### dees-dataview-codebox modification +- Removed `` elements from the appbar (Step 1 of the plan) +- Now shows clean centered filename title bar without fake window buttons + +### Icon Sizing Convention +- All `dees-icon` elements in buttons need explicit `font-size: 16px` CSS rule +- Toolbar buttons: 32px × 32px, border-radius: 6px +- Placeholder/error icons: `font-size: 32px` +- Pattern: `.button-class dees-icon { font-size: 16px; }` + +## Tile Component System (2026-01-27) + +A family of 200×260px content preview cards with a shared abstract base class. All tiles support lazy loading (IntersectionObserver with 200px margin), hover lift effect, click events, loading/error states, and three sizes (small: 150×195, default: 200×260, large: 250×325). + +### Architecture + +- **DeesTileBase** (`dees-tile-shared/DeesTileBase.ts`) — Abstract base class extending DeesElement + - Common properties: `clickable`, `loading`, `error`, `size`, `label` + - IntersectionObserver lazy loading via `onBecameVisible()` hook + - Click dispatch via `tile-click` CustomEvent (detail from `getTileClickDetail()`) + - Subclasses implement `renderTileContent(): TemplateResult` + +### Components + +| Tag | Class | Description | +|-----|-------|-------------| +| `dees-tile-pdf` | `DeesTilePdf` | PDF page thumbnail with hover-to-browse pages. Canvas-rendered via PDF.js/CanvasPool. | +| `dees-tile-image` | `DeesTileImage` | Image thumbnail with `object-fit: cover`, dimension detection on load | +| `dees-tile-audio` | `DeesTileAudio` | Music icon + mini waveform (AudioContext decode), duration badge | +| `dees-tile-video` | `DeesTileVideo` | Auto-captured first frame, duration badge, hover muted auto-preview | +| `dees-tile-note` | `DeesTileNote` | First ~12 lines of text in monospace, gradient fade, optional language badge | +| `dees-tile-folder` | `DeesTileFolder` | 2×2 grid of mini-previews (thumbnails or type icons), item count badge | + +### Deprecations + +- `dees-pdf-preview` → Use `dees-tile-pdf` instead. Old tag still works as a thin wrapper with console warning. +- `dees-pdf` deprecation comment updated to reference `DeesTilePdf`. + +### File Structure + +All tile components live in `ts_web/elements/00group-media/dees-tile-*/`: +- `component.ts` — Main component class +- `demo.ts` — Demo function +- `index.ts` — Re-export +- `styles.ts` — (PDF tile only) Component-specific styles +- Shared base: `dees-tile-shared/{DeesTileBase,styles,index}.ts` + +### Interface: ITileFolderItem +```typescript +interface ITileFolderItem { + type: 'pdf' | 'image' | 'audio' | 'video' | 'note' | 'folder' | 'unknown'; + thumbnailSrc?: string; + name: string; +} +``` + ## StatsGrid Enhancements (2026-01-12) ### Column Spanning @@ -973,4 +1060,51 @@ Features: - `trend` - Sparkline with recent data - `text` - Text value display - `multiPercentage` - Multiple progress bars -- `cpuCores` - Vertical bar visualization for CPU cores \ No newline at end of file +- `cpuCores` - Vertical bar visualization for CPU cores + +## Component Group Taxonomy (2026-01-27) + +All components are organized into `00group-*` directories with 14 groups visible in the wcctools sidebar. The `demoGroups` property (plural, `string[]`) replaces the old `demoGroup` (singular). Components can belong to multiple groups. + +### Group Directories +| Directory | Group Name | Count | +|-----------|-----------|-------| +| `00group-appui` | App UI | 10 | +| `00group-button` | Button | 3 | +| `00group-chart` | Chart | 2 | +| `00group-dataview` | Data View | 4 | +| `00group-feedback` | Feedback | 6 | +| `00group-form` | Form | 2 | +| `00group-input` | Input | 18 | +| `00group-layout` | Layout | 7 | +| `00group-media` | Media | 14 (viewers + PDF + tiles) | +| `00group-overlay` | Overlay | 4 | +| `00group-simple` | Simple | 3 | +| `00group-utility` | Utility | 5 | +| `00group-workspace` | Workspace | 9 | +| `00group-runtime` | (internal) | - | + +### Multi-Group Components +Some components appear in multiple groups via `demoGroups = ['Primary', 'Secondary']`: +- `dees-chart-log`: Chart, Workspace +- `dees-dataview-codebox`: Data View, Workspace +- `dees-input-code`: Input, Workspace +- `dees-input-wysiwyg`: Input, Workspace +- `dees-form-submit`: Form, Button +- `dees-preview`: Media, Data View +- `dees-pdf*` / `dees-tile-pdf`: Media, PDF +- `dees-stepper`: Layout, Form +- `dees-label`: Layout, Input +- `dees-toast`: Feedback, Overlay +- `dees-actionbar`: Feedback, Overlay + +### Import Conventions +- Within same group: `import '../sibling-component/file.js'` +- Cross-group (from depth-2): `import '../../00group-X/component/file.js'` +- Shared utilities: `import '../../00plugins.js'`, `import '../../00theme.js'`, etc. + +### Key Notes +- The old `demoGroup` property (singular, string) is fully removed +- All 79 components with demos use `demoGroups` (plural, string[]) +- `00group-pdf` no longer exists; PDF components are in `00group-media` +- `dees-search` and `dees-tooltip` remain standalone (no demos) \ No newline at end of file diff --git a/ts_web/00_commitinfo_data.ts b/ts_web/00_commitinfo_data.ts index e2a5298..5bc68ab 100644 --- a/ts_web/00_commitinfo_data.ts +++ b/ts_web/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@design.estate/dees-catalog', - version: '3.38.0', + version: '3.39.0', description: 'A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.' } diff --git a/ts_web/elements/00group-appui/dees-appui-activitylog/dees-appui-activitylog.ts b/ts_web/elements/00group-appui/dees-appui-activitylog/dees-appui-activitylog.ts index b5ae9e3..7d27398 100644 --- a/ts_web/elements/00group-appui/dees-appui-activitylog/dees-appui-activitylog.ts +++ b/ts_web/elements/00group-appui/dees-appui-activitylog/dees-appui-activitylog.ts @@ -10,8 +10,8 @@ import { } from '@design.estate/dees-element'; import * as domtools from '@design.estate/dees-domtools'; -import { DeesContextmenu } from '../../dees-contextmenu/dees-contextmenu.js'; -import '../../dees-icon/dees-icon.js'; +import { DeesContextmenu } from '../../00group-overlay/dees-contextmenu/dees-contextmenu.js'; +import '../../00group-utility/dees-icon/dees-icon.js'; import type { IActivityEntry, IActivityLogAPI } from '../../interfaces/appconfig.js'; import { demoFunc } from './dees-appui-activitylog.demo.js'; import { themeDefaultStyles } from '../../00theme.js'; @@ -20,7 +20,7 @@ import { themeDefaultStyles } from '../../00theme.js'; export class DeesAppuiActivitylog extends DeesElement implements IActivityLogAPI { // STATIC public static demo = demoFunc; - public static demoGroup = 'App UI'; + public static demoGroups = ['App UI']; // INSTANCE PROPERTIES @state() diff --git a/ts_web/elements/00group-appui/dees-appui-appbar/component.ts b/ts_web/elements/00group-appui/dees-appui-appbar/component.ts index 711ebf7..0c01bc4 100644 --- a/ts_web/elements/00group-appui/dees-appui-appbar/component.ts +++ b/ts_web/elements/00group-appui/dees-appui-appbar/component.ts @@ -15,8 +15,8 @@ import { appuiAppbarStyles } from './styles.js'; import { renderAppuiAppbar } from './template.js'; // Import required components -import '../../dees-icon/dees-icon.js'; -import '../../dees-windowcontrols/dees-windowcontrols.js'; +import '../../00group-utility/dees-icon/dees-icon.js'; +import '../../00group-utility/dees-windowcontrols/dees-windowcontrols.js'; import '../dees-appui-profiledropdown/dees-appui-profiledropdown.js'; declare global { @@ -28,7 +28,7 @@ declare global { @customElement('dees-appui-appbar') export class DeesAppuiBar extends DeesElement { public static demo = demoFunc; - public static demoGroup = 'App UI'; + public static demoGroups = ['App UI']; // INSTANCE PROPERTIES @property({ type: Array }) diff --git a/ts_web/elements/00group-appui/dees-appui-bottombar/dees-appui-bottombar.ts b/ts_web/elements/00group-appui/dees-appui-bottombar/dees-appui-bottombar.ts index 8f47df0..6ab1f70 100644 --- a/ts_web/elements/00group-appui/dees-appui-bottombar/dees-appui-bottombar.ts +++ b/ts_web/elements/00group-appui/dees-appui-bottombar/dees-appui-bottombar.ts @@ -8,8 +8,8 @@ import { state, } from '@design.estate/dees-element'; import { themeDefaultStyles } from '../../00theme.js'; -import '../../dees-icon/dees-icon.js'; -import { DeesContextmenu } from '../../dees-contextmenu/dees-contextmenu.js'; +import '../../00group-utility/dees-icon/dees-icon.js'; +import { DeesContextmenu } from '../../00group-overlay/dees-contextmenu/dees-contextmenu.js'; import type { IBottomBarWidget, IBottomBarAction, @@ -26,7 +26,7 @@ declare global { @customElement('dees-appui-bottombar') export class DeesAppuiBottombar extends DeesElement implements IBottomBarAPI { public static demo = demoFunc; - public static demoGroup = 'App UI'; + public static demoGroups = ['App UI']; // INSTANCE PROPERTIES @state() diff --git a/ts_web/elements/00group-appui/dees-appui-maincontent/dees-appui-maincontent.ts b/ts_web/elements/00group-appui/dees-appui-maincontent/dees-appui-maincontent.ts index adc6934..f3c3fad 100644 --- a/ts_web/elements/00group-appui/dees-appui-maincontent/dees-appui-maincontent.ts +++ b/ts_web/elements/00group-appui/dees-appui-maincontent/dees-appui-maincontent.ts @@ -31,7 +31,7 @@ export class DeesAppuiMaincontent extends DeesElement { `; - public static demoGroup = 'App UI'; + public static demoGroups = ['App UI']; // INSTANCE @property({ diff --git a/ts_web/elements/00group-appui/dees-appui-mainmenu/dees-appui-mainmenu.ts b/ts_web/elements/00group-appui/dees-appui-mainmenu/dees-appui-mainmenu.ts index c06b724..c17ce7f 100644 --- a/ts_web/elements/00group-appui/dees-appui-mainmenu/dees-appui-mainmenu.ts +++ b/ts_web/elements/00group-appui/dees-appui-mainmenu/dees-appui-mainmenu.ts @@ -11,7 +11,7 @@ import { css, cssManager, } from '@design.estate/dees-element'; -import { DeesContextmenu } from '../../dees-contextmenu/dees-contextmenu.js'; +import { DeesContextmenu } from '../../00group-overlay/dees-contextmenu/dees-contextmenu.js'; import { demoFunc } from './dees-appui-mainmenu.demo.js'; import { themeDefaultStyles } from '../../00theme.js'; @@ -22,7 +22,7 @@ import { themeDefaultStyles } from '../../00theme.js'; @customElement('dees-appui-mainmenu') export class DeesAppuiMainmenu extends DeesElement { public static demo = demoFunc; - public static demoGroup = 'App UI'; + public static demoGroups = ['App UI']; // INSTANCE diff --git a/ts_web/elements/00group-appui/dees-appui-profiledropdown/dees-appui-profiledropdown.ts b/ts_web/elements/00group-appui/dees-appui-profiledropdown/dees-appui-profiledropdown.ts index 3572ae8..87ee80b 100644 --- a/ts_web/elements/00group-appui/dees-appui-profiledropdown/dees-appui-profiledropdown.ts +++ b/ts_web/elements/00group-appui/dees-appui-profiledropdown/dees-appui-profiledropdown.ts @@ -35,7 +35,7 @@ export class DeesAppuiProfileDropdown extends DeesElement { .isOpen=${true} > `; - public static demoGroup = 'App UI'; + public static demoGroups = ['App UI']; @property({ type: Object }) accessor user: { diff --git a/ts_web/elements/00group-appui/dees-appui-secondarymenu/dees-appui-secondarymenu.ts b/ts_web/elements/00group-appui/dees-appui-secondarymenu/dees-appui-secondarymenu.ts index e43450e..a5b4394 100644 --- a/ts_web/elements/00group-appui/dees-appui-secondarymenu/dees-appui-secondarymenu.ts +++ b/ts_web/elements/00group-appui/dees-appui-secondarymenu/dees-appui-secondarymenu.ts @@ -1,8 +1,8 @@ import * as plugins from '../../00plugins.js'; import * as interfaces from '../../interfaces/index.js'; -import { DeesContextmenu } from '../../dees-contextmenu/dees-contextmenu.js'; -import '../../dees-icon/dees-icon.js'; +import { DeesContextmenu } from '../../00group-overlay/dees-contextmenu/dees-contextmenu.js'; +import '../../00group-utility/dees-icon/dees-icon.js'; import { DeesElement, @@ -33,7 +33,7 @@ import { themeDefaultStyles } from '../../00theme.js'; @customElement('dees-appui-secondarymenu') export class DeesAppuiSecondarymenu extends DeesElement { public static demo = demoFunc; - public static demoGroup = 'App UI'; + public static demoGroups = ['App UI']; // INSTANCE diff --git a/ts_web/elements/00group-appui/dees-appui-tabs/dees-appui-tabs.ts b/ts_web/elements/00group-appui/dees-appui-tabs/dees-appui-tabs.ts index 2fd3f8a..37d2de7 100644 --- a/ts_web/elements/00group-appui/dees-appui-tabs/dees-appui-tabs.ts +++ b/ts_web/elements/00group-appui/dees-appui-tabs/dees-appui-tabs.ts @@ -18,7 +18,7 @@ import { themeDefaultStyles } from '../../00theme.js'; @customElement('dees-appui-tabs') export class DeesAppuiTabs extends DeesElement { public static demo = demoFunc; - public static demoGroup = 'App UI'; + public static demoGroups = ['App UI']; // INSTANCE @property({ diff --git a/ts_web/elements/00group-appui/dees-appui/dees-appui.demo.ts b/ts_web/elements/00group-appui/dees-appui/dees-appui.demo.ts index 2d7d702..e937338 100644 --- a/ts_web/elements/00group-appui/dees-appui/dees-appui.demo.ts +++ b/ts_web/elements/00group-appui/dees-appui/dees-appui.demo.ts @@ -3,8 +3,8 @@ import type { DeesAppui } from './dees-appui.js'; import type { IAppConfig, IViewActivationContext } from '../../interfaces/appconfig.js'; import type * as interfaces from '../../interfaces/index.js'; import '@design.estate/dees-wcctools/demotools'; -import '../../dees-statsgrid/dees-statsgrid.js'; -import type { IStatsTile } from '../../dees-statsgrid/dees-statsgrid.js'; +import '../../00group-dataview/dees-statsgrid/dees-statsgrid.js'; +import type { IStatsTile } from '../../00group-dataview/dees-statsgrid/dees-statsgrid.js'; // Demo view component with lifecycle hooks @customElement('demo-dashboard-view') diff --git a/ts_web/elements/00group-appui/dees-appui/dees-appui.ts b/ts_web/elements/00group-appui/dees-appui/dees-appui.ts index 1428eda..84a64cb 100644 --- a/ts_web/elements/00group-appui/dees-appui/dees-appui.ts +++ b/ts_web/elements/00group-appui/dees-appui/dees-appui.ts @@ -39,7 +39,7 @@ declare global { @customElement('dees-appui') export class DeesAppui extends DeesElement { public static demo = demoFunc; - public static demoGroup = 'App UI'; + public static demoGroups = ['App UI']; // ========================================== // REACTIVE OBSERVABLES (RxJS Subjects) diff --git a/ts_web/elements/dees-mobilenavigation/dees-mobilenavigation.demo.ts b/ts_web/elements/00group-appui/dees-mobilenavigation/dees-mobilenavigation.demo.ts similarity index 99% rename from ts_web/elements/dees-mobilenavigation/dees-mobilenavigation.demo.ts rename to ts_web/elements/00group-appui/dees-mobilenavigation/dees-mobilenavigation.demo.ts index b115c0e..4299e1d 100644 --- a/ts_web/elements/dees-mobilenavigation/dees-mobilenavigation.demo.ts +++ b/ts_web/elements/00group-appui/dees-mobilenavigation/dees-mobilenavigation.demo.ts @@ -1,6 +1,6 @@ import { html, css } from '@design.estate/dees-element'; import '../00group-button/dees-button/dees-button.js'; -import '../dees-panel/dees-panel.js'; +import '../../00group-layout/dees-panel/dees-panel.js'; import '@design.estate/dees-wcctools/demotools'; export const demoFunc = () => html` diff --git a/ts_web/elements/dees-mobilenavigation/dees-mobilenavigation.ts b/ts_web/elements/00group-appui/dees-mobilenavigation/dees-mobilenavigation.ts similarity index 95% rename from ts_web/elements/dees-mobilenavigation/dees-mobilenavigation.ts rename to ts_web/elements/00group-appui/dees-mobilenavigation/dees-mobilenavigation.ts index 15eb0f4..067e60d 100644 --- a/ts_web/elements/dees-mobilenavigation/dees-mobilenavigation.ts +++ b/ts_web/elements/00group-appui/dees-mobilenavigation/dees-mobilenavigation.ts @@ -1,6 +1,6 @@ -import * as plugins from '../00plugins.js'; -import { zIndexRegistry } from '../00zindex.js'; -import { cssGeistFontFamily } from '../00fonts.js'; +import * as plugins from '../../00plugins.js'; +import { zIndexRegistry } from '../../00zindex.js'; +import { cssGeistFontFamily } from '../../00fonts.js'; import { cssManager, css, @@ -12,13 +12,14 @@ import { property, state, } from '@design.estate/dees-element'; -import { DeesWindowLayer } from '../dees-windowlayer/dees-windowlayer.js'; -import '../dees-icon/dees-icon.js'; -import { themeDefaultStyles } from '../00theme.js'; +import { DeesWindowLayer } from '../../00group-overlay/dees-windowlayer/dees-windowlayer.js'; +import '../../00group-utility/dees-icon/dees-icon.js'; +import { themeDefaultStyles } from '../../00theme.js'; @customElement('dees-mobilenavigation') export class DeesMobilenavigation extends DeesElement { // STATIC + public static demoGroups = ['App UI']; public static demo = () => html` { DeesMobilenavigation.createAndShow([ diff --git a/ts_web/elements/dees-mobilenavigation/index.ts b/ts_web/elements/00group-appui/dees-mobilenavigation/index.ts similarity index 100% rename from ts_web/elements/dees-mobilenavigation/index.ts rename to ts_web/elements/00group-appui/dees-mobilenavigation/index.ts diff --git a/ts_web/elements/00group-appui/index.ts b/ts_web/elements/00group-appui/index.ts index ea656f4..443a37a 100644 --- a/ts_web/elements/00group-appui/index.ts +++ b/ts_web/elements/00group-appui/index.ts @@ -8,3 +8,4 @@ export * from './dees-appui-mainmenu/index.js'; export * from './dees-appui-secondarymenu/index.js'; export * from './dees-appui-profiledropdown/index.js'; export * from './dees-appui-tabs/index.js'; +export * from './dees-mobilenavigation/index.js'; diff --git a/ts_web/elements/00group-button/dees-button-exit/dees-button-exit.ts b/ts_web/elements/00group-button/dees-button-exit/dees-button-exit.ts index b903fc1..7a1b172 100644 --- a/ts_web/elements/00group-button/dees-button-exit/dees-button-exit.ts +++ b/ts_web/elements/00group-button/dees-button-exit/dees-button-exit.ts @@ -16,7 +16,7 @@ export class DeesButtonExit extends DeesElement { public static demo = () => html` `; - public static demoGroup = 'Button'; + public static demoGroups = ['Button']; // INSTANCE @property({ diff --git a/ts_web/elements/00group-button/dees-button-group/dees-button-group.ts b/ts_web/elements/00group-button/dees-button-group/dees-button-group.ts index 8ad6cb6..6667931 100644 --- a/ts_web/elements/00group-button/dees-button-group/dees-button-group.ts +++ b/ts_web/elements/00group-button/dees-button-group/dees-button-group.ts @@ -21,7 +21,7 @@ declare global { @customElement('dees-button-group') export class DeesButtonGroup extends DeesElement { public static demo = demoFunc; - public static demoGroup = 'Button'; + public static demoGroups = ['Button']; @property() accessor label: string = ''; diff --git a/ts_web/elements/00group-button/dees-button/dees-button.demo.ts b/ts_web/elements/00group-button/dees-button/dees-button.demo.ts index 7e5e44f..9457baf 100644 --- a/ts_web/elements/00group-button/dees-button/dees-button.demo.ts +++ b/ts_web/elements/00group-button/dees-button/dees-button.demo.ts @@ -1,10 +1,10 @@ import { html, css, cssManager, domtools } from '@design.estate/dees-element'; import '@design.estate/dees-wcctools/demotools'; -import '../../dees-panel/dees-panel.js'; +import '../../00group-layout/dees-panel/dees-panel.js'; import '../../00group-form/dees-form/dees-form.js'; import '../../00group-form/dees-form-submit/dees-form-submit.js'; import '../../00group-input/dees-input-text/dees-input-text.js'; -import '../../dees-icon/dees-icon.js'; +import '../../00group-utility/dees-icon/dees-icon.js'; import type { DeesButton } from '../dees-button/dees-button.js'; export const demoFunc = () => html` diff --git a/ts_web/elements/00group-button/dees-button/dees-button.ts b/ts_web/elements/00group-button/dees-button/dees-button.ts index b45913f..76a94b9 100644 --- a/ts_web/elements/00group-button/dees-button/dees-button.ts +++ b/ts_web/elements/00group-button/dees-button/dees-button.ts @@ -23,7 +23,7 @@ declare global { @customElement('dees-button') export class DeesButton extends DeesElement { public static demo = demoFunc; - public static demoGroup = 'Button'; + public static demoGroups = ['Button']; @property({ reflect: true, diff --git a/ts_web/elements/00group-chart/dees-chart-area/component.ts b/ts_web/elements/00group-chart/dees-chart-area/component.ts index 9f345e4..a7df1f9 100644 --- a/ts_web/elements/00group-chart/dees-chart-area/component.ts +++ b/ts_web/elements/00group-chart/dees-chart-area/component.ts @@ -23,7 +23,7 @@ declare global { @customElement('dees-chart-area') export class DeesChartArea extends DeesElement { public static demo = demoFunc; - public static demoGroup = 'Chart'; + public static demoGroups = ['Chart']; // instance @state() diff --git a/ts_web/elements/00group-chart/dees-chart-log/dees-chart-log.ts b/ts_web/elements/00group-chart/dees-chart-log/dees-chart-log.ts index 8d85bc0..0786a37 100644 --- a/ts_web/elements/00group-chart/dees-chart-log/dees-chart-log.ts +++ b/ts_web/elements/00group-chart/dees-chart-log/dees-chart-log.ts @@ -44,7 +44,7 @@ export interface ILogMetrics { @customElement('dees-chart-log') export class DeesChartLog extends DeesElement { public static demo = demoFunc; - public static demoGroup = 'Chart'; + public static demoGroups = ['Chart', 'Workspace']; @property() accessor label: string = 'Server Logs'; diff --git a/ts_web/elements/00group-dataview/dees-dataview-codebox/dees-dataview-codebox.ts b/ts_web/elements/00group-dataview/dees-dataview-codebox/dees-dataview-codebox.ts index 2504468..b430b0d 100644 --- a/ts_web/elements/00group-dataview/dees-dataview-codebox/dees-dataview-codebox.ts +++ b/ts_web/elements/00group-dataview/dees-dataview-codebox/dees-dataview-codebox.ts @@ -15,7 +15,7 @@ import type { HLJSApi } from 'highlight.js'; import * as smartstring from '@push.rocks/smartstring'; import * as domtools from '@design.estate/dees-domtools'; -import { DeesContextmenu } from '../../dees-contextmenu/dees-contextmenu.js'; +import { DeesContextmenu } from '../../00group-overlay/dees-contextmenu/dees-contextmenu.js'; import { DeesServiceLibLoader } from '../../../services/index.js'; declare global { @@ -27,7 +27,7 @@ declare global { @customElement('dees-dataview-codebox') export class DeesDataviewCodebox extends DeesElement { public static demo = demoFunc; - public static demoGroup = 'Data View'; + public static demoGroups = ['Data View', 'Workspace']; @property() accessor progLang: string = 'typescript'; @@ -206,9 +206,7 @@ export class DeesDataviewCodebox extends DeesElement { }}" >
-
index.ts
-
diff --git a/ts_web/elements/00group-dataview/dees-dataview-statusobject/dees-dataview-statusobject.ts b/ts_web/elements/00group-dataview/dees-dataview-statusobject/dees-dataview-statusobject.ts index eff224d..da2312d 100644 --- a/ts_web/elements/00group-dataview/dees-dataview-statusobject/dees-dataview-statusobject.ts +++ b/ts_web/elements/00group-dataview/dees-dataview-statusobject/dees-dataview-statusobject.ts @@ -15,7 +15,7 @@ import { } from '@design.estate/dees-element'; import * as tsclass from '@tsclass/tsclass'; -import { DeesContextmenu } from '../../dees-contextmenu/dees-contextmenu.js'; +import { DeesContextmenu } from '../../00group-overlay/dees-contextmenu/dees-contextmenu.js'; import { themeDefaultStyles } from '../../00theme.js'; declare global { @@ -27,7 +27,7 @@ declare global { @customElement('dees-dataview-statusobject') export class DeesDataviewStatusobject extends DeesElement { public static demo = demoFunc; - public static demoGroup = 'Data View'; + public static demoGroups = ['Data View']; @property({ type: Object }) accessor statusObject: tsclass.code.IStatusObject; diff --git a/ts_web/elements/dees-statsgrid/dees-statsgrid.demo.ts b/ts_web/elements/00group-dataview/dees-statsgrid/dees-statsgrid.demo.ts similarity index 99% rename from ts_web/elements/dees-statsgrid/dees-statsgrid.demo.ts rename to ts_web/elements/00group-dataview/dees-statsgrid/dees-statsgrid.demo.ts index 405c812..ba8614c 100644 --- a/ts_web/elements/dees-statsgrid/dees-statsgrid.demo.ts +++ b/ts_web/elements/00group-dataview/dees-statsgrid/dees-statsgrid.demo.ts @@ -1,6 +1,6 @@ import { html, css, cssManager } from '@design.estate/dees-element'; import '@design.estate/dees-wcctools/demotools'; -import '../dees-panel/dees-panel.js'; +import '../../00group-layout/dees-panel/dees-panel.js'; import type { IStatsTile, ICpuCore, IPartitionData, IDiskData } from '../dees-statsgrid/dees-statsgrid.js'; // Helper function to generate random CPU core data diff --git a/ts_web/elements/dees-statsgrid/dees-statsgrid.ts b/ts_web/elements/00group-dataview/dees-statsgrid/dees-statsgrid.ts similarity index 98% rename from ts_web/elements/dees-statsgrid/dees-statsgrid.ts rename to ts_web/elements/00group-dataview/dees-statsgrid/dees-statsgrid.ts index d3ec12f..091ef64 100644 --- a/ts_web/elements/dees-statsgrid/dees-statsgrid.ts +++ b/ts_web/elements/00group-dataview/dees-statsgrid/dees-statsgrid.ts @@ -1,6 +1,6 @@ import { demoFunc } from './dees-statsgrid.demo.js'; -import * as plugins from '../00plugins.js'; -import { cssGeistFontFamily } from '../00fonts.js'; +import * as plugins from '../../00plugins.js'; +import { cssGeistFontFamily } from '../../00fonts.js'; import { customElement, html, @@ -13,10 +13,10 @@ import { } from '@design.estate/dees-element'; import type { TemplateResult } from '@design.estate/dees-element'; -import '../dees-icon/dees-icon.js'; -import '../dees-contextmenu/dees-contextmenu.js'; -import '../00group-button/dees-button/dees-button.js'; -import { themeDefaultStyles } from '../00theme.js'; +import '../../00group-utility/dees-icon/dees-icon.js'; +import '../../00group-overlay/dees-contextmenu/dees-contextmenu.js'; +import '../../00group-button/dees-button/dees-button.js'; +import { themeDefaultStyles } from '../../00theme.js'; declare global { interface HTMLElementTagNameMap { @@ -96,6 +96,7 @@ export interface IStatsTile { @customElement('dees-statsgrid') export class DeesStatsGrid extends DeesElement { public static demo = demoFunc; + public static demoGroups = ['Data View']; @property({ type: Array }) accessor tiles: IStatsTile[] = []; diff --git a/ts_web/elements/dees-statsgrid/index.ts b/ts_web/elements/00group-dataview/dees-statsgrid/index.ts similarity index 100% rename from ts_web/elements/dees-statsgrid/index.ts rename to ts_web/elements/00group-dataview/dees-statsgrid/index.ts diff --git a/ts_web/elements/dees-table/data.ts b/ts_web/elements/00group-dataview/dees-table/data.ts similarity index 100% rename from ts_web/elements/dees-table/data.ts rename to ts_web/elements/00group-dataview/dees-table/data.ts diff --git a/ts_web/elements/dees-table/dees-table.demo.ts b/ts_web/elements/00group-dataview/dees-table/dees-table.demo.ts similarity index 99% rename from ts_web/elements/dees-table/dees-table.demo.ts rename to ts_web/elements/00group-dataview/dees-table/dees-table.demo.ts index ae70cb9..776f5cd 100644 --- a/ts_web/elements/dees-table/dees-table.demo.ts +++ b/ts_web/elements/00group-dataview/dees-table/dees-table.demo.ts @@ -1,5 +1,5 @@ import { type ITableAction } from './dees-table.js'; -import * as plugins from '../00plugins.js'; +import * as plugins from '../../00plugins.js'; import { html, css, cssManager } from '@design.estate/dees-element'; interface ITableDemoData { diff --git a/ts_web/elements/dees-table/dees-table.ts b/ts_web/elements/00group-dataview/dees-table/dees-table.ts similarity index 98% rename from ts_web/elements/dees-table/dees-table.ts rename to ts_web/elements/00group-dataview/dees-table/dees-table.ts index d5ba7ae..0fce470 100644 --- a/ts_web/elements/dees-table/dees-table.ts +++ b/ts_web/elements/00group-dataview/dees-table/dees-table.ts @@ -1,10 +1,10 @@ -import * as plugins from '../00plugins.js'; +import * as plugins from '../../00plugins.js'; import { demoFunc } from './dees-table.demo.js'; import { customElement, html, DeesElement, property, type TemplateResult, directives } from '@design.estate/dees-element'; -import { DeesContextmenu } from '../dees-contextmenu/dees-contextmenu.js'; +import { DeesContextmenu } from '../../00group-overlay/dees-contextmenu/dees-contextmenu.js'; import * as domtools from '@design.estate/dees-domtools'; -import { type TIconKey } from '../dees-icon/dees-icon.js'; +import { type TIconKey } from '../../00group-utility/dees-icon/dees-icon.js'; import { tableStyles } from './styles.js'; import type { Column, ITableAction, ITableActionDataArg, TDisplayFunction } from './types.js'; import { @@ -14,7 +14,7 @@ import { getViewData as getViewDataFn, } from './data.js'; import { compileLucenePredicate } from './lucene.js'; -import { themeDefaultStyles } from '../00theme.js'; +import { themeDefaultStyles } from '../../00theme.js'; export type { Column, ITableAction, ITableActionDataArg, TDisplayFunction } from './types.js'; @@ -30,6 +30,7 @@ declare global { @customElement('dees-table') export class DeesTable extends DeesElement { public static demo = demoFunc; + public static demoGroups = ['Data View']; // INSTANCE @property({ diff --git a/ts_web/elements/dees-table/index.ts b/ts_web/elements/00group-dataview/dees-table/index.ts similarity index 100% rename from ts_web/elements/dees-table/index.ts rename to ts_web/elements/00group-dataview/dees-table/index.ts diff --git a/ts_web/elements/dees-table/lucene.ts b/ts_web/elements/00group-dataview/dees-table/lucene.ts similarity index 100% rename from ts_web/elements/dees-table/lucene.ts rename to ts_web/elements/00group-dataview/dees-table/lucene.ts diff --git a/ts_web/elements/dees-table/styles.ts b/ts_web/elements/00group-dataview/dees-table/styles.ts similarity index 99% rename from ts_web/elements/dees-table/styles.ts rename to ts_web/elements/00group-dataview/dees-table/styles.ts index fd00544..973e5d0 100644 --- a/ts_web/elements/dees-table/styles.ts +++ b/ts_web/elements/00group-dataview/dees-table/styles.ts @@ -1,6 +1,6 @@ import { cssManager, css, type CSSResult } from '@design.estate/dees-element'; -import { cssGeistFontFamily } from '../00fonts.js'; -import { themeDefaultStyles } from '../00theme.js'; +import { cssGeistFontFamily } from '../../00fonts.js'; +import { themeDefaultStyles } from '../../00theme.js'; export const tableStyles: CSSResult[] = [ themeDefaultStyles, diff --git a/ts_web/elements/dees-table/types.ts b/ts_web/elements/00group-dataview/dees-table/types.ts similarity index 93% rename from ts_web/elements/dees-table/types.ts rename to ts_web/elements/00group-dataview/dees-table/types.ts index b8de681..a77a2fc 100644 --- a/ts_web/elements/dees-table/types.ts +++ b/ts_web/elements/00group-dataview/dees-table/types.ts @@ -1,5 +1,5 @@ import type { TemplateResult } from '@design.estate/dees-element'; -import type { TIconKey } from '../dees-icon/dees-icon.js'; +import type { TIconKey } from '../../00group-utility/dees-icon/dees-icon.js'; export interface ITableActionDataArg { item: T; diff --git a/ts_web/elements/00group-dataview/index.ts b/ts_web/elements/00group-dataview/index.ts index 03dd1ac..5791f42 100644 --- a/ts_web/elements/00group-dataview/index.ts +++ b/ts_web/elements/00group-dataview/index.ts @@ -1,3 +1,5 @@ // Data View Components export * from './dees-dataview-codebox/index.js'; export * from './dees-dataview-statusobject/index.js'; +export * from './dees-table/index.js'; +export * from './dees-statsgrid/index.js'; diff --git a/ts_web/elements/dees-actionbar/actionbar.interfaces.ts b/ts_web/elements/00group-feedback/dees-actionbar/actionbar.interfaces.ts similarity index 100% rename from ts_web/elements/dees-actionbar/actionbar.interfaces.ts rename to ts_web/elements/00group-feedback/dees-actionbar/actionbar.interfaces.ts diff --git a/ts_web/elements/dees-actionbar/dees-actionbar.ts b/ts_web/elements/00group-feedback/dees-actionbar/dees-actionbar.ts similarity index 98% rename from ts_web/elements/dees-actionbar/dees-actionbar.ts rename to ts_web/elements/00group-feedback/dees-actionbar/dees-actionbar.ts index c73a6eb..8e87374 100644 --- a/ts_web/elements/dees-actionbar/dees-actionbar.ts +++ b/ts_web/elements/00group-feedback/dees-actionbar/dees-actionbar.ts @@ -7,8 +7,8 @@ import { state, cssManager, } from '@design.estate/dees-element'; -import { themeDefaultStyles } from '../00theme.js'; -import '../dees-icon/dees-icon.js'; +import { themeDefaultStyles } from '../../00theme.js'; +import '../../00group-utility/dees-icon/dees-icon.js'; import type { IActionBarOptions, IActionBarResult, @@ -25,6 +25,7 @@ declare global { @customElement('dees-actionbar') export class DeesActionbar extends DeesElement { // STATIC + public static demoGroups = ['Feedback', 'Overlay']; public static demo = () => { const getActionbar = (e: Event) => { const button = e.currentTarget as HTMLElement; diff --git a/ts_web/elements/dees-actionbar/index.ts b/ts_web/elements/00group-feedback/dees-actionbar/index.ts similarity index 100% rename from ts_web/elements/dees-actionbar/index.ts rename to ts_web/elements/00group-feedback/dees-actionbar/index.ts diff --git a/ts_web/elements/dees-badge/dees-badge.demo.ts b/ts_web/elements/00group-feedback/dees-badge/dees-badge.demo.ts similarity index 100% rename from ts_web/elements/dees-badge/dees-badge.demo.ts rename to ts_web/elements/00group-feedback/dees-badge/dees-badge.demo.ts diff --git a/ts_web/elements/dees-badge/dees-badge.ts b/ts_web/elements/00group-feedback/dees-badge/dees-badge.ts similarity index 95% rename from ts_web/elements/dees-badge/dees-badge.ts rename to ts_web/elements/00group-feedback/dees-badge/dees-badge.ts index d430205..d3e5809 100644 --- a/ts_web/elements/dees-badge/dees-badge.ts +++ b/ts_web/elements/00group-feedback/dees-badge/dees-badge.ts @@ -11,7 +11,7 @@ import { import * as domtools from '@design.estate/dees-domtools'; import { demoFunc } from './dees-badge.demo.js'; -import { themeDefaultStyles } from '../00theme.js'; +import { themeDefaultStyles } from '../../00theme.js'; declare global { interface HTMLElementTagNameMap { @@ -22,6 +22,7 @@ declare global { @customElement('dees-badge') export class DeesBadge extends DeesElement { public static demo = demoFunc; + public static demoGroups = ['Feedback']; @property({ type: String }) accessor type: 'default' | 'primary' | 'success' | 'warning' | 'error' = 'default'; diff --git a/ts_web/elements/dees-badge/index.ts b/ts_web/elements/00group-feedback/dees-badge/index.ts similarity index 100% rename from ts_web/elements/dees-badge/index.ts rename to ts_web/elements/00group-feedback/dees-badge/index.ts diff --git a/ts_web/elements/dees-hint/dees-hint.demo.ts b/ts_web/elements/00group-feedback/dees-hint/dees-hint.demo.ts similarity index 100% rename from ts_web/elements/dees-hint/dees-hint.demo.ts rename to ts_web/elements/00group-feedback/dees-hint/dees-hint.demo.ts diff --git a/ts_web/elements/dees-hint/dees-hint.ts b/ts_web/elements/00group-feedback/dees-hint/dees-hint.ts similarity index 89% rename from ts_web/elements/dees-hint/dees-hint.ts rename to ts_web/elements/00group-feedback/dees-hint/dees-hint.ts index 7ec728b..3d2a0e7 100644 --- a/ts_web/elements/dees-hint/dees-hint.ts +++ b/ts_web/elements/00group-feedback/dees-hint/dees-hint.ts @@ -11,7 +11,7 @@ import { import * as domtools from '@design.estate/dees-domtools'; import { demoFunc } from './dees-hint.demo.js'; -import { themeDefaultStyles } from '../00theme.js'; +import { themeDefaultStyles } from '../../00theme.js'; declare global { interface HTMLElementTagNameMap { @@ -22,6 +22,7 @@ declare global { @customElement('dees-hint') export class DeesHint extends DeesElement { public static demo = demoFunc; + public static demoGroups = ['Feedback']; @property({ type: String }) accessor type: 'info' | 'warn' | 'error' | 'critical' = 'info'; diff --git a/ts_web/elements/dees-hint/index.ts b/ts_web/elements/00group-feedback/dees-hint/index.ts similarity index 100% rename from ts_web/elements/dees-hint/index.ts rename to ts_web/elements/00group-feedback/dees-hint/index.ts diff --git a/ts_web/elements/dees-progressbar/dees-progressbar.demo.ts b/ts_web/elements/00group-feedback/dees-progressbar/dees-progressbar.demo.ts similarity index 100% rename from ts_web/elements/dees-progressbar/dees-progressbar.demo.ts rename to ts_web/elements/00group-feedback/dees-progressbar/dees-progressbar.demo.ts diff --git a/ts_web/elements/dees-progressbar/dees-progressbar.ts b/ts_web/elements/00group-feedback/dees-progressbar/dees-progressbar.ts similarity index 92% rename from ts_web/elements/dees-progressbar/dees-progressbar.ts rename to ts_web/elements/00group-feedback/dees-progressbar/dees-progressbar.ts index 1958835..66345f8 100644 --- a/ts_web/elements/dees-progressbar/dees-progressbar.ts +++ b/ts_web/elements/00group-feedback/dees-progressbar/dees-progressbar.ts @@ -1,5 +1,5 @@ -import * as plugins from '../00plugins.js'; -import * as colors from '../00colors.js'; +import * as plugins from '../../00plugins.js'; +import * as colors from '../../00colors.js'; import { demoFunc } from './dees-progressbar.demo.js'; import { customElement, @@ -16,12 +16,13 @@ import { } from '@design.estate/dees-element'; import * as domtools from '@design.estate/dees-domtools'; -import { themeDefaultStyles } from '../00theme.js'; +import { themeDefaultStyles } from '../../00theme.js'; @customElement('dees-progressbar') export class DeesProgressbar extends DeesElement { // STATIC public static demo = demoFunc; + public static demoGroups = ['Feedback']; // INSTANCE @property({ diff --git a/ts_web/elements/dees-progressbar/index.ts b/ts_web/elements/00group-feedback/dees-progressbar/index.ts similarity index 100% rename from ts_web/elements/dees-progressbar/index.ts rename to ts_web/elements/00group-feedback/dees-progressbar/index.ts diff --git a/ts_web/elements/dees-spinner/dees-spinner.ts b/ts_web/elements/00group-feedback/dees-spinner/dees-spinner.ts similarity index 97% rename from ts_web/elements/dees-spinner/dees-spinner.ts rename to ts_web/elements/00group-feedback/dees-spinner/dees-spinner.ts index 2aaf51d..aeb1622 100644 --- a/ts_web/elements/dees-spinner/dees-spinner.ts +++ b/ts_web/elements/00group-feedback/dees-spinner/dees-spinner.ts @@ -11,7 +11,7 @@ import { } from '@design.estate/dees-element'; import * as domtools from '@design.estate/dees-domtools'; -import { themeDefaultStyles } from '../00theme.js'; +import { themeDefaultStyles } from '../../00theme.js'; declare global { interface HTMLElementTagNameMap { @@ -21,6 +21,7 @@ declare global { @customElement('dees-spinner') export class DeesSpinner extends DeesElement { + public static demoGroups = ['Feedback']; public static demo = () => html` diff --git a/ts_web/elements/dees-spinner/index.ts b/ts_web/elements/00group-feedback/dees-spinner/index.ts similarity index 100% rename from ts_web/elements/dees-spinner/index.ts rename to ts_web/elements/00group-feedback/dees-spinner/index.ts diff --git a/ts_web/elements/dees-toast/dees-toast.demo.ts b/ts_web/elements/00group-feedback/dees-toast/dees-toast.demo.ts similarity index 99% rename from ts_web/elements/dees-toast/dees-toast.demo.ts rename to ts_web/elements/00group-feedback/dees-toast/dees-toast.demo.ts index cf8ab6d..6b698e6 100644 --- a/ts_web/elements/dees-toast/dees-toast.demo.ts +++ b/ts_web/elements/00group-feedback/dees-toast/dees-toast.demo.ts @@ -1,6 +1,6 @@ import { html, css, cssManager } from '@design.estate/dees-element'; import { DeesToast } from '../dees-toast/dees-toast.js'; -import '../00group-button/dees-button/dees-button.js'; +import '../../00group-button/dees-button/dees-button.js'; export const demoFunc = () => html` + +
+
+
+ + + ${this.formatTime(this.currentTime)} / ${this.formatTime(this.duration)} + +
+ + ${titleText ? html` + ${titleText} + ` : ''} + +
+ + +
+ + +
+
+
+ +
+ ${this.error ? html` +
+ + ${this.error} +
+ ` : this.loading ? html` +
+
+
+ ` : this.showWaveform ? html` +
+ +
+ ` : html` +
+
+
+ `} +
+
+ `; + } + + public async connectedCallback(): Promise { + await super.connectedCallback(); + if (this.src) { + this.initAudio(); + } + } + + public async disconnectedCallback(): Promise { + await super.disconnectedCallback(); + this.cleanup(); + } + + public async updated(changedProperties: Map): Promise { + super.updated(changedProperties); + if (changedProperties.has('src') && this.src) { + this.cleanup(); + this.initAudio(); + } + if (changedProperties.has('waveformData') || changedProperties.has('currentTime')) { + this.drawWaveform(); + } + } + + public play(): void { + this.audioElement?.play(); + } + + public pause(): void { + this.audioElement?.pause(); + } + + public togglePlay(): void { + if (this.isPlaying) { + this.pause(); + } else { + this.play(); + } + } + + public seek(time: number): void { + if (this.audioElement) { + this.audioElement.currentTime = time; + } + } + + public setVolume(v: number): void { + this.volume = Math.max(0, Math.min(1, v)); + if (this.audioElement) { + this.audioElement.volume = this.volume; + } + if (this.volume > 0) { + this.isMuted = false; + } + } + + public toggleMute(): void { + if (this.isMuted) { + this.isMuted = false; + this.volume = this.volumeBeforeMute || 0.5; + if (this.audioElement) { + this.audioElement.volume = this.volume; + } + } else { + this.volumeBeforeMute = this.volume; + this.isMuted = true; + if (this.audioElement) { + this.audioElement.volume = 0; + } + } + } + + private toggleLoop(): void { + this.loop = !this.loop; + if (this.audioElement) { + this.audioElement.loop = this.loop; + } + } + + private initAudio(): void { + this.audioElement = new Audio(); + this.audioElement.crossOrigin = 'anonymous'; + this.audioElement.src = this.src; + this.audioElement.volume = this.isMuted ? 0 : this.volume; + this.audioElement.loop = this.loop; + + this.audioElement.addEventListener('loadedmetadata', () => { + this.duration = this.audioElement!.duration; + this.loading = false; + }); + + this.audioElement.addEventListener('play', () => { + this.isPlaying = true; + this.startTimeUpdate(); + }); + + this.audioElement.addEventListener('pause', () => { + this.isPlaying = false; + this.stopTimeUpdate(); + }); + + this.audioElement.addEventListener('ended', () => { + this.isPlaying = false; + this.stopTimeUpdate(); + }); + + this.audioElement.addEventListener('error', () => { + this.error = 'Failed to load audio'; + this.loading = false; + }); + + this.audioElement.addEventListener('timeupdate', () => { + this.currentTime = this.audioElement!.currentTime; + }); + + if (this.autoplay) { + this.audioElement.play().catch(() => { + // Autoplay blocked by browser + }); + } + + if (this.showWaveform) { + this.loadWaveform(); + } + } + + private async loadWaveform(): Promise { + try { + this.loading = true; + const response = await fetch(this.src); + const arrayBuffer = await response.arrayBuffer(); + const audioContext = new AudioContext(); + const audioBuffer = await audioContext.decodeAudioData(arrayBuffer); + + const channelData = audioBuffer.getChannelData(0); + const bars = 200; + const blockSize = Math.floor(channelData.length / bars); + const waveform: number[] = []; + + for (let i = 0; i < bars; i++) { + let sum = 0; + for (let j = 0; j < blockSize; j++) { + sum += Math.abs(channelData[i * blockSize + j]); + } + waveform.push(sum / blockSize); + } + + // Normalize + const max = Math.max(...waveform); + this.waveformData = waveform.map((v) => (max > 0 ? v / max : 0)); + this.waveformReady = true; + this.loading = false; + + await audioContext.close(); + } catch { + this.waveformReady = false; + this.loading = false; + } + } + + private drawWaveform(): void { + if (!this.showWaveform || !this.waveformReady) return; + + const canvas = this.shadowRoot?.querySelector('canvas') as HTMLCanvasElement; + if (!canvas) return; + + this.canvasElement = canvas; + const container = canvas.parentElement!; + const dpr = window.devicePixelRatio || 1; + const width = container.clientWidth; + const height = container.clientHeight; + + canvas.width = width * dpr; + canvas.height = height * dpr; + + const ctx = canvas.getContext('2d'); + if (!ctx) return; + + ctx.scale(dpr, dpr); + ctx.clearRect(0, 0, width, height); + + const bars = this.waveformData.length; + if (bars === 0) return; + + const barWidth = width / bars; + const playedRatio = this.duration > 0 ? this.currentTime / this.duration : 0; + const playedBars = Math.floor(playedRatio * bars); + + const isDark = document.body.classList.contains('theme-dark') || + window.matchMedia('(prefers-color-scheme: dark)').matches; + const playedColor = isDark ? 'hsl(213 93% 68%)' : 'hsl(217 91% 60%)'; + const unplayedColor = isDark ? 'hsl(217 25% 22%)' : 'hsl(214 31% 86%)'; + + for (let i = 0; i < bars; i++) { + const amplitude = this.waveformData[i]; + const barHeight = Math.max(2, amplitude * (height - 4)); + const x = i * barWidth; + const y = (height - barHeight) / 2; + + ctx.fillStyle = i < playedBars ? playedColor : unplayedColor; + ctx.fillRect(x + 0.5, y, barWidth - 1, barHeight); + } + } + + private handleWaveformClick(e: MouseEvent): void { + const rect = (e.currentTarget as HTMLElement).getBoundingClientRect(); + const ratio = (e.clientX - rect.left) / rect.width; + this.seek(ratio * this.duration); + } + + private handleSeekbarClick(e: MouseEvent): void { + const rect = (e.currentTarget as HTMLElement).getBoundingClientRect(); + const ratio = (e.clientX - rect.left) / rect.width; + this.seek(ratio * this.duration); + } + + private handleVolumeChange(e: Event): void { + const value = parseFloat((e.target as HTMLInputElement).value); + this.setVolume(value); + } + + private startTimeUpdate(): void { + this.stopTimeUpdate(); + const update = () => { + if (this.audioElement && this.isPlaying) { + this.currentTime = this.audioElement.currentTime; + this.animFrameId = requestAnimationFrame(update); + } + }; + this.animFrameId = requestAnimationFrame(update); + } + + private stopTimeUpdate(): void { + if (this.animFrameId) { + cancelAnimationFrame(this.animFrameId); + this.animFrameId = 0; + } + } + + private formatTime(seconds: number): string { + if (!isFinite(seconds) || seconds < 0) return '0:00'; + const mins = Math.floor(seconds / 60); + const secs = Math.floor(seconds % 60); + return `${mins}:${secs.toString().padStart(2, '0')}`; + } + + private cleanup(): void { + this.stopTimeUpdate(); + if (this.audioElement) { + this.audioElement.pause(); + this.audioElement.src = ''; + this.audioElement = null; + } + this.isPlaying = false; + this.currentTime = 0; + this.duration = 0; + this.waveformData = []; + this.waveformReady = false; + } +} diff --git a/ts_web/elements/00group-media/dees-audio-viewer/demo.ts b/ts_web/elements/00group-media/dees-audio-viewer/demo.ts new file mode 100644 index 0000000..c76ac6a --- /dev/null +++ b/ts_web/elements/00group-media/dees-audio-viewer/demo.ts @@ -0,0 +1,69 @@ +import { html, cssManager } from '@design.estate/dees-element'; + +export const demo = () => html` + + +
+
+
Audio with Waveform
+
Audio player with waveform visualization and full transport controls.
+ +
+ +
+
Audio without Waveform
+
Simple audio player with a seekbar instead of a waveform.
+ +
+ +
+
Minimal Audio Player
+
No title or artist metadata — just the player.
+ +
+
+`; diff --git a/ts_web/elements/00group-pdf/dees-pdf-preview/index.ts b/ts_web/elements/00group-media/dees-audio-viewer/index.ts similarity index 100% rename from ts_web/elements/00group-pdf/dees-pdf-preview/index.ts rename to ts_web/elements/00group-media/dees-audio-viewer/index.ts diff --git a/ts_web/elements/00group-media/dees-image-viewer/component.ts b/ts_web/elements/00group-media/dees-image-viewer/component.ts new file mode 100644 index 0000000..95b5625 --- /dev/null +++ b/ts_web/elements/00group-media/dees-image-viewer/component.ts @@ -0,0 +1,410 @@ +import { + DeesElement, + html, + customElement, + type TemplateResult, + property, + state, + cssManager, +} from '@design.estate/dees-element'; +import '../../00group-utility/dees-icon/dees-icon.js'; +import { demo } from './demo.js'; + +declare global { + interface HTMLElementTagNameMap { + 'dees-image-viewer': DeesImageViewer; + } +} + +@customElement('dees-image-viewer') +export class DeesImageViewer extends DeesElement { + public static demo = demo; + public static demoGroups = ['Media']; + + @property() + accessor src: string = ''; + + @property() + accessor alt: string = ''; + + @property() + accessor fit: 'contain' | 'cover' | 'actual' = 'contain'; + + @property({ type: Boolean }) + accessor showToolbar: boolean = true; + + @state() + accessor zoom: number = 1; + + @state() + accessor panX: number = 0; + + @state() + accessor panY: number = 0; + + @state() + accessor isDragging: boolean = false; + + @state() + accessor loading: boolean = true; + + @state() + accessor error: string = ''; + + @state() + accessor imageNaturalWidth: number = 0; + + @state() + accessor imageNaturalHeight: number = 0; + + private dragStartX = 0; + private dragStartY = 0; + private dragStartPanX = 0; + private dragStartPanY = 0; + + public render(): TemplateResult { + return html` + + +
+ ${this.showToolbar ? html` +
+
+ + + +
+
+ + +
+
+ +
+ ${this.imageNaturalWidth > 0 ? html` +
+ ${this.imageNaturalWidth} x ${this.imageNaturalHeight} +
+ ` : ''} +
+ ` : ''} + +
+
+
+ ${this.src ? html` + ${this.alt} + ` : ''} +
+ ${this.loading && this.src ? html` +
+
+
+ ` : ''} + ${this.error ? html` +
+ + ${this.error} +
+ ` : ''} +
+
+ `; + } + + public zoomIn(): void { + this.zoom = Math.min(10, this.zoom * 1.25); + } + + public zoomOut(): void { + this.zoom = Math.max(0.1, this.zoom / 1.25); + if (this.zoom <= 1) { + this.panX = 0; + this.panY = 0; + } + } + + public resetZoom(): void { + this.zoom = 1; + this.panX = 0; + this.panY = 0; + } + + public fitToScreen(): void { + this.zoom = 1; + this.panX = 0; + this.panY = 0; + this.fit = 'contain'; + } + + public actualSize(): void { + this.zoom = 1; + this.panX = 0; + this.panY = 0; + this.fit = 'actual'; + } + + public download(): void { + if (!this.src) return; + const link = document.createElement('a'); + link.href = this.src; + link.download = this.src.split('/').pop() || 'image'; + link.click(); + } + + private handleImageLoad(e: Event): void { + const img = e.target as HTMLImageElement; + this.loading = false; + this.error = ''; + this.imageNaturalWidth = img.naturalWidth; + this.imageNaturalHeight = img.naturalHeight; + } + + private handleImageError(): void { + this.loading = false; + this.error = 'Failed to load image'; + } + + private handleWheel(e: WheelEvent): void { + e.preventDefault(); + const delta = e.deltaY > 0 ? 0.9 : 1.1; + const newZoom = Math.min(10, Math.max(0.1, this.zoom * delta)); + this.zoom = newZoom; + if (this.zoom <= 1) { + this.panX = 0; + this.panY = 0; + } + } + + private handleMouseDown(e: MouseEvent): void { + if (this.zoom <= 1) return; + this.isDragging = true; + this.dragStartX = e.clientX; + this.dragStartY = e.clientY; + this.dragStartPanX = this.panX; + this.dragStartPanY = this.panY; + } + + private handleMouseMove(e: MouseEvent): void { + if (!this.isDragging) return; + this.panX = this.dragStartPanX + (e.clientX - this.dragStartX); + this.panY = this.dragStartPanY + (e.clientY - this.dragStartY); + } + + private handleMouseUp(): void { + this.isDragging = false; + } + + private handleDoubleClick(): void { + if (this.zoom === 1) { + this.zoom = 2; + } else { + this.zoom = 1; + this.panX = 0; + this.panY = 0; + } + } + + public updated(changedProperties: Map): void { + super.updated(changedProperties); + if (changedProperties.has('src')) { + this.loading = true; + this.error = ''; + this.zoom = 1; + this.panX = 0; + this.panY = 0; + this.imageNaturalWidth = 0; + this.imageNaturalHeight = 0; + } + } +} diff --git a/ts_web/elements/00group-media/dees-image-viewer/demo.ts b/ts_web/elements/00group-media/dees-image-viewer/demo.ts new file mode 100644 index 0000000..c3c701c --- /dev/null +++ b/ts_web/elements/00group-media/dees-image-viewer/demo.ts @@ -0,0 +1,84 @@ +import { html, cssManager } from '@design.estate/dees-element'; + +export const demo = () => html` + + +
+
+
JPEG Image with Toolbar
+
A landscape photo with zoom, pan, fit, and download controls.
+ +
+ +
+
PNG with Transparency
+
Transparent PNG displayed on a checkerboard background.
+ +
+ +
+
SVG Image
+
Scalable vector graphic.
+ +
+ +
+
No Toolbar Variant
+
Image viewer with the toolbar hidden.
+ +
+
+`; diff --git a/ts_web/elements/00group-pdf/dees-pdf-viewer/index.ts b/ts_web/elements/00group-media/dees-image-viewer/index.ts similarity index 100% rename from ts_web/elements/00group-pdf/dees-pdf-viewer/index.ts rename to ts_web/elements/00group-media/dees-image-viewer/index.ts diff --git a/ts_web/elements/00group-media/dees-pdf-preview/component.ts b/ts_web/elements/00group-media/dees-pdf-preview/component.ts new file mode 100644 index 0000000..beaf6a8 --- /dev/null +++ b/ts_web/elements/00group-media/dees-pdf-preview/component.ts @@ -0,0 +1,24 @@ +import { customElement } from '@design.estate/dees-element'; +import { DeesTilePdf } from '../dees-tile-pdf/component.js'; + +declare global { + interface HTMLElementTagNameMap { + 'dees-pdf-preview': DeesPdfPreview; + } +} + +/** + * @deprecated Use instead. This component will be removed in a future release. + */ +@customElement('dees-pdf-preview') +export class DeesPdfPreview extends DeesTilePdf { + public static demoGroups: never[] = []; // Hide from demo catalog + + public connectedCallback(): Promise { + console.warn( + '[dees-pdf-preview] is deprecated. Use instead. ' + + 'This component will be removed in a future release.' + ); + return super.connectedCallback(); + } +} diff --git a/ts_web/elements/00group-pdf/dees-pdf-preview/demo.ts b/ts_web/elements/00group-media/dees-pdf-preview/demo.ts similarity index 100% rename from ts_web/elements/00group-pdf/dees-pdf-preview/demo.ts rename to ts_web/elements/00group-media/dees-pdf-preview/demo.ts diff --git a/ts_web/elements/00group-pdf/dees-pdf/index.ts b/ts_web/elements/00group-media/dees-pdf-preview/index.ts similarity index 100% rename from ts_web/elements/00group-pdf/dees-pdf/index.ts rename to ts_web/elements/00group-media/dees-pdf-preview/index.ts diff --git a/ts_web/elements/00group-pdf/dees-pdf-preview/styles.ts b/ts_web/elements/00group-media/dees-pdf-preview/styles.ts similarity index 100% rename from ts_web/elements/00group-pdf/dees-pdf-preview/styles.ts rename to ts_web/elements/00group-media/dees-pdf-preview/styles.ts diff --git a/ts_web/elements/00group-pdf/dees-pdf-shared/CanvasPool.ts b/ts_web/elements/00group-media/dees-pdf-shared/CanvasPool.ts similarity index 100% rename from ts_web/elements/00group-pdf/dees-pdf-shared/CanvasPool.ts rename to ts_web/elements/00group-media/dees-pdf-shared/CanvasPool.ts diff --git a/ts_web/elements/00group-pdf/dees-pdf-shared/PdfManager.ts b/ts_web/elements/00group-media/dees-pdf-shared/PdfManager.ts similarity index 100% rename from ts_web/elements/00group-pdf/dees-pdf-shared/PdfManager.ts rename to ts_web/elements/00group-media/dees-pdf-shared/PdfManager.ts diff --git a/ts_web/elements/00group-pdf/dees-pdf-shared/index.ts b/ts_web/elements/00group-media/dees-pdf-shared/index.ts similarity index 100% rename from ts_web/elements/00group-pdf/dees-pdf-shared/index.ts rename to ts_web/elements/00group-media/dees-pdf-shared/index.ts diff --git a/ts_web/elements/00group-pdf/dees-pdf-shared/utils.ts b/ts_web/elements/00group-media/dees-pdf-shared/utils.ts similarity index 100% rename from ts_web/elements/00group-pdf/dees-pdf-shared/utils.ts rename to ts_web/elements/00group-media/dees-pdf-shared/utils.ts diff --git a/ts_web/elements/00group-pdf/dees-pdf-viewer/component.ts b/ts_web/elements/00group-media/dees-pdf-viewer/component.ts similarity index 99% rename from ts_web/elements/00group-pdf/dees-pdf-viewer/component.ts rename to ts_web/elements/00group-media/dees-pdf-viewer/component.ts index 6c15d17..a3399ac 100644 --- a/ts_web/elements/00group-pdf/dees-pdf-viewer/component.ts +++ b/ts_web/elements/00group-media/dees-pdf-viewer/component.ts @@ -2,7 +2,7 @@ import { DeesElement, property, html, customElement, type TemplateResult, direct import { PdfManager } from '../dees-pdf-shared/PdfManager.js'; import { viewerStyles } from './styles.js'; import { demo as demoFunc } from './demo.js'; -import '../../dees-icon/dees-icon.js'; +import '../../00group-utility/dees-icon/dees-icon.js'; declare global { interface HTMLElementTagNameMap { @@ -15,7 +15,7 @@ type RenderState = 'idle' | 'loading' | 'rendering-main' | 'rendering-thumbs' | @customElement('dees-pdf-viewer') export class DeesPdfViewer extends DeesElement { public static demo = demoFunc; - public static demoGroup = 'PDF'; + public static demoGroups = ['Media', 'PDF']; public static styles = viewerStyles; @property({ type: String }) diff --git a/ts_web/elements/00group-pdf/dees-pdf-viewer/demo.ts b/ts_web/elements/00group-media/dees-pdf-viewer/demo.ts similarity index 100% rename from ts_web/elements/00group-pdf/dees-pdf-viewer/demo.ts rename to ts_web/elements/00group-media/dees-pdf-viewer/demo.ts diff --git a/ts_web/elements/00group-media/dees-pdf-viewer/index.ts b/ts_web/elements/00group-media/dees-pdf-viewer/index.ts new file mode 100644 index 0000000..16900c4 --- /dev/null +++ b/ts_web/elements/00group-media/dees-pdf-viewer/index.ts @@ -0,0 +1 @@ +export * from './component.js'; diff --git a/ts_web/elements/00group-pdf/dees-pdf-viewer/styles.ts b/ts_web/elements/00group-media/dees-pdf-viewer/styles.ts similarity index 100% rename from ts_web/elements/00group-pdf/dees-pdf-viewer/styles.ts rename to ts_web/elements/00group-media/dees-pdf-viewer/styles.ts diff --git a/ts_web/elements/00group-pdf/dees-pdf/component.ts b/ts_web/elements/00group-media/dees-pdf/component.ts similarity index 92% rename from ts_web/elements/00group-pdf/dees-pdf/component.ts rename to ts_web/elements/00group-media/dees-pdf/component.ts index 74511ab..fc69497 100644 --- a/ts_web/elements/00group-pdf/dees-pdf/component.ts +++ b/ts_web/elements/00group-media/dees-pdf/component.ts @@ -1,8 +1,8 @@ import { DeesElement, property, html, customElement, domtools, type TemplateResult, type CSSResult, } from '@design.estate/dees-element'; import { Deferred } from '@push.rocks/smartpromise'; -import { DeesContextmenu } from '../../dees-contextmenu/dees-contextmenu.js'; -import '../../dees-icon/dees-icon.js'; +import { DeesContextmenu } from '../../00group-overlay/dees-contextmenu/dees-contextmenu.js'; +import '../../00group-utility/dees-icon/dees-icon.js'; // import type pdfjsTypes from 'pdfjs-dist'; @@ -13,15 +13,15 @@ declare global { } /** - * @deprecated Use DeesPdfViewer or DeesPdfPreview instead + * @deprecated Use DeesPdfViewer or DeesTilePdf instead * - DeesPdfViewer: Full-featured PDF viewing with controls, navigation, zoom - * - DeesPdfPreview: Lightweight, performance-optimized preview for grids + * - DeesTilePdf: Lightweight, performance-optimized tile preview for grids */ @customElement('dees-pdf') export class DeesPdf extends DeesElement { // DEMO public static demo = () => html` `; - public static demoGroup = 'PDF'; + public static demoGroups = ['Media', 'PDF']; // INSTANCE diff --git a/ts_web/elements/00group-media/dees-pdf/index.ts b/ts_web/elements/00group-media/dees-pdf/index.ts new file mode 100644 index 0000000..16900c4 --- /dev/null +++ b/ts_web/elements/00group-media/dees-pdf/index.ts @@ -0,0 +1 @@ +export * from './component.js'; diff --git a/ts_web/elements/00group-media/dees-preview/dees-preview.demo.ts b/ts_web/elements/00group-media/dees-preview/dees-preview.demo.ts new file mode 100644 index 0000000..fd613da --- /dev/null +++ b/ts_web/elements/00group-media/dees-preview/dees-preview.demo.ts @@ -0,0 +1,122 @@ +import { html, cssManager } from '@design.estate/dees-element'; + +export const demoFunc = () => html` + + +
+
+
Image Preview (URL)
+
Auto-detects image from URL extension and renders with the image viewer.
+ +
+ +
+
PDF Preview (URL)
+
Auto-detects PDF and displays with the PDF viewer including toolbar.
+ +
+ +
+
Code Preview (Text Content)
+
TypeScript code displayed with syntax highlighting via the codebox.
+ Hello World\`; + } +}`} + > +
+ +
+
Audio Preview (URL)
+
Audio file detected by extension, shown with waveform player.
+ +
+ +
+
Video Preview (URL)
+
Video file detected from URL, rendered with custom video controls.
+ +
+ +
+
Explicit Type Override
+
Force content type to 'text' even though the URL has no extension.
+ +
+ +
+
Unknown Type
+
When content type cannot be detected, shows a placeholder.
+ +
+
+`; diff --git a/ts_web/elements/00group-media/dees-preview/dees-preview.ts b/ts_web/elements/00group-media/dees-preview/dees-preview.ts new file mode 100644 index 0000000..5a73ffc --- /dev/null +++ b/ts_web/elements/00group-media/dees-preview/dees-preview.ts @@ -0,0 +1,507 @@ +import { + DeesElement, + html, + customElement, + type TemplateResult, + property, + state, + cssManager, +} from '@design.estate/dees-element'; +import '../dees-image-viewer/component.js'; +import '../dees-audio-viewer/component.js'; +import '../dees-video-viewer/component.js'; +import '../../00group-dataview/dees-dataview-codebox/dees-dataview-codebox.js'; +import '../dees-pdf-viewer/component.js'; +import '../../00group-utility/dees-icon/dees-icon.js'; +import { demoFunc } from './dees-preview.demo.js'; + +export type TPreviewContentType = 'image' | 'pdf' | 'audio' | 'video' | 'code' | 'text' | 'unknown'; + +declare global { + interface HTMLElementTagNameMap { + 'dees-preview': DeesPreview; + } +} + +const EXTENSION_MAP: Record = { + // Image + jpg: 'image', jpeg: 'image', png: 'image', gif: 'image', webp: 'image', + svg: 'image', bmp: 'image', avif: 'image', ico: 'image', + // PDF + pdf: 'pdf', + // Audio + mp3: 'audio', wav: 'audio', ogg: 'audio', flac: 'audio', aac: 'audio', + m4a: 'audio', opus: 'audio', weba: 'audio', + // Video + mp4: 'video', webm: 'video', mov: 'video', avi: 'video', mkv: 'video', ogv: 'video', + // Code + ts: 'code', js: 'code', jsx: 'code', tsx: 'code', json: 'code', + html: 'code', css: 'code', scss: 'code', less: 'code', + py: 'code', java: 'code', go: 'code', rs: 'code', + yaml: 'code', yml: 'code', xml: 'code', sql: 'code', + sh: 'code', bash: 'code', zsh: 'code', md: 'code', + c: 'code', cpp: 'code', h: 'code', hpp: 'code', + rb: 'code', php: 'code', swift: 'code', kt: 'code', + // Text + txt: 'text', log: 'text', csv: 'text', env: 'text', +}; + +const MIME_PREFIX_MAP: Record = { + 'image/': 'image', + 'audio/': 'audio', + 'video/': 'video', + 'application/pdf': 'pdf', +}; + +const EXTENSION_LANG_MAP: Record = { + ts: 'typescript', tsx: 'typescript', + js: 'javascript', jsx: 'javascript', + json: 'json', html: 'xml', xml: 'xml', + css: 'css', scss: 'scss', less: 'less', + py: 'python', java: 'java', go: 'go', rs: 'rust', + yaml: 'yaml', yml: 'yaml', sql: 'sql', + sh: 'bash', bash: 'bash', zsh: 'bash', + c: 'c', cpp: 'cpp', h: 'c', hpp: 'cpp', + rb: 'ruby', php: 'php', swift: 'swift', kt: 'kotlin', + md: 'markdown', +}; + +const TYPE_ICONS: Record = { + image: 'lucide:Image', + pdf: 'lucide:FileText', + audio: 'lucide:Music', + video: 'lucide:Video', + code: 'lucide:Code', + text: 'lucide:FileText', + unknown: 'lucide:File', +}; + +@customElement('dees-preview') +export class DeesPreview extends DeesElement { + public static demo = demoFunc; + public static demoGroups = ['Media', 'Data View']; + + // Content sources (use one) + @property() + accessor url: string = ''; + + @property({ attribute: false }) + accessor file: File | undefined = undefined; + + @property() + accessor base64: string = ''; + + @property() + accessor textContent: string = ''; + + // Hints & overrides + @property() + accessor contentType: TPreviewContentType | undefined = undefined; + + @property() + accessor language: string = ''; + + @property() + accessor mimeType: string = ''; + + @property() + accessor filename: string = ''; + + // UI + @property({ type: Boolean }) + accessor showToolbar: boolean = true; + + @property({ type: Boolean }) + accessor showFilename: boolean = true; + + // Internal + @state() + accessor resolvedType: TPreviewContentType = 'unknown'; + + @state() + accessor resolvedSrc: string = ''; + + @state() + accessor resolvedText: string = ''; + + @state() + accessor resolvedLang: string = 'text'; + + @state() + accessor loading: boolean = false; + + @state() + accessor error: string = ''; + + private objectUrl: string = ''; + + public render(): TemplateResult { + const displayName = this.filename || this.file?.name || this.getFilenameFromUrl() || ''; + + return html` + + +
+ ${this.showFilename && displayName ? html` +
+ + ${displayName} + ${this.resolvedType} +
+ ` : ''} + +
+ ${this.error ? html` +
+ + ${this.error} +
+ ` : this.loading ? html` +
+
+
+ ` : this.renderContent()} +
+
+ `; + } + + private renderContent(): TemplateResult { + switch (this.resolvedType) { + case 'image': + return html` + + `; + case 'pdf': + return html` + + `; + case 'audio': + return html` + + `; + case 'video': + return html` + + `; + case 'code': + return html` + + `; + case 'text': + return html`
${this.resolvedText}
`; + default: + return html` +
+ + Preview not available +
+ `; + } + } + + public async updated(changedProperties: Map): Promise { + super.updated(changedProperties); + + const relevant = ['url', 'file', 'base64', 'textContent', 'contentType', 'language', 'mimeType', 'filename']; + const needsResolve = relevant.some((key) => changedProperties.has(key)); + if (needsResolve) { + await this.resolveContent(); + } + } + + public async disconnectedCallback(): Promise { + await super.disconnectedCallback(); + this.revokeObjectUrl(); + } + + private async resolveContent(): Promise { + this.error = ''; + this.revokeObjectUrl(); + + // Detect type + this.resolvedType = this.detectType(); + + // Resolve source + try { + if (this.url) { + this.resolvedSrc = this.url; + if (this.resolvedType === 'code' || this.resolvedType === 'text') { + if (!this.textContent) { + this.loading = true; + const response = await fetch(this.url); + this.resolvedText = await response.text(); + this.loading = false; + } else { + this.resolvedText = this.textContent; + } + } + } else if (this.file) { + this.objectUrl = URL.createObjectURL(this.file); + this.resolvedSrc = this.objectUrl; + if (this.resolvedType === 'code' || this.resolvedType === 'text') { + this.loading = true; + this.resolvedText = await this.file.text(); + this.loading = false; + } + } else if (this.base64) { + const mime = this.mimeType || 'application/octet-stream'; + this.resolvedSrc = `data:${mime};base64,${this.base64}`; + } else if (this.textContent) { + this.resolvedText = this.textContent; + } + } catch { + this.error = 'Failed to load content'; + this.loading = false; + } + + // Resolve language for code + this.resolvedLang = this.resolveLanguage(); + } + + private detectType(): TPreviewContentType { + // 1. Explicit override + if (this.contentType) return this.contentType; + + // 2. MIME type + const mime = this.mimeType || this.file?.type || ''; + if (mime) { + if (mime === 'application/pdf') return 'pdf'; + for (const [prefix, type] of Object.entries(MIME_PREFIX_MAP)) { + if (mime.startsWith(prefix)) return type; + } + if (mime.startsWith('text/')) return 'text'; + } + + // 3. File extension + const ext = this.getExtension(); + if (ext && EXTENSION_MAP[ext]) return EXTENSION_MAP[ext]; + + // 4. If textContent is provided, assume code or text + if (this.textContent) { + return this.language ? 'code' : 'text'; + } + + return 'unknown'; + } + + private getExtension(): string { + const name = this.filename || this.file?.name || ''; + if (name) { + const parts = name.split('.'); + if (parts.length > 1) return parts.pop()!.toLowerCase(); + } + if (this.url) { + try { + const pathname = new URL(this.url, 'https://placeholder.com').pathname; + const parts = pathname.split('.'); + if (parts.length > 1) return parts.pop()!.toLowerCase(); + } catch { + // Invalid URL + } + } + return ''; + } + + private getFilenameFromUrl(): string { + if (!this.url) return ''; + try { + const pathname = new URL(this.url, 'https://placeholder.com').pathname; + return pathname.split('/').pop() || ''; + } catch { + return ''; + } + } + + private resolveLanguage(): string { + if (this.language) return this.language; + const ext = this.getExtension(); + return EXTENSION_LANG_MAP[ext] || 'text'; + } + + private revokeObjectUrl(): void { + if (this.objectUrl) { + URL.revokeObjectURL(this.objectUrl); + this.objectUrl = ''; + } + } +} diff --git a/ts_web/elements/dees-preview/index.ts b/ts_web/elements/00group-media/dees-preview/index.ts similarity index 100% rename from ts_web/elements/dees-preview/index.ts rename to ts_web/elements/00group-media/dees-preview/index.ts diff --git a/ts_web/elements/00group-media/dees-tile-audio/component.ts b/ts_web/elements/00group-media/dees-tile-audio/component.ts new file mode 100644 index 0000000..c5817a5 --- /dev/null +++ b/ts_web/elements/00group-media/dees-tile-audio/component.ts @@ -0,0 +1,344 @@ +import { + property, + state, + html, + customElement, + css, + cssManager, + type TemplateResult, + type CSSResult, +} from '@design.estate/dees-element'; +import { DeesTileBase } from '../dees-tile-shared/DeesTileBase.js'; +import { tileBaseStyles } from '../dees-tile-shared/styles.js'; +import { demo } from './demo.js'; + +declare global { + interface HTMLElementTagNameMap { + 'dees-tile-audio': DeesTileAudio; + } +} + +@customElement('dees-tile-audio') +export class DeesTileAudio extends DeesTileBase { + public static demo = demo; + public static demoGroups = ['Media']; + public static styles = [ + ...tileBaseStyles, + css` + .audio-content { + position: relative; + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 16px; + background: ${cssManager.bdTheme( + 'linear-gradient(135deg, hsl(250 40% 96%), hsl(280 30% 94%))', + 'linear-gradient(135deg, hsl(250 30% 16%), hsl(280 25% 14%))' + )}; + } + + .music-icon { + font-size: 48px; + color: ${cssManager.bdTheme('hsl(250 60% 65%)', 'hsl(250 60% 70%)')}; + opacity: 0.8; + } + + .audio-title { + font-size: 12px; + font-weight: 600; + color: ${cssManager.bdTheme('hsl(250 20% 35%)', 'hsl(250 20% 80%)')}; + text-align: center; + padding: 0 16px; + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .audio-artist { + font-size: 11px; + font-weight: 400; + color: ${cssManager.bdTheme('hsl(250 15% 50%)', 'hsl(250 15% 65%)')}; + text-align: center; + padding: 0 16px; + margin-top: -12px; + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .waveform-container { + width: calc(100% - 32px); + height: 40px; + position: relative; + overflow: hidden; + } + + .waveform-container canvas { + width: 100%; + height: 100%; + display: block; + } + + .duration-badge { + position: absolute; + bottom: 8px; + right: 8px; + padding: 3px 8px; + background: ${cssManager.bdTheme('hsl(0 0% 0% / 0.6)', 'hsl(0 0% 100% / 0.85)')}; + color: ${cssManager.bdTheme('white', 'hsl(215 20% 12%)')}; + border-radius: 4px; + font-size: 10px; + font-weight: 600; + font-variant-numeric: tabular-nums; + backdrop-filter: blur(8px); + z-index: 10; + } + + .play-overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + display: flex; + align-items: center; + justify-content: center; + opacity: 0; + transition: opacity 0.2s ease; + z-index: 18; + pointer-events: none; + } + + .tile-container.clickable:hover .play-overlay { + opacity: 1; + } + + .play-circle { + width: 48px; + height: 48px; + border-radius: 50%; + background: rgba(0, 0, 0, 0.6); + display: flex; + align-items: center; + justify-content: center; + backdrop-filter: blur(8px); + } + + .play-circle dees-icon { + font-size: 20px; + color: white; + } + `, + ] as any; + + @property({ type: String }) + accessor src: string = ''; + + @property({ type: String }) + accessor title: string = ''; + + @property({ type: String }) + accessor artist: string = ''; + + @state() + accessor duration: number = 0; + + @state() + accessor waveformData: number[] = []; + + @state() + accessor waveformReady: boolean = false; + + @state() + accessor isPreviewPlaying: boolean = false; + + private audioElement: HTMLAudioElement | null = null; + private previewTimeout: ReturnType | null = null; + private hasLoadedWaveform: boolean = false; + + protected renderTileContent(): TemplateResult { + return html` +
+ + + ${this.title ? html`
${this.title}
` : ''} + ${this.artist ? html`
${this.artist}
` : ''} + + ${this.waveformReady ? html` +
+ +
+ ` : ''} +
+ + ${this.duration > 0 ? html` +
${this.formatTime(this.duration)}
+ ` : ''} + +
+
+ +
+
+ + ${this.clickable ? html` +
+ + Play Audio +
+ ` : ''} + `; + } + + protected getTileClickDetail(): Record { + return { + src: this.src, + title: this.title, + artist: this.artist, + duration: this.duration, + }; + } + + protected onBecameVisible(): void { + if (!this.hasLoadedWaveform && this.src) { + this.hasLoadedWaveform = true; + this.loadAudioMeta(); + } + } + + private async loadAudioMeta(): Promise { + this.loading = true; + + try { + // Load duration via Audio element + const audio = new Audio(); + audio.crossOrigin = 'anonymous'; + audio.preload = 'metadata'; + + await new Promise((resolve, reject) => { + audio.addEventListener('loadedmetadata', () => { + this.duration = audio.duration; + resolve(); + }, { once: true }); + audio.addEventListener('error', () => reject(new Error('Failed to load audio')), { once: true }); + audio.src = this.src; + }); + + // Load waveform data + await this.loadWaveform(); + this.loading = false; + } catch { + this.loading = false; + // Don't set error - audio may still be playable, just no waveform + } + } + + private async loadWaveform(): Promise { + try { + const response = await fetch(this.src); + const arrayBuffer = await response.arrayBuffer(); + const audioContext = new AudioContext(); + const audioBuffer = await audioContext.decodeAudioData(arrayBuffer); + + const channelData = audioBuffer.getChannelData(0); + const bars = 80; + const blockSize = Math.floor(channelData.length / bars); + const waveform: number[] = []; + + for (let i = 0; i < bars; i++) { + let sum = 0; + for (let j = 0; j < blockSize; j++) { + sum += Math.abs(channelData[i * blockSize + j]); + } + waveform.push(sum / blockSize); + } + + const max = Math.max(...waveform); + this.waveformData = waveform.map((v) => (max > 0 ? v / max : 0)); + this.waveformReady = true; + + await audioContext.close(); + await this.updateComplete; + this.drawWaveform(); + } catch { + this.waveformReady = false; + } + } + + private drawWaveform(): void { + if (!this.waveformReady) return; + + const canvas = this.shadowRoot?.querySelector('.waveform-container canvas') as HTMLCanvasElement; + if (!canvas) return; + + const container = canvas.parentElement!; + const dpr = window.devicePixelRatio || 1; + const width = container.clientWidth; + const height = container.clientHeight; + + canvas.width = width * dpr; + canvas.height = height * dpr; + + const ctx = canvas.getContext('2d'); + if (!ctx) return; + + ctx.scale(dpr, dpr); + ctx.clearRect(0, 0, width, height); + + const bars = this.waveformData.length; + if (bars === 0) return; + + const barWidth = width / bars; + + const isDark = document.body.classList.contains('theme-dark') || + window.matchMedia('(prefers-color-scheme: dark)').matches; + const barColor = isDark ? 'hsl(250 50% 60%)' : 'hsl(250 50% 70%)'; + + ctx.fillStyle = barColor; + for (let i = 0; i < bars; i++) { + const amplitude = this.waveformData[i]; + const barHeight = Math.max(2, amplitude * (height - 4)); + const x = i * barWidth; + const y = (height - barHeight) / 2; + ctx.fillRect(x + 0.5, y, barWidth - 1, barHeight); + } + } + + public async updated(changedProperties: Map): Promise { + super.updated(changedProperties); + if (changedProperties.has('src') && this.src && this.isVisible) { + this.hasLoadedWaveform = true; + this.waveformReady = false; + this.duration = 0; + this.loadAudioMeta(); + } + if (changedProperties.has('waveformReady') && this.waveformReady) { + await this.updateComplete; + this.drawWaveform(); + } + } + + public async disconnectedCallback(): Promise { + await super.disconnectedCallback(); + if (this.previewTimeout) { + clearTimeout(this.previewTimeout); + } + if (this.audioElement) { + this.audioElement.pause(); + this.audioElement.src = ''; + this.audioElement = null; + } + } + + private formatTime(seconds: number): string { + if (!isFinite(seconds) || seconds < 0) return '0:00'; + const mins = Math.floor(seconds / 60); + const secs = Math.floor(seconds % 60); + return `${mins}:${secs.toString().padStart(2, '0')}`; + } +} diff --git a/ts_web/elements/00group-media/dees-tile-audio/demo.ts b/ts_web/elements/00group-media/dees-tile-audio/demo.ts new file mode 100644 index 0000000..d61e432 --- /dev/null +++ b/ts_web/elements/00group-media/dees-tile-audio/demo.ts @@ -0,0 +1,77 @@ +import { html } from '@design.estate/dees-element'; + +export const demo = () => html` + + +
+
+

Audio Tiles

+
+ console.log('Audio clicked:', e.detail)} + > + + + + +
+
+ +
+

Size Variants

+
+ + + + + +
+
+
+`; diff --git a/ts_web/elements/00group-media/dees-tile-audio/index.ts b/ts_web/elements/00group-media/dees-tile-audio/index.ts new file mode 100644 index 0000000..16900c4 --- /dev/null +++ b/ts_web/elements/00group-media/dees-tile-audio/index.ts @@ -0,0 +1 @@ +export * from './component.js'; diff --git a/ts_web/elements/00group-media/dees-tile-folder/component.ts b/ts_web/elements/00group-media/dees-tile-folder/component.ts new file mode 100644 index 0000000..d783fa1 --- /dev/null +++ b/ts_web/elements/00group-media/dees-tile-folder/component.ts @@ -0,0 +1,181 @@ +import { + property, + html, + customElement, + css, + cssManager, + type TemplateResult, + type CSSResult, +} from '@design.estate/dees-element'; +import { DeesTileBase } from '../dees-tile-shared/DeesTileBase.js'; +import { tileBaseStyles } from '../dees-tile-shared/styles.js'; +import { demo } from './demo.js'; + +export interface ITileFolderItem { + type: 'pdf' | 'image' | 'audio' | 'video' | 'note' | 'folder' | 'unknown'; + thumbnailSrc?: string; + name: string; +} + +const TYPE_ICON_MAP: Record = { + pdf: 'lucide:FileText', + image: 'lucide:Image', + audio: 'lucide:Music', + video: 'lucide:Video', + note: 'lucide:FileCode', + folder: 'lucide:Folder', + unknown: 'lucide:File', +}; + +declare global { + interface HTMLElementTagNameMap { + 'dees-tile-folder': DeesTileFolder; + } +} + +@customElement('dees-tile-folder') +export class DeesTileFolder extends DeesTileBase { + public static demo = demo; + public static demoGroups = ['Media']; + public static styles = [ + ...tileBaseStyles, + css` + .folder-content { + position: relative; + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + background: ${cssManager.bdTheme('hsl(40 30% 97%)', 'hsl(215 20% 14%)')}; + overflow: hidden; + } + + .folder-header { + display: flex; + align-items: center; + gap: 8px; + padding: 12px 14px 8px; + flex-shrink: 0; + } + + .folder-icon { + font-size: 18px; + color: ${cssManager.bdTheme('hsl(40 80% 50%)', 'hsl(40 70% 60%)')}; + } + + .folder-name { + font-size: 12px; + font-weight: 700; + color: ${cssManager.bdTheme('hsl(215 20% 20%)', 'hsl(215 16% 80%)')}; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + flex: 1; + } + + .preview-grid { + flex: 1; + display: grid; + grid-template-columns: 1fr 1fr; + grid-template-rows: 1fr 1fr; + gap: 4px; + padding: 0 14px 14px; + min-height: 0; + } + + .grid-cell { + display: flex; + align-items: center; + justify-content: center; + border-radius: 4px; + overflow: hidden; + background: ${cssManager.bdTheme('hsl(215 20% 94%)', 'hsl(215 20% 18%)')}; + position: relative; + } + + .grid-cell img { + width: 100%; + height: 100%; + object-fit: cover; + display: block; + } + + .grid-cell dees-icon { + font-size: 20px; + color: ${cssManager.bdTheme('hsl(215 16% 60%)', 'hsl(215 16% 55%)')}; + } + + .grid-cell-empty { + background: ${cssManager.bdTheme('hsl(215 15% 96%)', 'hsl(215 20% 16%)')}; + } + + .item-count-badge { + position: absolute; + bottom: 8px; + right: 8px; + padding: 3px 8px; + background: ${cssManager.bdTheme('hsl(0 0% 0% / 0.6)', 'hsl(0 0% 100% / 0.85)')}; + color: ${cssManager.bdTheme('white', 'hsl(215 20% 12%)')}; + border-radius: 4px; + font-size: 10px; + font-weight: 600; + backdrop-filter: blur(8px); + z-index: 10; + } + `, + ] as any; + + @property({ type: String }) + accessor name: string = ''; + + @property({ attribute: false }) + accessor items: ITileFolderItem[] = []; + + protected renderTileContent(): TemplateResult { + const previewItems = this.items.slice(0, 4); + const emptyCells = 4 - previewItems.length; + + return html` +
+
+ +
${this.name || 'Untitled Folder'}
+
+ +
+ ${previewItems.map((item) => html` +
+ ${item.thumbnailSrc ? html` + ${item.name} + ` : html` + + `} +
+ `)} + ${Array.from({ length: emptyCells }).map(() => html` +
+ `)} +
+
+ +
+ ${this.items.length} item${this.items.length !== 1 ? 's' : ''} +
+ + ${this.clickable ? html` +
+ + Open Folder +
+ ` : ''} + `; + } + + protected getTileClickDetail(): Record { + return { + name: this.name, + itemCount: this.items.length, + items: this.items, + }; + } +} diff --git a/ts_web/elements/00group-media/dees-tile-folder/demo.ts b/ts_web/elements/00group-media/dees-tile-folder/demo.ts new file mode 100644 index 0000000..c0843fb --- /dev/null +++ b/ts_web/elements/00group-media/dees-tile-folder/demo.ts @@ -0,0 +1,122 @@ +import { html } from '@design.estate/dees-element'; +import type { ITileFolderItem } from './component.js'; + +export const demo = () => { + const photosFolder: ITileFolderItem[] = [ + { type: 'image', name: 'sunset.jpg', thumbnailSrc: 'https://picsum.photos/200/200?random=1' }, + { type: 'image', name: 'mountain.jpg', thumbnailSrc: 'https://picsum.photos/200/200?random=2' }, + { type: 'image', name: 'ocean.jpg', thumbnailSrc: 'https://picsum.photos/200/200?random=3' }, + { type: 'image', name: 'forest.jpg', thumbnailSrc: 'https://picsum.photos/200/200?random=4' }, + { type: 'image', name: 'city.jpg', thumbnailSrc: 'https://picsum.photos/200/200?random=5' }, + { type: 'image', name: 'desert.jpg', thumbnailSrc: 'https://picsum.photos/200/200?random=6' }, + ]; + + const projectFolder: ITileFolderItem[] = [ + { type: 'note', name: 'README.md' }, + { type: 'note', name: 'package.json' }, + { type: 'folder', name: 'src' }, + { type: 'folder', name: 'test' }, + { type: 'note', name: 'tsconfig.json' }, + { type: 'pdf', name: 'docs.pdf' }, + { type: 'image', name: 'logo.png', thumbnailSrc: 'https://picsum.photos/100/100?random=10' }, + ]; + + const mediaFolder: ITileFolderItem[] = [ + { type: 'video', name: 'intro.mp4' }, + { type: 'audio', name: 'background.mp3' }, + { type: 'image', name: 'thumbnail.jpg', thumbnailSrc: 'https://picsum.photos/200/200?random=20' }, + { type: 'pdf', name: 'storyboard.pdf' }, + ]; + + const emptyFolder: ITileFolderItem[] = []; + + const singleItemFolder: ITileFolderItem[] = [ + { type: 'pdf', name: 'report.pdf' }, + ]; + + return html` + + +
+
+

Folder Tiles

+
+ console.log('Folder clicked:', e.detail)} + > + + + + +
+
+ +
+

Edge Cases

+
+ + + +
+
+ +
+

Size Variants

+
+ + + + + +
+
+
+ `; +}; diff --git a/ts_web/elements/00group-media/dees-tile-folder/index.ts b/ts_web/elements/00group-media/dees-tile-folder/index.ts new file mode 100644 index 0000000..16900c4 --- /dev/null +++ b/ts_web/elements/00group-media/dees-tile-folder/index.ts @@ -0,0 +1 @@ +export * from './component.js'; diff --git a/ts_web/elements/00group-media/dees-tile-image/component.ts b/ts_web/elements/00group-media/dees-tile-image/component.ts new file mode 100644 index 0000000..b311e1e --- /dev/null +++ b/ts_web/elements/00group-media/dees-tile-image/component.ts @@ -0,0 +1,172 @@ +import { + property, + state, + html, + customElement, + css, + cssManager, + type TemplateResult, + type CSSResult, +} from '@design.estate/dees-element'; +import { DeesTileBase } from '../dees-tile-shared/DeesTileBase.js'; +import { tileBaseStyles } from '../dees-tile-shared/styles.js'; +import { demo } from './demo.js'; + +declare global { + interface HTMLElementTagNameMap { + 'dees-tile-image': DeesTileImage; + } +} + +@customElement('dees-tile-image') +export class DeesTileImage extends DeesTileBase { + public static demo = demo; + public static demoGroups = ['Media']; + public static styles = [ + ...tileBaseStyles, + css` + .image-wrapper { + position: relative; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; + background: ${cssManager.bdTheme( + 'repeating-conic-gradient(#e8e8e8 0% 25%, white 0% 50%) 50% / 16px 16px', + 'repeating-conic-gradient(hsl(215 20% 18%) 0% 25%, hsl(215 20% 14%) 0% 50%) 50% / 16px 16px' + )}; + } + + .image-wrapper img { + width: 100%; + height: 100%; + object-fit: cover; + display: block; + transition: opacity 0.3s ease; + } + + .image-wrapper img.loaded { + opacity: 1; + } + + .image-wrapper img.loading { + opacity: 0; + } + + .dimension-badge { + position: absolute; + top: 8px; + right: 8px; + padding: 3px 8px; + background: ${cssManager.bdTheme('hsl(0 0% 0% / 0.6)', 'hsl(0 0% 100% / 0.85)')}; + color: ${cssManager.bdTheme('white', 'hsl(215 20% 12%)')}; + border-radius: 4px; + font-size: 10px; + font-weight: 600; + backdrop-filter: blur(8px); + z-index: 15; + pointer-events: none; + opacity: 0; + transition: opacity 0.2s ease; + } + + .tile-container.clickable:hover .dimension-badge { + opacity: 1; + } + `, + ] as any; + + @property({ type: String }) + accessor src: string = ''; + + @property({ type: String }) + accessor alt: string = ''; + + @state() + accessor imageLoaded: boolean = false; + + @state() + accessor imageWidth: number = 0; + + @state() + accessor imageHeight: number = 0; + + private hasStartedLoading: boolean = false; + + protected renderTileContent(): TemplateResult { + return html` +
+ ${this.hasStartedLoading ? html` + ${this.alt} + ` : ''} +
+ + ${this.imageWidth > 0 && this.imageHeight > 0 ? html` +
+ ${this.imageWidth} × ${this.imageHeight} +
+ ` : ''} + + ${this.imageLoaded ? html` +
+ + ${this.imageWidth} × ${this.imageHeight} +
+ ` : ''} + + ${this.clickable ? html` +
+ + View Image +
+ ` : ''} + `; + } + + protected getTileClickDetail(): Record { + return { + src: this.src, + alt: this.alt, + width: this.imageWidth, + height: this.imageHeight, + }; + } + + protected onBecameVisible(): void { + if (!this.hasStartedLoading && this.src) { + this.hasStartedLoading = true; + this.loading = true; + this.requestUpdate(); + } + } + + private handleImageLoad(e: Event): void { + const img = e.target as HTMLImageElement; + this.imageWidth = img.naturalWidth; + this.imageHeight = img.naturalHeight; + this.imageLoaded = true; + this.loading = false; + } + + private handleImageError(): void { + this.error = true; + this.loading = false; + } + + public async updated(changedProperties: Map): Promise { + super.updated(changedProperties); + if (changedProperties.has('src') && this.src && this.isVisible) { + this.hasStartedLoading = true; + this.imageLoaded = false; + this.loading = true; + } + } +} diff --git a/ts_web/elements/00group-media/dees-tile-image/demo.ts b/ts_web/elements/00group-media/dees-tile-image/demo.ts new file mode 100644 index 0000000..c72a3df --- /dev/null +++ b/ts_web/elements/00group-media/dees-tile-image/demo.ts @@ -0,0 +1,84 @@ +import { html } from '@design.estate/dees-element'; + +export const demo = () => html` + + +
+
+

Image Tiles

+
+ console.log('Image clicked:', e.detail)} + > + + + + +
+
+ +
+

Size Variants

+
+ + + + + +
+
+ +
+

Error State (broken URL)

+ +
+
+`; diff --git a/ts_web/elements/00group-media/dees-tile-image/index.ts b/ts_web/elements/00group-media/dees-tile-image/index.ts new file mode 100644 index 0000000..16900c4 --- /dev/null +++ b/ts_web/elements/00group-media/dees-tile-image/index.ts @@ -0,0 +1 @@ +export * from './component.js'; diff --git a/ts_web/elements/00group-media/dees-tile-note/component.ts b/ts_web/elements/00group-media/dees-tile-note/component.ts new file mode 100644 index 0000000..13d000f --- /dev/null +++ b/ts_web/elements/00group-media/dees-tile-note/component.ts @@ -0,0 +1,231 @@ +import { + property, + state, + html, + customElement, + css, + cssManager, + type TemplateResult, + type CSSResult, +} from '@design.estate/dees-element'; +import { DeesTileBase } from '../dees-tile-shared/DeesTileBase.js'; +import { tileBaseStyles } from '../dees-tile-shared/styles.js'; +import { demo } from './demo.js'; + +declare global { + interface HTMLElementTagNameMap { + 'dees-tile-note': DeesTileNote; + } +} + +@customElement('dees-tile-note') +export class DeesTileNote extends DeesTileBase { + public static demo = demo; + public static demoGroups = ['Media']; + public static styles = [ + ...tileBaseStyles, + css` + .note-content { + position: relative; + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + background: ${cssManager.bdTheme('#ffffff', 'hsl(60 5% 96%)')}; + overflow: hidden; + } + + .note-header { + padding: 12px 14px 8px; + flex-shrink: 0; + } + + .note-title { + font-size: 12px; + font-weight: 700; + color: ${cssManager.bdTheme('hsl(215 20% 20%)', 'hsl(215 20% 20%)')}; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + line-height: 1.3; + } + + .note-body { + flex: 1; + padding: 0 14px 14px; + position: relative; + overflow: hidden; + } + + .note-text { + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; + font-size: 10px; + line-height: 1.5; + color: ${cssManager.bdTheme('hsl(215 10% 40%)', 'hsl(215 10% 35%)')}; + white-space: pre-wrap; + word-wrap: break-word; + overflow: hidden; + margin: 0; + } + + .note-fade { + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 60px; + background: linear-gradient( + transparent, + ${cssManager.bdTheme('#ffffff', 'hsl(60 5% 96%)')} + ); + pointer-events: none; + } + + .note-language { + position: absolute; + top: 8px; + right: 8px; + padding: 2px 6px; + background: ${cssManager.bdTheme('hsl(215 20% 92%)', 'hsl(215 20% 88%)')}; + color: ${cssManager.bdTheme('hsl(215 16% 50%)', 'hsl(215 16% 40%)')}; + border-radius: 3px; + font-size: 9px; + font-weight: 600; + text-transform: uppercase; + z-index: 5; + } + + .note-lines { + position: absolute; + top: 0; + left: 0; + bottom: 0; + width: 34px; + border-right: 1px solid ${cssManager.bdTheme('hsl(0 70% 85%)', 'hsl(0 50% 80%)')}; + display: flex; + flex-direction: column; + padding-top: 12px; + } + + .line-number { + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; + font-size: 9px; + line-height: 15px; /* matches 10px * 1.5 line-height */ + color: ${cssManager.bdTheme('hsl(215 10% 75%)', 'hsl(215 10% 70%)')}; + text-align: right; + padding-right: 6px; + } + + .note-line-indicator { + position: absolute; + bottom: 8px; + right: 8px; + padding: 3px 8px; + background: rgba(0, 0, 0, 0.6); + color: white; + border-radius: 4px; + font-size: 9px; + font-weight: 600; + font-variant-numeric: tabular-nums; + backdrop-filter: blur(8px); + z-index: 10; + pointer-events: none; + } + `, + ] as any; + + @property({ type: String }) + accessor title: string = ''; + + @property({ type: String }) + accessor content: string = ''; + + @property({ type: String }) + accessor language: string = ''; + + @state() + accessor isHovering: boolean = false; + + private noteBodyElement: HTMLElement | null = null; + + protected renderTileContent(): TemplateResult { + const lines = this.content.split('\n'); + + return html` +
+ ${this.language ? html` +
${this.language}
+ ` : ''} + + ${this.title ? html` +
+
${this.title}
+
+ ` : ''} + +
+
${lines.join('\n')}
+ ${!this.isHovering ? html`
` : ''} +
+ + ${this.isHovering && lines.length > 12 ? html` +
+ Line ${this.getVisibleLineRange(lines.length)} +
+ ` : ''} +
+ + ${this.clickable ? html` +
+ + Open Note +
+ ` : ''} + `; + } + + protected getTileClickDetail(): Record { + return { + title: this.title, + content: this.content, + language: this.language, + }; + } + + protected onTileMouseEnter(): void { + this.isHovering = true; + if (!this.noteBodyElement) { + this.noteBodyElement = this.shadowRoot?.querySelector('.note-body') as HTMLElement; + } + } + + protected onTileMouseLeave(): void { + this.isHovering = false; + if (this.noteBodyElement) { + this.noteBodyElement.scrollTop = 0; + } + } + + protected onTileMouseMove(e: MouseEvent): void { + if (!this.isHovering || !this.noteBodyElement) return; + + const totalLines = this.content.split('\n').length; + if (totalLines <= 12) return; + + const rect = this.getBoundingClientRect(); + const y = e.clientY - rect.top; + const percentage = Math.max(0, Math.min(1, y / rect.height)); + + const maxScroll = this.noteBodyElement.scrollHeight - this.noteBodyElement.clientHeight; + this.noteBodyElement.scrollTop = percentage * maxScroll; + } + + private getVisibleLineRange(totalLines: number): string { + if (!this.noteBodyElement) return `1–12 of ${totalLines}`; + const lineHeight = 15; // 10px font × 1.5 line-height + const firstLine = Math.floor(this.noteBodyElement.scrollTop / lineHeight) + 1; + const visibleCount = Math.floor(this.noteBodyElement.clientHeight / lineHeight); + const lastLine = Math.min(firstLine + visibleCount - 1, totalLines); + return `${firstLine}–${lastLine} of ${totalLines}`; + } +} diff --git a/ts_web/elements/00group-media/dees-tile-note/demo.ts b/ts_web/elements/00group-media/dees-tile-note/demo.ts new file mode 100644 index 0000000..b09069c --- /dev/null +++ b/ts_web/elements/00group-media/dees-tile-note/demo.ts @@ -0,0 +1,135 @@ +import { html } from '@design.estate/dees-element'; + +export const demo = () => { + const sampleCode = `import { html } from 'lit'; + +export class MyComponent { + private items: string[] = []; + + render() { + return html\` +
+ \${this.items.map(item => html\` + \${item} + \`)} +
+ \`; + } +}`; + + const sampleText = `Meeting Notes - Q4 Planning +Date: January 15, 2026 +Attendees: Alice, Bob, Charlie + +Key Decisions: +1. Launch new feature by March +2. Hire 2 more engineers +3. Migrate to new CI/CD pipeline +4. Update design system to v3 + +Action Items: +- Alice: Draft PRD by next week +- Bob: Set up interview pipeline +- Charlie: Evaluate Jenkins vs GitHub Actions`; + + const sampleJson = `{ + "name": "@design.estate/dees-catalog", + "version": "3.38.0", + "description": "Design component catalog", + "dependencies": { + "@design.estate/dees-element": "^2.0.0", + "lit": "^3.1.0" + }, + "scripts": { + "build": "tsbuild", + "test": "tstest" + } +}`; + + return html` + + +
+
+

Note Tiles

+
+ console.log('Note clicked:', e.detail)} + > + + + + +
+
+ +
+

Size Variants

+
+ + + + + +
+
+ +
+

Without Title

+ +
+
+ `; +}; diff --git a/ts_web/elements/00group-media/dees-tile-note/index.ts b/ts_web/elements/00group-media/dees-tile-note/index.ts new file mode 100644 index 0000000..16900c4 --- /dev/null +++ b/ts_web/elements/00group-media/dees-tile-note/index.ts @@ -0,0 +1 @@ +export * from './component.js'; diff --git a/ts_web/elements/00group-pdf/dees-pdf-preview/component.ts b/ts_web/elements/00group-media/dees-tile-pdf/component.ts similarity index 57% rename from ts_web/elements/00group-pdf/dees-pdf-preview/component.ts rename to ts_web/elements/00group-media/dees-tile-pdf/component.ts index 4052ef3..f47d14f 100644 --- a/ts_web/elements/00group-pdf/dees-pdf-preview/component.ts +++ b/ts_web/elements/00group-media/dees-tile-pdf/component.ts @@ -1,22 +1,23 @@ -import { DeesElement, property, html, customElement, type TemplateResult } from '@design.estate/dees-element'; +import { property, html, customElement, type TemplateResult, type CSSResult } from '@design.estate/dees-element'; +import { DeesTileBase } from '../dees-tile-shared/DeesTileBase.js'; +import { tileBaseStyles } from '../dees-tile-shared/styles.js'; import { PdfManager } from '../dees-pdf-shared/PdfManager.js'; import { CanvasPool, type PooledCanvas } from '../dees-pdf-shared/CanvasPool.js'; import { PerformanceMonitor, throttle } from '../dees-pdf-shared/utils.js'; -import { previewStyles } from './styles.js'; +import { tilePdfStyles } from './styles.js'; import { demo as demoFunc } from './demo.js'; -import '../../dees-icon/dees-icon.js'; declare global { interface HTMLElementTagNameMap { - 'dees-pdf-preview': DeesPdfPreview; + 'dees-tile-pdf': DeesTilePdf; } } -@customElement('dees-pdf-preview') -export class DeesPdfPreview extends DeesElement { +@customElement('dees-tile-pdf') +export class DeesTilePdf extends DeesTileBase { public static demo = demoFunc; - public static demoGroup = 'PDF'; - public static styles = previewStyles; + public static demoGroups = ['Media', 'PDF']; + public static styles = [...tileBaseStyles, tilePdfStyles] as any; @property({ type: String }) accessor pdfUrl: string = ''; @@ -24,21 +25,12 @@ export class DeesPdfPreview extends DeesElement { @property({ type: Number }) accessor currentPreviewPage: number = 1; - @property({ type: Boolean }) - accessor clickable: boolean = true; - @property({ type: Number }) accessor pageCount: number = 0; - @property({ type: Boolean }) - accessor loading: boolean = false; - @property({ type: Boolean }) accessor rendered: boolean = false; - @property({ type: Boolean }) - accessor error: boolean = false; - @property({ type: Boolean }) accessor isHovering: boolean = false; @@ -47,95 +39,75 @@ export class DeesPdfPreview extends DeesElement { private renderPagesTask: Promise | null = null; private renderPagesQueued: boolean = false; - - private observer: IntersectionObserver; private pdfDocument: any; private canvases: PooledCanvas[] = []; private resizeObserver?: ResizeObserver; - private previewContainer: HTMLElement | null = null; private stackElement: HTMLElement | null = null; private loadedPdfUrl: string | null = null; - constructor() { - super(); - } - - public render(): TemplateResult { + protected renderTileContent(): TemplateResult { return html` -
- ${this.loading ? html` -
-
-
Loading preview...
-
- ` : ''} - - ${this.error ? html` -
- -
Failed to load PDF
-
- ` : ''} - - ${!this.loading && !this.error ? html` -
- -
- - ${this.pageCount > 1 && this.isHovering ? html` -
- Page ${this.currentPreviewPage} of ${this.pageCount} -
- ` : ''} - - ${this.pageCount > 0 && !this.isHovering ? html` -
- - ${this.pageCount} page${this.pageCount > 1 ? 's' : ''} -
- ` : ''} - - ${this.clickable ? html` -
- - View PDF -
- ` : ''} - ` : ''} +
+
+ + ${this.pageCount > 1 && this.isHovering ? html` +
+ Page ${this.currentPreviewPage} of ${this.pageCount} +
+ ` : ''} + + ${this.pageCount > 0 && !this.isHovering ? html` +
+ + ${this.pageCount} page${this.pageCount > 1 ? 's' : ''} +
+ ` : ''} + + ${this.clickable ? html` +
+ + View PDF +
+ ` : ''} `; } - private handleMouseEnter() { + protected getTileClickDetail(): Record { + return { + pdfUrl: this.pdfUrl, + pageCount: this.pageCount, + }; + } + + protected onBecameVisible(): void { + if (!this.rendered && this.pdfUrl) { + this.loadAndRenderPreview(); + } + } + + protected onTileMouseEnter(): void { this.isHovering = true; } - private handleMouseLeave() { + protected onTileMouseLeave(): void { this.isHovering = false; - // Reset to first page when not hovering if (this.currentPreviewPage !== 1) { this.currentPreviewPage = 1; void this.scheduleRenderPages(); } } - private handleMouseMove(e: MouseEvent) { + protected onTileMouseMove(e: MouseEvent): void { if (!this.isHovering || this.pageCount <= 1) return; const rect = this.getBoundingClientRect(); const x = e.clientX - rect.left; const width = rect.width; - // Calculate which page to show based on horizontal position const percentage = Math.max(0, Math.min(1, x / width)); const newPage = Math.ceil(percentage * this.pageCount) || 1; @@ -145,49 +117,21 @@ export class DeesPdfPreview extends DeesElement { } } - public async connectedCallback() { + public async connectedCallback(): Promise { await super.connectedCallback(); - this.setupIntersectionObserver(); await this.updateComplete; this.cacheElements(); this.setupResizeObserver(); } - public async disconnectedCallback() { + public async disconnectedCallback(): Promise { await super.disconnectedCallback(); this.cleanup(); - if (this.observer) { - this.observer.disconnect(); - } this.resizeObserver?.disconnect(); this.resizeObserver = undefined; } - private setupIntersectionObserver() { - const options = { - root: null, - rootMargin: '200px', - threshold: 0.01, - }; - - this.observer = new IntersectionObserver( - throttle((entries) => { - for (const entry of entries) { - if (entry.isIntersecting && !this.rendered && this.pdfUrl) { - this.loadAndRenderPreview(); - } else if (!entry.isIntersecting && this.rendered) { - // Optional: Clear canvases when out of view for memory optimization - // this.clearCanvases(); - } - } - }, 100), - options - ); - - this.observer.observe(this); - } - - private async loadAndRenderPreview() { + private async loadAndRenderPreview(): Promise { if (this.rendered || this.loading) return; this.loading = true; @@ -200,20 +144,17 @@ export class DeesPdfPreview extends DeesElement { this.currentPreviewPage = 1; this.loadedPdfUrl = this.pdfUrl; - // Force an update to ensure the canvas element is in the DOM this.loading = false; await this.updateComplete; this.cacheElements(); - // Now render the first page await this.scheduleRenderPages(); - this.rendered = true; const duration = PerformanceMonitor.measure(`preview-render-${this.pdfUrl}`, `preview-load-${this.pdfUrl}`); - console.log(`PDF preview rendered in ${duration}ms`); + console.log(`PDF tile rendered in ${duration}ms`); } catch (error) { - console.error('Failed to load PDF preview:', error); + console.error('Failed to load PDF tile:', error); this.error = true; this.loading = false; } @@ -233,7 +174,7 @@ export class DeesPdfPreview extends DeesElement { try { await this.performRenderPages(); } catch (error) { - console.error('Failed to render PDF preview pages:', error); + console.error('Failed to render PDF tile pages:', error); } })().finally(() => { this.renderPagesTask = null; @@ -246,64 +187,44 @@ export class DeesPdfPreview extends DeesElement { return this.renderPagesTask; } - private async performRenderPages() { + private async performRenderPages(): Promise { if (!this.pdfDocument) return; - // Wait a frame to ensure DOM is ready await new Promise(resolve => requestAnimationFrame(resolve)); const canvas = this.shadowRoot?.querySelector('.preview-canvas') as HTMLCanvasElement; - if (!canvas) { - console.warn('Preview canvas not found in DOM'); - return; - } + if (!canvas) return; - // Release old canvases this.clearCanvases(); - this.cacheElements(); - // Get available size for the preview const { availableWidth, availableHeight } = this.getAvailableSize(); try { - // Get the page to render const pageNum = this.currentPreviewPage; const page = await this.pdfDocument.getPage(pageNum); - // Calculate scale to fit within available area while keeping aspect ratio - // Use higher scale for sharper rendering const initialViewport = page.getViewport({ scale: 1 }); - - // Check if this is standard paper format (A4 or US Letter) const aspectRatio = initialViewport.height / initialViewport.width; - // Common paper format ratios - const a4PortraitRatio = 1.414; // 297mm / 210mm - const a4LandscapeRatio = 0.707; // 210mm / 297mm - const letterPortraitRatio = 1.294; // 11" / 8.5" - const letterLandscapeRatio = 0.773; // 8.5" / 11" - - // Check for standard formats with 5% tolerance + const a4PortraitRatio = 1.414; + const a4LandscapeRatio = 0.707; + const letterPortraitRatio = 1.294; + const letterLandscapeRatio = 0.773; const tolerance = 0.05; + const isA4Portrait = Math.abs(aspectRatio - a4PortraitRatio) < (a4PortraitRatio * tolerance); const isA4Landscape = Math.abs(aspectRatio - a4LandscapeRatio) < (a4LandscapeRatio * tolerance); const isLetterPortrait = Math.abs(aspectRatio - letterPortraitRatio) < (letterPortraitRatio * tolerance); const isLetterLandscape = Math.abs(aspectRatio - letterLandscapeRatio) < (letterLandscapeRatio * tolerance); - // Consider it standard format if it matches A4 or US Letter this.isA4Format = isA4Portrait || isA4Landscape || isLetterPortrait || isLetterLandscape; - // Debug logging - console.log(`PDF aspect ratio: ${aspectRatio.toFixed(3)}, standard format: ${this.isA4Format}`) - - // Adjust available size for non-A4 documents (account for padding) const adjustedWidth = this.isA4Format ? availableWidth : availableWidth - 24; const adjustedHeight = this.isA4Format ? availableHeight : availableHeight - 24; const scaleX = adjustedWidth > 0 ? adjustedWidth / initialViewport.width : 0; const scaleY = adjustedHeight > 0 ? adjustedHeight / initialViewport.height : 0; - // Increase scale by 2x for sharper rendering, but limit to 3.0 max const baseScale = Math.min(scaleX || 0.5, scaleY || scaleX || 0.5); const renderScale = Math.min(baseScale * 2, 3.0); @@ -314,11 +235,9 @@ export class DeesPdfPreview extends DeesElement { const viewport = page.getViewport({ scale: renderScale }); - // Acquire canvas from pool const pooledCanvas = CanvasPool.acquire(viewport.width, viewport.height); this.canvases.push(pooledCanvas); - // Render to pooled canvas first const renderContext = { canvasContext: pooledCanvas.ctx, viewport: viewport, @@ -326,17 +245,12 @@ export class DeesPdfPreview extends DeesElement { await page.render(renderContext).promise; - // Transfer to display canvas - // Set actual canvas resolution for sharpness canvas.width = viewport.width; canvas.height = viewport.height; - // Scale down display size to fit the container while keeping high resolution - // For A4, fill the container; for non-A4, respect padding const displayWidth = adjustedWidth; const displayHeight = (viewport.height / viewport.width) * adjustedWidth; - // If it fits height-wise better, scale by height instead if (displayHeight > adjustedHeight) { const altDisplayHeight = adjustedHeight; const altDisplayWidth = (viewport.width / viewport.height) * adjustedHeight; @@ -349,28 +263,25 @@ export class DeesPdfPreview extends DeesElement { const ctx = canvas.getContext('2d'); if (ctx) { - // Enable image smoothing for better quality ctx.imageSmoothingEnabled = true; ctx.imageSmoothingQuality = 'high'; ctx.drawImage(pooledCanvas.canvas, 0, 0); } - // Release page to free memory page.cleanup(); } catch (error) { console.error(`Failed to render page ${this.currentPreviewPage}:`, error); } } - private clearCanvases() { - // Release pooled canvases + private clearCanvases(): void { for (const pooledCanvas of this.canvases) { CanvasPool.release(pooledCanvas); } this.canvases = []; } - private cleanup() { + private cleanup(): void { this.clearCanvases(); if (this.pdfDocument) { @@ -379,12 +290,10 @@ export class DeesPdfPreview extends DeesElement { } this.renderPagesQueued = false; - this.pageCount = 0; this.currentPreviewPage = 1; this.isHovering = false; this.isA4Format = true; - this.previewContainer = null; this.stackElement = null; this.loadedPdfUrl = null; this.rendered = false; @@ -392,21 +301,7 @@ export class DeesPdfPreview extends DeesElement { this.error = false; } - private handleClick() { - if (!this.clickable) return; - - // Dispatch custom event for parent to handle - this.dispatchEvent(new CustomEvent('pdf-preview-click', { - detail: { - pdfUrl: this.pdfUrl, - pageCount: this.pageCount, - }, - bubbles: true, - composed: true, - })); - } - - public async updated(changedProperties: Map) { + public async updated(changedProperties: Map): Promise { super.updated(changedProperties); if (changedProperties.has('pdfUrl') && this.pdfUrl) { @@ -418,12 +313,9 @@ export class DeesPdfPreview extends DeesElement { this.rendered = false; this.currentPreviewPage = 1; - // Check if in viewport and render if so - if (this.observer) { - const rect = this.getBoundingClientRect(); - if (rect.top < window.innerHeight && rect.bottom > 0) { - this.loadAndRenderPreview(); - } + const rect = this.getBoundingClientRect(); + if (rect.top < window.innerHeight && rect.bottom > 0) { + this.loadAndRenderPreview(); } } @@ -432,19 +324,19 @@ export class DeesPdfPreview extends DeesElement { } } - /** - * Provide context menu items for right-click functionality - */ - public getContextMenuItems() { + public getContextMenuItems(): any[] { const items: any[] = []; - // If clickable, add option to view the PDF if (this.clickable) { items.push({ name: 'View PDF', iconName: 'lucide:Eye', action: async () => { - this.handleClick(); + this.dispatchEvent(new CustomEvent('tile-click', { + detail: this.getTileClickDetail(), + bubbles: true, + composed: true, + })); } }); items.push({ divider: true }); @@ -478,7 +370,6 @@ export class DeesPdfPreview extends DeesElement { } ); - // Add page count info as a disabled item if (this.pageCount > 0) { items.push( { divider: true }, @@ -494,17 +385,14 @@ export class DeesPdfPreview extends DeesElement { return items; } - private cacheElements() { - if (!this.previewContainer) { - this.previewContainer = this.shadowRoot?.querySelector('.preview-container') as HTMLElement; - } + private cacheElements(): void { if (!this.stackElement) { this.stackElement = this.shadowRoot?.querySelector('.preview-stack') as HTMLElement; } } - private setupResizeObserver() { - if (!this.previewContainer || this.resizeObserver) return; + private setupResizeObserver(): void { + if (this.resizeObserver) return; this.resizeObserver = new ResizeObserver(() => { if (this.rendered && this.pdfDocument && !this.loading) { @@ -515,18 +403,13 @@ export class DeesPdfPreview extends DeesElement { this.resizeObserver.observe(this); } - private getAvailableSize() { + private getAvailableSize(): { availableWidth: number; availableHeight: number } { if (!this.stackElement) { - // Try to get the stack element if it's not cached this.stackElement = this.shadowRoot?.querySelector('.preview-stack') as HTMLElement; } if (!this.stackElement) { - // Fallback to default size if element not found - return { - availableWidth: 200, // Full container width - availableHeight: 260, // Full container height - }; + return { availableWidth: 200, availableHeight: 260 }; } const rect = this.stackElement.getBoundingClientRect(); diff --git a/ts_web/elements/00group-media/dees-tile-pdf/demo.ts b/ts_web/elements/00group-media/dees-tile-pdf/demo.ts new file mode 100644 index 0000000..6398098 --- /dev/null +++ b/ts_web/elements/00group-media/dees-tile-pdf/demo.ts @@ -0,0 +1,128 @@ +import { html } from '@design.estate/dees-element'; + +export const demo = () => { + const samplePdfs = [ + 'https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/examples/learning/helloworld.pdf', + 'https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/web/compressed.tracemonkey-pldi-09.pdf', + ]; + + const generateGridItems = (count: number) => { + const items = []; + for (let i = 0; i < count; i++) { + const pdfUrl = samplePdfs[i % samplePdfs.length]; + items.push(html` + { + console.log('PDF Tile clicked:', e.detail); + alert(`PDF clicked: ${e.detail.pageCount} pages`); + }} + > + `); + } + return items; + }; + + return html` + + +
+
+

Single PDF Tile

+ +
+ +
+

Different Sizes

+
+
Small:
+ +
+ +
+
Default:
+ +
+ +
+
Large:
+ +
+
+ +
+

With Label

+ +
+ +
+

Non-Clickable

+ +
+ +
+

Grid - 20 PDFs with Lazy Loading

+
+ ${generateGridItems(20)} +
+
+
+ `; +}; diff --git a/ts_web/elements/00group-media/dees-tile-pdf/index.ts b/ts_web/elements/00group-media/dees-tile-pdf/index.ts new file mode 100644 index 0000000..16900c4 --- /dev/null +++ b/ts_web/elements/00group-media/dees-tile-pdf/index.ts @@ -0,0 +1 @@ +export * from './component.js'; diff --git a/ts_web/elements/00group-media/dees-tile-pdf/styles.ts b/ts_web/elements/00group-media/dees-tile-pdf/styles.ts new file mode 100644 index 0000000..6efbc22 --- /dev/null +++ b/ts_web/elements/00group-media/dees-tile-pdf/styles.ts @@ -0,0 +1,61 @@ +import { css, cssManager } from '@design.estate/dees-element'; + +export const tilePdfStyles = css` + .preview-stack { + position: relative; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + box-sizing: border-box; + overflow: hidden; + } + + .preview-stack.non-a4 { + padding: 12px; + } + + .preview-canvas { + position: relative; + background: white; + display: block; + max-width: 100%; + max-height: 100%; + width: auto; + height: auto; + object-fit: contain; + image-rendering: auto; + -webkit-font-smoothing: antialiased; + box-shadow: 0 1px 3px ${cssManager.bdTheme('rgba(0, 0, 0, 0.1)', 'rgba(0, 0, 0, 0.3)')}; + } + + .non-a4 .preview-canvas { + border: 1px solid ${cssManager.bdTheme('hsl(214 31% 92%)', 'hsl(217 25% 24%)')}; + border-radius: 4px; + } + + .preview-page-indicator { + position: absolute; + top: 8px; + left: 8px; + right: 8px; + padding: 5px 8px; + background: ${cssManager.bdTheme('hsl(0 0% 0% / 0.7)', 'hsl(0 0% 100% / 0.9)')}; + color: ${cssManager.bdTheme('white', 'hsl(215 20% 12%)')}; + border-radius: 4px; + font-size: 11px; + font-weight: 600; + text-align: center; + backdrop-filter: blur(12px); + z-index: 15; + pointer-events: none; + animation: fadeIn 0.2s ease; + } + + /* Grid optimizations */ + :host([grid-mode]) .preview-canvas { + image-rendering: -webkit-optimize-contrast; + image-rendering: crisp-edges; + } +`; diff --git a/ts_web/elements/00group-media/dees-tile-shared/DeesTileBase.ts b/ts_web/elements/00group-media/dees-tile-shared/DeesTileBase.ts new file mode 100644 index 0000000..b91734b --- /dev/null +++ b/ts_web/elements/00group-media/dees-tile-shared/DeesTileBase.ts @@ -0,0 +1,130 @@ +import { + DeesElement, + html, + property, + type TemplateResult, + type CSSResult, +} from '@design.estate/dees-element'; +import { tileBaseStyles } from './styles.js'; +import '../../00group-utility/dees-icon/dees-icon.js'; + +export abstract class DeesTileBase extends DeesElement { + public static styles: CSSResult[] = tileBaseStyles as any; + + @property({ type: Boolean }) + accessor clickable: boolean = true; + + @property({ type: Boolean }) + accessor loading: boolean = false; + + @property({ type: Boolean }) + accessor error: boolean = false; + + @property({ type: String, reflect: true }) + accessor size: 'small' | 'default' | 'large' = 'default'; + + @property({ type: String }) + accessor label: string = ''; + + private observer: IntersectionObserver | undefined; + private _visible: boolean = false; + + /** Whether this tile is currently visible in the viewport */ + protected get isVisible(): boolean { + return this._visible; + } + + public render(): TemplateResult { + return html` +
+ ${this.loading ? html` +
+
+
Loading...
+
+ ` : ''} + + ${this.error ? html` +
+ +
Failed to load
+
+ ` : ''} + + ${!this.loading && !this.error ? this.renderTileContent() : ''} + + ${this.label ? html` +
${this.label}
+ ` : ''} +
+ `; + } + + /** Subclasses implement this to render their specific content */ + protected abstract renderTileContent(): TemplateResult; + + public async connectedCallback(): Promise { + await super.connectedCallback(); + this.setupIntersectionObserver(); + } + + public async disconnectedCallback(): Promise { + await super.disconnectedCallback(); + if (this.observer) { + this.observer.disconnect(); + this.observer = undefined; + } + } + + private setupIntersectionObserver(): void { + this.observer = new IntersectionObserver( + (entries) => { + for (const entry of entries) { + const wasVisible = this._visible; + this._visible = entry.isIntersecting; + if (this._visible && !wasVisible) { + this.onBecameVisible(); + } + } + }, + { root: null, rootMargin: '200px', threshold: 0.01 } + ); + this.observer.observe(this); + } + + /** Called when the tile first enters the viewport. Override for lazy loading. */ + protected onBecameVisible(): void { + // Subclasses can override + } + + /** Called when mouse enters the tile container. Override in subclasses. */ + protected onTileMouseEnter(): void {} + + /** Called when mouse leaves the tile container. Override in subclasses. */ + protected onTileMouseLeave(): void {} + + /** Called when mouse moves over the tile container. Override in subclasses. */ + protected onTileMouseMove(_e: MouseEvent): void {} + + protected handleTileClick(): void { + if (!this.clickable) return; + this.dispatchEvent( + new CustomEvent('tile-click', { + detail: this.getTileClickDetail(), + bubbles: true, + composed: true, + }) + ); + } + + /** Return the detail object for tile-click events. Override in subclasses. */ + protected getTileClickDetail(): Record { + return {}; + } +} diff --git a/ts_web/elements/00group-media/dees-tile-shared/index.ts b/ts_web/elements/00group-media/dees-tile-shared/index.ts new file mode 100644 index 0000000..542c362 --- /dev/null +++ b/ts_web/elements/00group-media/dees-tile-shared/index.ts @@ -0,0 +1,2 @@ +export { DeesTileBase } from './DeesTileBase.js'; +export { tileBaseStyles } from './styles.js'; diff --git a/ts_web/elements/00group-media/dees-tile-shared/styles.ts b/ts_web/elements/00group-media/dees-tile-shared/styles.ts new file mode 100644 index 0000000..17a24ac --- /dev/null +++ b/ts_web/elements/00group-media/dees-tile-shared/styles.ts @@ -0,0 +1,213 @@ +import { css, cssManager } from '@design.estate/dees-element'; + +export const tileBaseStyles = [ + cssManager.defaultStyles, + css` + :host { + display: inline-block; + position: relative; + } + + .tile-container { + position: relative; + width: 200px; + height: 260px; + background: ${cssManager.bdTheme('hsl(0 0% 98%)', 'hsl(215 20% 14%)')}; + border-radius: 4px; + overflow: hidden; + transition: transform 0.2s ease, box-shadow 0.2s ease; + box-shadow: 0 1px 3px ${cssManager.bdTheme('rgba(0, 0, 0, 0.12)', 'rgba(0, 0, 0, 0.24)')}; + } + + .tile-container.clickable { + cursor: pointer; + } + + .tile-container.clickable:hover { + transform: translateY(-2px); + box-shadow: 0 8px 24px ${cssManager.bdTheme('rgba(0, 0, 0, 0.12)', 'rgba(0, 0, 0, 0.3)')}; + } + + .tile-container.clickable:hover .tile-overlay { + opacity: 1; + } + + .tile-content { + position: relative; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + box-sizing: border-box; + overflow: hidden; + } + + .tile-overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.7)', 'rgba(0, 0, 0, 0.8)')}; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 8px; + opacity: 0; + transition: opacity 0.2s ease; + z-index: 20; + } + + .tile-overlay dees-icon { + font-size: 24px; + color: white; + } + + .tile-overlay span { + font-size: 14px; + font-weight: 500; + color: white; + } + + .tile-info { + position: absolute; + bottom: 8px; + left: 8px; + right: 8px; + padding: 6px 10px; + background: ${cssManager.bdTheme('hsl(0 0% 100% / 0.92)', 'hsl(215 20% 12% / 0.92)')}; + border-radius: 6px; + display: flex; + align-items: center; + gap: 6px; + font-size: 12px; + color: ${cssManager.bdTheme('hsl(215 16% 45%)', 'hsl(215 16% 75%)')}; + backdrop-filter: blur(12px); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + z-index: 10; + } + + .tile-info dees-icon { + font-size: 13px; + color: ${cssManager.bdTheme('hsl(217 91% 60%)', 'hsl(213 93% 68%)')}; + } + + .tile-info-text { + font-weight: 500; + font-size: 11px; + } + + .tile-badge { + position: absolute; + top: 8px; + left: 8px; + right: 8px; + padding: 5px 8px; + background: ${cssManager.bdTheme('hsl(0 0% 0% / 0.7)', 'hsl(0 0% 100% / 0.9)')}; + color: ${cssManager.bdTheme('white', 'hsl(215 20% 12%)')}; + border-radius: 4px; + font-size: 11px; + font-weight: 600; + text-align: center; + backdrop-filter: blur(12px); + z-index: 15; + pointer-events: none; + animation: fadeIn 0.2s ease; + } + + .tile-loading, + .tile-error { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 12px; + color: ${cssManager.bdTheme('hsl(215 16% 45%)', 'hsl(215 16% 75%)')}; + } + + .tile-loading { + background: ${cssManager.bdTheme('hsl(0 0% 99%)', 'hsl(215 20% 14%)')}; + } + + .tile-error { + background: ${cssManager.bdTheme('hsl(0 72% 98%)', 'hsl(0 62% 20%)')}; + color: ${cssManager.bdTheme('hsl(0 72% 40%)', 'hsl(0 70% 68%)')}; + } + + .tile-error dees-icon { + font-size: 32px; + } + + .tile-spinner { + width: 24px; + height: 24px; + border-radius: 50%; + border: 2px solid ${cssManager.bdTheme('hsl(214 31% 86%)', 'hsl(217 25% 28%)')}; + border-top-color: ${cssManager.bdTheme('hsl(217 91% 60%)', 'hsl(213 93% 68%)')}; + animation: spin 0.8s linear infinite; + } + + .tile-loading-text, + .tile-error-text { + font-size: 13px; + font-weight: 500; + } + + .tile-label { + position: absolute; + bottom: 0; + left: 0; + right: 0; + padding: 6px 10px; + background: ${cssManager.bdTheme('hsl(0 0% 100% / 0.95)', 'hsl(215 20% 12% / 0.95)')}; + font-size: 11px; + font-weight: 500; + color: ${cssManager.bdTheme('hsl(215 16% 35%)', 'hsl(215 16% 75%)')}; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + z-index: 10; + backdrop-filter: blur(12px); + } + + @keyframes spin { + to { + transform: rotate(360deg); + } + } + + @keyframes fadeIn { + from { + opacity: 0; + transform: translateY(-4px); + } + to { + opacity: 1; + transform: translateY(0); + } + } + + /* Size variants */ + :host([size="small"]) .tile-container { + width: 150px; + height: 195px; + } + + :host([size="large"]) .tile-container { + width: 250px; + height: 325px; + } + + /* Grid optimizations */ + :host([grid-mode]) .tile-container { + will-change: auto; + } + `, +]; diff --git a/ts_web/elements/00group-media/dees-tile-video/component.ts b/ts_web/elements/00group-media/dees-tile-video/component.ts new file mode 100644 index 0000000..9c49058 --- /dev/null +++ b/ts_web/elements/00group-media/dees-tile-video/component.ts @@ -0,0 +1,317 @@ +import { + property, + state, + html, + customElement, + css, + cssManager, + type TemplateResult, + type CSSResult, +} from '@design.estate/dees-element'; +import { DeesTileBase } from '../dees-tile-shared/DeesTileBase.js'; +import { tileBaseStyles } from '../dees-tile-shared/styles.js'; +import { demo } from './demo.js'; + +declare global { + interface HTMLElementTagNameMap { + 'dees-tile-video': DeesTileVideo; + } +} + +@customElement('dees-tile-video') +export class DeesTileVideo extends DeesTileBase { + public static demo = demo; + public static demoGroups = ['Media']; + public static styles = [ + ...tileBaseStyles, + css` + .video-wrapper { + position: relative; + width: 100%; + height: 100%; + overflow: hidden; + background: #000; + } + + .video-wrapper video { + width: 100%; + height: 100%; + object-fit: cover; + display: block; + } + + .video-wrapper canvas { + width: 100%; + height: 100%; + object-fit: cover; + display: block; + } + + .poster-image { + width: 100%; + height: 100%; + object-fit: cover; + display: block; + } + + .duration-badge { + position: absolute; + bottom: 8px; + right: 8px; + padding: 3px 8px; + background: rgba(0, 0, 0, 0.7); + color: white; + border-radius: 4px; + font-size: 10px; + font-weight: 600; + font-variant-numeric: tabular-nums; + backdrop-filter: blur(8px); + z-index: 10; + } + + .play-overlay { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 48px; + height: 48px; + border-radius: 50%; + background: rgba(0, 0, 0, 0.6); + display: flex; + align-items: center; + justify-content: center; + z-index: 15; + pointer-events: none; + transition: opacity 0.2s ease; + } + + .play-overlay dees-icon { + font-size: 20px; + color: white; + } + + .tile-container.clickable:hover .play-overlay { + opacity: 0; + } + + .video-hover-preview { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + object-fit: cover; + z-index: 5; + opacity: 0; + transition: opacity 0.3s ease; + } + + .video-hover-preview.active { + opacity: 1; + } + `, + ] as any; + + @property({ type: String }) + accessor src: string = ''; + + @property({ type: String }) + accessor poster: string = ''; + + @state() + accessor duration: number = 0; + + @state() + accessor thumbnailCaptured: boolean = false; + + @state() + accessor isHovering: boolean = false; + + private thumbnailCanvas: HTMLCanvasElement | null = null; + private hoverVideo: HTMLVideoElement | null = null; + private hasStartedLoading: boolean = false; + + protected renderTileContent(): TemplateResult { + return html` +
+ ${this.poster ? html` + + ` : this.thumbnailCaptured ? html` + + ` : html` +
+ `} + + ${this.isHovering && this.src ? html` + + ` : ''} +
+ + ${this.duration > 0 ? html` +
${this.formatTime(this.duration)}
+ ` : ''} + + ${!this.isHovering ? html` +
+ +
+ ` : ''} + + ${this.clickable ? html` +
+ + Play Video +
+ ` : ''} + `; + } + + protected getTileClickDetail(): Record { + return { + src: this.src, + poster: this.poster, + duration: this.duration, + }; + } + + protected onBecameVisible(): void { + if (!this.hasStartedLoading && this.src) { + this.hasStartedLoading = true; + this.captureFirstFrame(); + } + } + + private async captureFirstFrame(): Promise { + if (this.poster) { + // If poster is provided, just load duration + this.loadDuration(); + return; + } + + this.loading = true; + + try { + const video = document.createElement('video'); + video.crossOrigin = 'anonymous'; + video.muted = true; + video.preload = 'metadata'; + + await new Promise((resolve, reject) => { + video.addEventListener('loadeddata', () => { + this.duration = video.duration; + + // Capture the first frame + video.currentTime = 0.1; // Slightly after start for better frame + video.addEventListener('seeked', () => { + const canvas = document.createElement('canvas'); + canvas.width = video.videoWidth; + canvas.height = video.videoHeight; + const ctx = canvas.getContext('2d'); + if (ctx) { + ctx.drawImage(video, 0, 0); + this.thumbnailCanvas = canvas; + this.thumbnailCaptured = true; + } + + // Clean up + video.src = ''; + video.load(); + resolve(); + }, { once: true }); + }, { once: true }); + + video.addEventListener('error', () => reject(new Error('Failed to load video')), { once: true }); + video.src = this.src; + }); + + this.loading = false; + + // Copy thumbnail to shadow DOM canvas + await this.updateComplete; + this.copyThumbnailToCanvas(); + } catch { + this.loading = false; + // Don't set error for thumbnail failure + this.loadDuration(); + } + } + + private loadDuration(): void { + const video = document.createElement('video'); + video.preload = 'metadata'; + video.addEventListener('loadedmetadata', () => { + this.duration = video.duration; + video.src = ''; + video.load(); + }); + video.src = this.src; + } + + private copyThumbnailToCanvas(): void { + if (!this.thumbnailCanvas) return; + const canvas = this.shadowRoot?.querySelector('.video-wrapper canvas') as HTMLCanvasElement; + if (!canvas) return; + + canvas.width = this.thumbnailCanvas.width; + canvas.height = this.thumbnailCanvas.height; + const ctx = canvas.getContext('2d'); + if (ctx) { + ctx.drawImage(this.thumbnailCanvas, 0, 0); + } + } + + protected onTileMouseEnter(): void { + this.isHovering = true; + } + + protected onTileMouseLeave(): void { + this.isHovering = false; + // The video element will be removed from DOM by the template + this.hoverVideo = null; + } + + private handleHoverVideoLoaded(e: Event): void { + this.hoverVideo = e.target as HTMLVideoElement; + this.hoverVideo.play().catch(() => { + // Autoplay may be blocked + }); + } + + public async updated(changedProperties: Map): Promise { + super.updated(changedProperties); + if (changedProperties.has('src') && this.src && this.isVisible) { + this.hasStartedLoading = true; + this.thumbnailCaptured = false; + this.duration = 0; + this.captureFirstFrame(); + } + if (changedProperties.has('thumbnailCaptured') && this.thumbnailCaptured) { + await this.updateComplete; + this.copyThumbnailToCanvas(); + } + } + + public async disconnectedCallback(): Promise { + await super.disconnectedCallback(); + if (this.hoverVideo) { + this.hoverVideo.pause(); + this.hoverVideo.src = ''; + this.hoverVideo = null; + } + this.thumbnailCanvas = null; + } + + private formatTime(seconds: number): string { + if (!isFinite(seconds) || seconds < 0) return '0:00'; + const mins = Math.floor(seconds / 60); + const secs = Math.floor(seconds % 60); + return `${mins}:${secs.toString().padStart(2, '0')}`; + } +} diff --git a/ts_web/elements/00group-media/dees-tile-video/demo.ts b/ts_web/elements/00group-media/dees-tile-video/demo.ts new file mode 100644 index 0000000..5d69b98 --- /dev/null +++ b/ts_web/elements/00group-media/dees-tile-video/demo.ts @@ -0,0 +1,79 @@ +import { html } from '@design.estate/dees-element'; + +export const demo = () => html` + + +
+
+

Video Tiles

+
+ console.log('Video clicked:', e.detail)} + > + + + + +
+
+ +
+

Size Variants

+
+ + + + + +
+
+ +
+

With Poster Image

+ +
+
+`; diff --git a/ts_web/elements/00group-media/dees-tile-video/index.ts b/ts_web/elements/00group-media/dees-tile-video/index.ts new file mode 100644 index 0000000..16900c4 --- /dev/null +++ b/ts_web/elements/00group-media/dees-tile-video/index.ts @@ -0,0 +1 @@ +export * from './component.js'; diff --git a/ts_web/elements/00group-media/dees-video-viewer/component.ts b/ts_web/elements/00group-media/dees-video-viewer/component.ts new file mode 100644 index 0000000..7651a68 --- /dev/null +++ b/ts_web/elements/00group-media/dees-video-viewer/component.ts @@ -0,0 +1,506 @@ +import { + DeesElement, + html, + customElement, + type TemplateResult, + property, + state, + cssManager, +} from '@design.estate/dees-element'; +import '../../00group-utility/dees-icon/dees-icon.js'; +import { demo } from './demo.js'; + +declare global { + interface HTMLElementTagNameMap { + 'dees-video-viewer': DeesVideoViewer; + } +} + +@customElement('dees-video-viewer') +export class DeesVideoViewer extends DeesElement { + public static demo = demo; + public static demoGroups = ['Media']; + + @property() + accessor src: string = ''; + + @property() + accessor poster: string = ''; + + @property({ type: Boolean }) + accessor showControls: boolean = true; + + @property({ type: Boolean }) + accessor autoplay: boolean = false; + + @property({ type: Boolean }) + accessor loop: boolean = false; + + @property({ type: Boolean }) + accessor muted: boolean = false; + + @state() + accessor isPlaying: boolean = false; + + @state() + accessor currentTime: number = 0; + + @state() + accessor duration: number = 0; + + @state() + accessor volume: number = 1; + + @state() + accessor loading: boolean = true; + + @state() + accessor error: string = ''; + + @state() + accessor isFullscreen: boolean = false; + + @state() + accessor controlsVisible: boolean = true; + + private hideControlsTimer: ReturnType | null = null; + private videoElement: HTMLVideoElement | null = null; + + public render(): TemplateResult { + return html` + + +
+ + + ${this.showControls ? html` +
+
+ +
+ +
e.stopPropagation()}> +
+
+
+ +
+ + + + ${this.formatTime(this.currentTime)} / ${this.formatTime(this.duration)} + + + + +
+ + +
+ + +
+
+
+ ` : ''} + + ${this.loading && !this.error ? html` +
+
+
+ ` : ''} + + ${this.error ? html` +
+ + ${this.error} +
+ ` : ''} +
+ `; + } + + public async firstUpdated(): Promise { + this.videoElement = this.shadowRoot?.querySelector('video') || null; + document.addEventListener('fullscreenchange', this.handleFullscreenChange); + } + + public async disconnectedCallback(): Promise { + await super.disconnectedCallback(); + document.removeEventListener('fullscreenchange', this.handleFullscreenChange); + if (this.hideControlsTimer) { + clearTimeout(this.hideControlsTimer); + } + } + + public play(): void { + this.videoElement?.play(); + } + + public pause(): void { + this.videoElement?.pause(); + } + + public togglePlay(): void { + if (this.isPlaying) { + this.pause(); + } else { + this.play(); + } + } + + public seek(time: number): void { + if (this.videoElement) { + this.videoElement.currentTime = time; + } + } + + public setVolume(v: number): void { + this.volume = Math.max(0, Math.min(1, v)); + if (this.videoElement) { + this.videoElement.volume = this.volume; + } + } + + public toggleFullscreen(): void { + const container = this.shadowRoot?.querySelector('.video-container') as HTMLElement; + if (!container) return; + + if (this.isFullscreen) { + document.exitFullscreen?.(); + } else { + container.requestFullscreen?.(); + } + } + + private handleLoadedMetadata(): void { + if (this.videoElement) { + this.duration = this.videoElement.duration; + this.loading = false; + } + } + + private handlePlay(): void { + this.isPlaying = true; + this.scheduleHideControls(); + } + + private handlePause(): void { + this.isPlaying = false; + this.controlsVisible = true; + } + + private handleEnded(): void { + this.isPlaying = false; + this.controlsVisible = true; + } + + private handleTimeUpdate(): void { + if (this.videoElement) { + this.currentTime = this.videoElement.currentTime; + } + } + + private handleError(): void { + this.error = 'Failed to load video'; + this.loading = false; + } + + private handleOverlayClick(): void { + this.togglePlay(); + } + + private handleSeek(e: MouseEvent): void { + const rect = (e.currentTarget as HTMLElement).getBoundingClientRect(); + const ratio = (e.clientX - rect.left) / rect.width; + this.seek(ratio * this.duration); + } + + private handleVolumeChange(e: Event): void { + const value = parseFloat((e.target as HTMLInputElement).value); + this.setVolume(value); + this.muted = value === 0; + } + + private toggleMute(): void { + this.muted = !this.muted; + if (this.videoElement) { + this.videoElement.muted = this.muted; + } + } + + private handleMouseMove(): void { + this.controlsVisible = true; + this.scheduleHideControls(); + } + + private handleMouseLeave(): void { + if (this.isPlaying) { + this.controlsVisible = false; + } + } + + private scheduleHideControls(): void { + if (this.hideControlsTimer) { + clearTimeout(this.hideControlsTimer); + } + if (this.isPlaying) { + this.hideControlsTimer = setTimeout(() => { + this.controlsVisible = false; + }, 3000); + } + } + + private handleFullscreenChange = (): void => { + this.isFullscreen = !!document.fullscreenElement; + }; + + private formatTime(seconds: number): string { + if (!isFinite(seconds) || seconds < 0) return '0:00'; + const mins = Math.floor(seconds / 60); + const secs = Math.floor(seconds % 60); + return `${mins}:${secs.toString().padStart(2, '0')}`; + } +} diff --git a/ts_web/elements/00group-media/dees-video-viewer/demo.ts b/ts_web/elements/00group-media/dees-video-viewer/demo.ts new file mode 100644 index 0000000..7575d75 --- /dev/null +++ b/ts_web/elements/00group-media/dees-video-viewer/demo.ts @@ -0,0 +1,63 @@ +import { html, cssManager } from '@design.estate/dees-element'; + +export const demo = () => html` + + +
+
+
Video with Custom Controls
+
A video player with overlay controls, seeking, and volume adjustment.
+ +
+ +
+
Autoplay Muted
+
Video that autoplays muted, commonly used for previews.
+ +
+ +
+
Native Controls
+
Video using browser-native controls instead of custom overlay.
+ +
+
+`; diff --git a/ts_web/elements/00group-media/dees-video-viewer/index.ts b/ts_web/elements/00group-media/dees-video-viewer/index.ts new file mode 100644 index 0000000..16900c4 --- /dev/null +++ b/ts_web/elements/00group-media/dees-video-viewer/index.ts @@ -0,0 +1 @@ +export * from './component.js'; diff --git a/ts_web/elements/00group-media/index.ts b/ts_web/elements/00group-media/index.ts new file mode 100644 index 0000000..6d97d45 --- /dev/null +++ b/ts_web/elements/00group-media/index.ts @@ -0,0 +1,20 @@ +// Media Viewer Components +export * from './dees-image-viewer/index.js'; +export * from './dees-audio-viewer/index.js'; +export * from './dees-video-viewer/index.js'; +export * from './dees-preview/index.js'; + +// PDF Components +export * from './dees-pdf/index.js'; // @deprecated - Use dees-pdf-viewer or dees-tile-pdf instead +export * from './dees-pdf-preview/index.js'; // @deprecated - Use dees-tile-pdf instead +export * from './dees-pdf-shared/index.js'; +export * from './dees-pdf-viewer/index.js'; + +// Tile Components +export * from './dees-tile-shared/index.js'; +export * from './dees-tile-pdf/index.js'; +export * from './dees-tile-image/index.js'; +export * from './dees-tile-audio/index.js'; +export * from './dees-tile-video/index.js'; +export * from './dees-tile-note/index.js'; +export * from './dees-tile-folder/index.js'; diff --git a/ts_web/elements/dees-contextmenu/dees-contextmenu.demo.ts b/ts_web/elements/00group-overlay/dees-contextmenu/dees-contextmenu.demo.ts similarity index 99% rename from ts_web/elements/dees-contextmenu/dees-contextmenu.demo.ts rename to ts_web/elements/00group-overlay/dees-contextmenu/dees-contextmenu.demo.ts index baccce3..620b96f 100644 --- a/ts_web/elements/dees-contextmenu/dees-contextmenu.demo.ts +++ b/ts_web/elements/00group-overlay/dees-contextmenu/dees-contextmenu.demo.ts @@ -1,5 +1,5 @@ import { html } from '@design.estate/dees-element'; -import * as plugins from '../00plugins.js'; +import * as plugins from '../../00plugins.js'; import { DeesContextmenu } from '../dees-contextmenu/dees-contextmenu.js'; diff --git a/ts_web/elements/dees-contextmenu/dees-contextmenu.ts b/ts_web/elements/00group-overlay/dees-contextmenu/dees-contextmenu.ts similarity index 98% rename from ts_web/elements/dees-contextmenu/dees-contextmenu.ts rename to ts_web/elements/00group-overlay/dees-contextmenu/dees-contextmenu.ts index 1b198dc..def6063 100644 --- a/ts_web/elements/dees-contextmenu/dees-contextmenu.ts +++ b/ts_web/elements/00group-overlay/dees-contextmenu/dees-contextmenu.ts @@ -1,4 +1,4 @@ -import * as plugins from '../00plugins.js'; +import * as plugins from '../../00plugins.js'; import { demoFunc } from './dees-contextmenu.demo.js'; import { customElement, @@ -14,9 +14,9 @@ import { import * as domtools from '@design.estate/dees-domtools'; import { DeesWindowLayer } from '../dees-windowlayer/dees-windowlayer.js'; -import { zIndexLayers } from '../00zindex.js'; -import '../dees-icon/dees-icon.js'; -import { themeDefaultStyles } from '../00theme.js'; +import { zIndexLayers } from '../../00zindex.js'; +import '../../00group-utility/dees-icon/dees-icon.js'; +import { themeDefaultStyles } from '../../00theme.js'; declare global { interface HTMLElementTagNameMap { @@ -28,6 +28,7 @@ declare global { export class DeesContextmenu extends DeesElement { // DEMO public static demo = demoFunc + public static demoGroups = ['Overlay']; // STATIC // This will store all the accumulated menu items diff --git a/ts_web/elements/dees-contextmenu/index.ts b/ts_web/elements/00group-overlay/dees-contextmenu/index.ts similarity index 100% rename from ts_web/elements/dees-contextmenu/index.ts rename to ts_web/elements/00group-overlay/dees-contextmenu/index.ts diff --git a/ts_web/elements/dees-modal/dees-modal.demo.ts b/ts_web/elements/00group-overlay/dees-modal/dees-modal.demo.ts similarity index 100% rename from ts_web/elements/dees-modal/dees-modal.demo.ts rename to ts_web/elements/00group-overlay/dees-modal/dees-modal.demo.ts diff --git a/ts_web/elements/dees-modal/dees-modal.ts b/ts_web/elements/00group-overlay/dees-modal/dees-modal.ts similarity index 97% rename from ts_web/elements/dees-modal/dees-modal.ts rename to ts_web/elements/00group-overlay/dees-modal/dees-modal.ts index 8138a3a..2b9c19b 100644 --- a/ts_web/elements/dees-modal/dees-modal.ts +++ b/ts_web/elements/00group-overlay/dees-modal/dees-modal.ts @@ -1,7 +1,7 @@ -import * as colors from '../00colors.js'; -import * as plugins from '../00plugins.js'; -import { zIndexLayers, zIndexRegistry } from '../00zindex.js'; -import { cssGeistFontFamily } from '../00fonts.js'; +import * as colors from '../../00colors.js'; +import * as plugins from '../../00plugins.js'; +import { zIndexLayers, zIndexRegistry } from '../../00zindex.js'; +import { cssGeistFontFamily } from '../../00fonts.js'; import { demoFunc } from './dees-modal.demo.js'; import { @@ -20,8 +20,8 @@ import { import * as domtools from '@design.estate/dees-domtools'; import { DeesWindowLayer } from '../dees-windowlayer/dees-windowlayer.js'; -import '../dees-icon/dees-icon.js'; -import { themeDefaultStyles } from '../00theme.js'; +import '../../00group-utility/dees-icon/dees-icon.js'; +import { themeDefaultStyles } from '../../00theme.js'; declare global { interface HTMLElementTagNameMap { @@ -33,6 +33,7 @@ declare global { export class DeesModal extends DeesElement { // STATIC public static demo = demoFunc; + public static demoGroups = ['Overlay']; public static async createAndShow(optionsArg: { heading: string; diff --git a/ts_web/elements/dees-modal/index.ts b/ts_web/elements/00group-overlay/dees-modal/index.ts similarity index 100% rename from ts_web/elements/dees-modal/index.ts rename to ts_web/elements/00group-overlay/dees-modal/index.ts diff --git a/ts_web/elements/dees-speechbubble/dees-speechbubble.demo.ts b/ts_web/elements/00group-overlay/dees-speechbubble/dees-speechbubble.demo.ts similarity index 100% rename from ts_web/elements/dees-speechbubble/dees-speechbubble.demo.ts rename to ts_web/elements/00group-overlay/dees-speechbubble/dees-speechbubble.demo.ts diff --git a/ts_web/elements/dees-speechbubble/dees-speechbubble.ts b/ts_web/elements/00group-overlay/dees-speechbubble/dees-speechbubble.ts similarity index 96% rename from ts_web/elements/dees-speechbubble/dees-speechbubble.ts rename to ts_web/elements/00group-overlay/dees-speechbubble/dees-speechbubble.ts index 61b0901..9dfe225 100644 --- a/ts_web/elements/dees-speechbubble/dees-speechbubble.ts +++ b/ts_web/elements/00group-overlay/dees-speechbubble/dees-speechbubble.ts @@ -1,5 +1,5 @@ -import * as colors from '../00colors.js'; -import * as plugins from '../00plugins.js'; +import * as colors from '../../00colors.js'; +import * as plugins from '../../00plugins.js'; import { demoFunc } from './dees-speechbubble.demo.js'; import { @@ -17,7 +17,7 @@ import { unsafeHTML, } from '@design.estate/dees-element'; import { DeesWindowLayer } from '../dees-windowlayer/dees-windowlayer.js'; -import { themeDefaultStyles } from '../00theme.js'; +import { themeDefaultStyles } from '../../00theme.js'; declare global { interface HTMLElementTagNameMap { @@ -28,6 +28,7 @@ declare global { @customElement('dees-speechbubble') export class DeesSpeechbubble extends DeesElement { public static demo = demoFunc; + public static demoGroups = ['Overlay']; // STATIC public static async createAndShow(refElement: HTMLElement, textArg: string) { diff --git a/ts_web/elements/dees-speechbubble/index.ts b/ts_web/elements/00group-overlay/dees-speechbubble/index.ts similarity index 100% rename from ts_web/elements/dees-speechbubble/index.ts rename to ts_web/elements/00group-overlay/dees-speechbubble/index.ts diff --git a/ts_web/elements/dees-windowlayer/dees-windowlayer.ts b/ts_web/elements/00group-overlay/dees-windowlayer/dees-windowlayer.ts similarity index 97% rename from ts_web/elements/dees-windowlayer/dees-windowlayer.ts rename to ts_web/elements/00group-overlay/dees-windowlayer/dees-windowlayer.ts index 30787ca..4ce77a3 100644 --- a/ts_web/elements/dees-windowlayer/dees-windowlayer.ts +++ b/ts_web/elements/00group-overlay/dees-windowlayer/dees-windowlayer.ts @@ -1,5 +1,5 @@ import { customElement, DeesElement, domtools, type TemplateResult, html, property, type CSSResult, state, } from '@design.estate/dees-element'; -import { zIndexLayers, zIndexRegistry } from '../00zindex.js'; +import { zIndexLayers, zIndexRegistry } from '../../00zindex.js'; declare global { interface HTMLElementTagNameMap { @@ -15,6 +15,7 @@ export interface IOptions_DeesWindowLayer { export class DeesWindowLayer extends DeesElement { // STATIC public static demo = () => html``; + public static demoGroups = ['Overlay']; public static async createAndShow(optionsArg?: IOptions_DeesWindowLayer) { const domtoolsInstance = domtools.DomTools.getGlobalDomToolsSync(); diff --git a/ts_web/elements/dees-windowlayer/index.ts b/ts_web/elements/00group-overlay/dees-windowlayer/index.ts similarity index 100% rename from ts_web/elements/dees-windowlayer/index.ts rename to ts_web/elements/00group-overlay/dees-windowlayer/index.ts diff --git a/ts_web/elements/00group-overlay/index.ts b/ts_web/elements/00group-overlay/index.ts new file mode 100644 index 0000000..daf445a --- /dev/null +++ b/ts_web/elements/00group-overlay/index.ts @@ -0,0 +1,5 @@ +// Overlay Components +export * from './dees-contextmenu/index.js'; +export * from './dees-modal/index.js'; +export * from './dees-speechbubble/index.js'; +export * from './dees-windowlayer/index.js'; diff --git a/ts_web/elements/00group-pdf/index.ts b/ts_web/elements/00group-pdf/index.ts deleted file mode 100644 index cdb10cf..0000000 --- a/ts_web/elements/00group-pdf/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -// PDF Components -export * from './dees-pdf/index.js'; // @deprecated - Use dees-pdf-viewer or dees-pdf-preview instead -export * from './dees-pdf-preview/index.js'; -export * from './dees-pdf-shared/index.js'; -export * from './dees-pdf-viewer/index.js'; diff --git a/ts_web/elements/dees-shopping-productcard/dees-shopping-productcard.demo.ts b/ts_web/elements/00group-simple/dees-shopping-productcard/dees-shopping-productcard.demo.ts similarity index 99% rename from ts_web/elements/dees-shopping-productcard/dees-shopping-productcard.demo.ts rename to ts_web/elements/00group-simple/dees-shopping-productcard/dees-shopping-productcard.demo.ts index 7fd5a04..79d91d8 100644 --- a/ts_web/elements/dees-shopping-productcard/dees-shopping-productcard.demo.ts +++ b/ts_web/elements/00group-simple/dees-shopping-productcard/dees-shopping-productcard.demo.ts @@ -1,6 +1,6 @@ import { html, css, cssManager } from '@design.estate/dees-element'; import '@design.estate/dees-wcctools/demotools'; -import '../dees-panel/dees-panel.js'; +import '../../00group-layout/dees-panel/dees-panel.js'; import type { DeesShoppingProductcard } from '../dees-shopping-productcard/dees-shopping-productcard.js'; export const demoFunc = () => html` diff --git a/ts_web/elements/dees-shopping-productcard/dees-shopping-productcard.ts b/ts_web/elements/00group-simple/dees-shopping-productcard/dees-shopping-productcard.ts similarity index 98% rename from ts_web/elements/dees-shopping-productcard/dees-shopping-productcard.ts rename to ts_web/elements/00group-simple/dees-shopping-productcard/dees-shopping-productcard.ts index a0dc127..e2e8845 100644 --- a/ts_web/elements/dees-shopping-productcard/dees-shopping-productcard.ts +++ b/ts_web/elements/00group-simple/dees-shopping-productcard/dees-shopping-productcard.ts @@ -8,7 +8,7 @@ import { DeesElement, } from '@design.estate/dees-element'; import { demoFunc } from './dees-shopping-productcard.demo.js'; -import { themeDefaultStyles } from '../00theme.js'; +import { themeDefaultStyles } from '../../00theme.js'; declare global { interface HTMLElementTagNameMap { @@ -32,6 +32,7 @@ export interface IProductData { @customElement('dees-shopping-productcard') export class DeesShoppingProductcard extends DeesElement { public static demo = demoFunc; + public static demoGroups = ['Simple']; @property({ type: Object }) accessor productData: IProductData = { diff --git a/ts_web/elements/dees-shopping-productcard/index.ts b/ts_web/elements/00group-simple/dees-shopping-productcard/index.ts similarity index 100% rename from ts_web/elements/dees-shopping-productcard/index.ts rename to ts_web/elements/00group-simple/dees-shopping-productcard/index.ts diff --git a/ts_web/elements/00group-simple/dees-simple-appdash/dees-simple-appdash.demo.ts b/ts_web/elements/00group-simple/dees-simple-appdash/dees-simple-appdash.demo.ts index 0148ec2..5486ced 100644 --- a/ts_web/elements/00group-simple/dees-simple-appdash/dees-simple-appdash.demo.ts +++ b/ts_web/elements/00group-simple/dees-simple-appdash/dees-simple-appdash.demo.ts @@ -6,8 +6,8 @@ import '../../00group-input/dees-input-checkbox/dees-input-checkbox.js'; import '../../00group-input/dees-input-dropdown/dees-input-dropdown.js'; import '../../00group-input/dees-input-radiogroup/dees-input-radiogroup.js'; import '../../00group-form/dees-form-submit/dees-form-submit.js'; -import '../../dees-statsgrid/dees-statsgrid.js'; -import type { IStatsTile } from '../../dees-statsgrid/dees-statsgrid.js'; +import '../../00group-dataview/dees-statsgrid/dees-statsgrid.js'; +import type { IStatsTile } from '../../00group-dataview/dees-statsgrid/dees-statsgrid.js'; // Create demo view components @customElement('demo-view-dashboard') diff --git a/ts_web/elements/00group-simple/dees-simple-appdash/dees-simple-appdash.ts b/ts_web/elements/00group-simple/dees-simple-appdash/dees-simple-appdash.ts index e8ddd82..bf31c45 100644 --- a/ts_web/elements/00group-simple/dees-simple-appdash/dees-simple-appdash.ts +++ b/ts_web/elements/00group-simple/dees-simple-appdash/dees-simple-appdash.ts @@ -13,7 +13,7 @@ import { state, domtools, } from '@design.estate/dees-element'; -import '../../dees-icon/dees-icon.js'; +import '../../00group-utility/dees-icon/dees-icon.js'; import type { DeesWorkspaceTerminal } from '../../00group-workspace/dees-workspace-terminal/dees-workspace-terminal.js'; import { themeDefaultStyles } from '../../00theme.js'; @@ -33,7 +33,7 @@ export interface IView { export class DeesSimpleAppDash extends DeesElement { // STATIC public static demo = demoFunc; - public static demoGroup = 'Simple'; + public static demoGroups = ['Simple']; // INSTANCE @property() diff --git a/ts_web/elements/00group-simple/dees-simple-login/dees-simple-login.ts b/ts_web/elements/00group-simple/dees-simple-login/dees-simple-login.ts index fa8cb24..df4f52b 100644 --- a/ts_web/elements/00group-simple/dees-simple-login/dees-simple-login.ts +++ b/ts_web/elements/00group-simple/dees-simple-login/dees-simple-login.ts @@ -21,7 +21,7 @@ declare global { export class DeesSimpleLogin extends DeesElement { // STATIC public static demo = demoFunc; - public static demoGroup = 'Simple'; + public static demoGroups = ['Simple']; // INSTANCE @property() diff --git a/ts_web/elements/00group-simple/index.ts b/ts_web/elements/00group-simple/index.ts index 0f6b2a8..987425b 100644 --- a/ts_web/elements/00group-simple/index.ts +++ b/ts_web/elements/00group-simple/index.ts @@ -1,3 +1,4 @@ // Simple Components +export * from './dees-shopping-productcard/index.js'; export * from './dees-simple-appdash/index.js'; export * from './dees-simple-login/index.js'; diff --git a/ts_web/elements/dees-icon/dees-icon.demo.ts b/ts_web/elements/00group-utility/dees-icon/dees-icon.demo.ts similarity index 100% rename from ts_web/elements/dees-icon/dees-icon.demo.ts rename to ts_web/elements/00group-utility/dees-icon/dees-icon.demo.ts diff --git a/ts_web/elements/dees-icon/dees-icon.ts b/ts_web/elements/00group-utility/dees-icon/dees-icon.ts similarity index 99% rename from ts_web/elements/dees-icon/dees-icon.ts rename to ts_web/elements/00group-utility/dees-icon/dees-icon.ts index c6515ec..99f3fd8 100644 --- a/ts_web/elements/dees-icon/dees-icon.ts +++ b/ts_web/elements/00group-utility/dees-icon/dees-icon.ts @@ -9,7 +9,7 @@ import { } from '@design.estate/dees-element'; import * as domtools from '@design.estate/dees-domtools'; -import { themeDefaultStyles } from '../00theme.js'; +import { themeDefaultStyles } from '../../00theme.js'; import { icon, type IconDefinition } from '@fortawesome/fontawesome-svg-core'; import { @@ -178,6 +178,7 @@ declare global { @customElement('dees-icon') export class DeesIcon extends DeesElement { public static demo = demoFunc; + public static demoGroups = ['Utility']; /** * @deprecated Use the `icon` property instead with format "fa:iconName" or "lucide:iconName" diff --git a/ts_web/elements/dees-icon/index.ts b/ts_web/elements/00group-utility/dees-icon/index.ts similarity index 100% rename from ts_web/elements/dees-icon/index.ts rename to ts_web/elements/00group-utility/dees-icon/index.ts diff --git a/ts_web/elements/dees-searchbar/dees-searchbar.demo.ts b/ts_web/elements/00group-utility/dees-searchbar/dees-searchbar.demo.ts similarity index 100% rename from ts_web/elements/dees-searchbar/dees-searchbar.demo.ts rename to ts_web/elements/00group-utility/dees-searchbar/dees-searchbar.demo.ts diff --git a/ts_web/elements/dees-searchbar/dees-searchbar.ts b/ts_web/elements/00group-utility/dees-searchbar/dees-searchbar.ts similarity index 96% rename from ts_web/elements/dees-searchbar/dees-searchbar.ts rename to ts_web/elements/00group-utility/dees-searchbar/dees-searchbar.ts index 6a51178..6bc1c4e 100644 --- a/ts_web/elements/dees-searchbar/dees-searchbar.ts +++ b/ts_web/elements/00group-utility/dees-searchbar/dees-searchbar.ts @@ -11,9 +11,9 @@ import { query, } from '@design.estate/dees-element'; -import * as colors from '../00colors.js'; +import * as colors from '../../00colors.js'; import { demoFunc } from './dees-searchbar.demo.js'; -import { themeDefaultStyles } from '../00theme.js'; +import { themeDefaultStyles } from '../../00theme.js'; declare global { interface HTMLElementTagNameMap { @@ -25,6 +25,7 @@ declare global { export class DeesSearchbar extends DeesElement { // DEMO public static demo = demoFunc; + public static demoGroups = ['Utility']; // STATIC public static styles = [ diff --git a/ts_web/elements/dees-searchbar/index.ts b/ts_web/elements/00group-utility/dees-searchbar/index.ts similarity index 100% rename from ts_web/elements/dees-searchbar/index.ts rename to ts_web/elements/00group-utility/dees-searchbar/index.ts diff --git a/ts_web/elements/dees-theme/dees-theme.demo.ts b/ts_web/elements/00group-utility/dees-theme/dees-theme.demo.ts similarity index 100% rename from ts_web/elements/dees-theme/dees-theme.demo.ts rename to ts_web/elements/00group-utility/dees-theme/dees-theme.demo.ts diff --git a/ts_web/elements/dees-theme/dees-theme.ts b/ts_web/elements/00group-utility/dees-theme/dees-theme.ts similarity index 98% rename from ts_web/elements/dees-theme/dees-theme.ts rename to ts_web/elements/00group-utility/dees-theme/dees-theme.ts index a1b9a9c..431198d 100644 --- a/ts_web/elements/dees-theme/dees-theme.ts +++ b/ts_web/elements/00group-utility/dees-theme/dees-theme.ts @@ -18,7 +18,7 @@ import { type IThemeControlHeights, themeDefaults, themeDefaultStyles, -} from '../00theme.js'; +} from '../../00theme.js'; import { demoFunc } from './dees-theme.demo.js'; @@ -43,6 +43,7 @@ import { demoFunc } from './dees-theme.demo.js'; @customElement('dees-theme') export class DeesTheme extends DeesElement { public static demo = demoFunc; + public static demoGroups = ['Utility']; // ============================================ // Properties for theme overrides diff --git a/ts_web/elements/dees-theme/index.ts b/ts_web/elements/00group-utility/dees-theme/index.ts similarity index 100% rename from ts_web/elements/dees-theme/index.ts rename to ts_web/elements/00group-utility/dees-theme/index.ts diff --git a/ts_web/elements/dees-updater/dees-updater.demo.ts b/ts_web/elements/00group-utility/dees-updater/dees-updater.demo.ts similarity index 100% rename from ts_web/elements/dees-updater/dees-updater.demo.ts rename to ts_web/elements/00group-utility/dees-updater/dees-updater.demo.ts diff --git a/ts_web/elements/dees-updater/dees-updater.ts b/ts_web/elements/00group-utility/dees-updater/dees-updater.ts similarity index 93% rename from ts_web/elements/dees-updater/dees-updater.ts rename to ts_web/elements/00group-utility/dees-updater/dees-updater.ts index 56ffe43..76fa266 100644 --- a/ts_web/elements/dees-updater/dees-updater.ts +++ b/ts_web/elements/00group-utility/dees-updater/dees-updater.ts @@ -9,9 +9,9 @@ import { } from '@design.estate/dees-element'; import { demoFunc } from './dees-updater.demo.js'; -import '../dees-windowlayer/dees-windowlayer.js'; +import '../../00group-overlay/dees-windowlayer/dees-windowlayer.js'; import { css, cssManager } from '@design.estate/dees-element'; -import { themeDefaultStyles } from '../00theme.js'; +import { themeDefaultStyles } from '../../00theme.js'; declare global { interface HTMLElementTagNameMap { @@ -22,6 +22,7 @@ declare global { @customElement('dees-updater') export class DeesUpdater extends DeesElement { public static demo = demoFunc; + public static demoGroups = ['Utility']; public static async createAndShow() { const updater = new DeesUpdater(); diff --git a/ts_web/elements/dees-updater/index.ts b/ts_web/elements/00group-utility/dees-updater/index.ts similarity index 100% rename from ts_web/elements/dees-updater/index.ts rename to ts_web/elements/00group-utility/dees-updater/index.ts diff --git a/ts_web/elements/dees-windowcontrols/dees-windowcontrols.ts b/ts_web/elements/00group-utility/dees-windowcontrols/dees-windowcontrols.ts similarity index 95% rename from ts_web/elements/dees-windowcontrols/dees-windowcontrols.ts rename to ts_web/elements/00group-utility/dees-windowcontrols/dees-windowcontrols.ts index daf7525..9a4cffa 100644 --- a/ts_web/elements/dees-windowcontrols/dees-windowcontrols.ts +++ b/ts_web/elements/00group-utility/dees-windowcontrols/dees-windowcontrols.ts @@ -10,7 +10,7 @@ import { css, cssManager, } from '@design.estate/dees-element'; -import { themeDefaultStyles } from '../00theme.js'; +import { themeDefaultStyles } from '../../00theme.js'; declare global { interface HTMLElementTagNameMap { @@ -22,6 +22,7 @@ declare global { export class DeesWindowControls extends DeesElement { // STATIC public static demo = () => html``; + public static demoGroups = ['Utility']; // Instance @property({ diff --git a/ts_web/elements/dees-windowcontrols/index.ts b/ts_web/elements/00group-utility/dees-windowcontrols/index.ts similarity index 100% rename from ts_web/elements/dees-windowcontrols/index.ts rename to ts_web/elements/00group-utility/dees-windowcontrols/index.ts diff --git a/ts_web/elements/00group-utility/index.ts b/ts_web/elements/00group-utility/index.ts new file mode 100644 index 0000000..22b1747 --- /dev/null +++ b/ts_web/elements/00group-utility/index.ts @@ -0,0 +1,6 @@ +// Utility Components +export * from './dees-icon/index.js'; +export * from './dees-searchbar/index.js'; +export * from './dees-theme/index.js'; +export * from './dees-updater/index.js'; +export * from './dees-windowcontrols/index.js'; diff --git a/ts_web/elements/00group-workspace/dees-workspace-bottombar/dees-workspace-bottombar.ts b/ts_web/elements/00group-workspace/dees-workspace-bottombar/dees-workspace-bottombar.ts index bbeee3c..0c1466a 100644 --- a/ts_web/elements/00group-workspace/dees-workspace-bottombar/dees-workspace-bottombar.ts +++ b/ts_web/elements/00group-workspace/dees-workspace-bottombar/dees-workspace-bottombar.ts @@ -10,8 +10,8 @@ import { } from '@design.estate/dees-element'; import { themeDefaultStyles } from '../../00theme.js'; import type { IExecutionEnvironment } from '../../00group-runtime/index.js'; -import '../../dees-icon/dees-icon.js'; -import { DeesContextmenu } from '../../dees-contextmenu/dees-contextmenu.js'; +import '../../00group-utility/dees-icon/dees-icon.js'; +import { DeesContextmenu } from '../../00group-overlay/dees-contextmenu/dees-contextmenu.js'; import type { IRunProcessEventDetail, ITerminalProcessCompleteEventDetail } from '../dees-workspace-terminal/interfaces.js'; declare global { diff --git a/ts_web/elements/00group-workspace/dees-workspace-diff-editor/dees-workspace-diff-editor.ts b/ts_web/elements/00group-workspace/dees-workspace-diff-editor/dees-workspace-diff-editor.ts index 6b53518..f879965 100644 --- a/ts_web/elements/00group-workspace/dees-workspace-diff-editor/dees-workspace-diff-editor.ts +++ b/ts_web/elements/00group-workspace/dees-workspace-diff-editor/dees-workspace-diff-editor.ts @@ -31,7 +31,7 @@ export class DeesWorkspaceDiffEditor extends DeesElement { .filePath=${'/demo/example.ts'} > `; - public static demoGroup = 'Workspace'; + public static demoGroups = ['Workspace']; // INSTANCE public diffEditorDeferred = domtools.plugins.smartpromise.defer(); diff --git a/ts_web/elements/00group-workspace/dees-workspace-filetree/dees-workspace-filetree.ts b/ts_web/elements/00group-workspace/dees-workspace-filetree/dees-workspace-filetree.ts index 207c83b..ace5f42 100644 --- a/ts_web/elements/00group-workspace/dees-workspace-filetree/dees-workspace-filetree.ts +++ b/ts_web/elements/00group-workspace/dees-workspace-filetree/dees-workspace-filetree.ts @@ -11,10 +11,10 @@ import { import * as domtools from '@design.estate/dees-domtools'; import { themeDefaultStyles } from '../../00theme.js'; import type { IExecutionEnvironment, IFileEntry, IFileWatcher } from '../../00group-runtime/index.js'; -import '../../dees-icon/dees-icon.js'; -import '../../dees-contextmenu/dees-contextmenu.js'; -import { DeesContextmenu } from '../../dees-contextmenu/dees-contextmenu.js'; -import { DeesModal } from '../../dees-modal/dees-modal.js'; +import '../../00group-utility/dees-icon/dees-icon.js'; +import '../../00group-overlay/dees-contextmenu/dees-contextmenu.js'; +import { DeesContextmenu } from '../../00group-overlay/dees-contextmenu/dees-contextmenu.js'; +import { DeesModal } from '../../00group-overlay/dees-modal/dees-modal.js'; import '../../00group-input/dees-input-text/dees-input-text.js'; import { DeesInputText } from '../../00group-input/dees-input-text/dees-input-text.js'; @@ -37,7 +37,7 @@ export class DeesWorkspaceFiletree extends DeesElement {
`; - public static demoGroup = 'Workspace'; + public static demoGroups = ['Workspace']; // INSTANCE @property({ type: Object }) diff --git a/ts_web/elements/00group-workspace/dees-workspace-markdown/dees-workspace-markdown.ts b/ts_web/elements/00group-workspace/dees-workspace-markdown/dees-workspace-markdown.ts index f2091c0..925e1a7 100644 --- a/ts_web/elements/00group-workspace/dees-workspace-markdown/dees-workspace-markdown.ts +++ b/ts_web/elements/00group-workspace/dees-workspace-markdown/dees-workspace-markdown.ts @@ -23,7 +23,7 @@ declare global { @customElement('dees-workspace-markdown') export class DeesWorkspaceMarkdown extends DeesElement { public static demo = () => html``; - public static demoGroup = 'Workspace'; + public static demoGroups = ['Workspace']; public static styles = [ themeDefaultStyles, diff --git a/ts_web/elements/00group-workspace/dees-workspace-markdownoutlet/dees-workspace-markdownoutlet.demo.ts b/ts_web/elements/00group-workspace/dees-workspace-markdownoutlet/dees-workspace-markdownoutlet.demo.ts index 3d8567a..46be0e4 100644 --- a/ts_web/elements/00group-workspace/dees-workspace-markdownoutlet/dees-workspace-markdownoutlet.demo.ts +++ b/ts_web/elements/00group-workspace/dees-workspace-markdownoutlet/dees-workspace-markdownoutlet.demo.ts @@ -1,6 +1,6 @@ import { html, css } from '@design.estate/dees-element'; import '@design.estate/dees-wcctools/demotools'; -import '../../dees-panel/dees-panel.js'; +import '../../00group-layout/dees-panel/dees-panel.js'; import type { DeesWorkspaceMarkdownoutlet } from './dees-workspace-markdownoutlet.js'; export const demoFunc = () => html` diff --git a/ts_web/elements/00group-workspace/dees-workspace-markdownoutlet/dees-workspace-markdownoutlet.ts b/ts_web/elements/00group-workspace/dees-workspace-markdownoutlet/dees-workspace-markdownoutlet.ts index e40ed04..e6598b2 100644 --- a/ts_web/elements/00group-workspace/dees-workspace-markdownoutlet/dees-workspace-markdownoutlet.ts +++ b/ts_web/elements/00group-workspace/dees-workspace-markdownoutlet/dees-workspace-markdownoutlet.ts @@ -19,7 +19,7 @@ declare global { export class DeesWorkspaceMarkdownoutlet extends DeesElement { // DEMO public static demo = demoFunc; - public static demoGroup = 'Workspace'; + public static demoGroups = ['Workspace']; public static styles = [ themeDefaultStyles, diff --git a/ts_web/elements/00group-workspace/dees-workspace-monaco/dees-workspace-monaco.ts b/ts_web/elements/00group-workspace/dees-workspace-monaco/dees-workspace-monaco.ts index 66b74a3..a4b2ba7 100644 --- a/ts_web/elements/00group-workspace/dees-workspace-monaco/dees-workspace-monaco.ts +++ b/ts_web/elements/00group-workspace/dees-workspace-monaco/dees-workspace-monaco.ts @@ -23,7 +23,7 @@ declare global { export class DeesWorkspaceMonaco extends DeesElement { // DEMO public static demo = () => html``; - public static demoGroup = 'Workspace'; + public static demoGroups = ['Workspace']; // STATIC public static monacoDeferred: ReturnType; diff --git a/ts_web/elements/00group-workspace/dees-workspace-terminal-preview/dees-workspace-terminal-preview.ts b/ts_web/elements/00group-workspace/dees-workspace-terminal-preview/dees-workspace-terminal-preview.ts index 12ffe29..2a4a0bb 100644 --- a/ts_web/elements/00group-workspace/dees-workspace-terminal-preview/dees-workspace-terminal-preview.ts +++ b/ts_web/elements/00group-workspace/dees-workspace-terminal-preview/dees-workspace-terminal-preview.ts @@ -39,7 +39,7 @@ export class DeesWorkspaceTerminalPreview extends DeesElement { ]} > `; - public static demoGroup = 'Workspace'; + public static demoGroups = ['Workspace']; /** * The command being displayed (shown in header) diff --git a/ts_web/elements/00group-workspace/dees-workspace-terminal/dees-workspace-terminal.ts b/ts_web/elements/00group-workspace/dees-workspace-terminal/dees-workspace-terminal.ts index fd42045..45d5c08 100644 --- a/ts_web/elements/00group-workspace/dees-workspace-terminal/dees-workspace-terminal.ts +++ b/ts_web/elements/00group-workspace/dees-workspace-terminal/dees-workspace-terminal.ts @@ -14,9 +14,9 @@ import type { Terminal } from 'xterm'; import { themeDefaultStyles } from '../../00theme.js'; import type { IExecutionEnvironment } from '../../00group-runtime/index.js'; import { WebContainerEnvironment } from '../../00group-runtime/index.js'; -import '../../dees-icon/dees-icon.js'; -import '../../dees-actionbar/dees-actionbar.js'; -import type { DeesActionbar } from '../../dees-actionbar/dees-actionbar.js'; +import '../../00group-utility/dees-icon/dees-icon.js'; +import '../../00group-feedback/dees-actionbar/dees-actionbar.js'; +import type { DeesActionbar } from '../../00group-feedback/dees-actionbar/dees-actionbar.js'; import { TerminalTabManager } from './terminal-tab-manager.js'; import type { ITerminalTab, @@ -37,7 +37,7 @@ export class DeesWorkspaceTerminal extends DeesElement { const env = new WebContainerEnvironment(); return html``; }; - public static demoGroup = 'Workspace'; + public static demoGroups = ['Workspace']; // INSTANCE private resizeObserver: ResizeObserver; diff --git a/ts_web/elements/00group-workspace/dees-workspace/dees-workspace.ts b/ts_web/elements/00group-workspace/dees-workspace/dees-workspace.ts index 21d2bb2..01b4f20 100644 --- a/ts_web/elements/00group-workspace/dees-workspace/dees-workspace.ts +++ b/ts_web/elements/00group-workspace/dees-workspace/dees-workspace.ts @@ -21,13 +21,13 @@ import { DeesWorkspaceTerminal } from '../dees-workspace-terminal/dees-workspace import type { IRunProcessEventDetail } from '../dees-workspace-terminal/interfaces.js'; import '../dees-workspace-terminal-preview/dees-workspace-terminal-preview.js'; import '../dees-workspace-bottombar/dees-workspace-bottombar.js'; -import '../../dees-icon/dees-icon.js'; +import '../../00group-utility/dees-icon/dees-icon.js'; import { DeesWorkspaceMonaco } from '../dees-workspace-monaco/dees-workspace-monaco.js'; import { TypeScriptIntelliSenseManager } from './typescript-intellisense.js'; -import { DeesContextmenu } from '../../dees-contextmenu/dees-contextmenu.js'; +import { DeesContextmenu } from '../../00group-overlay/dees-contextmenu/dees-contextmenu.js'; import '@design.estate/dees-wcctools/demotools'; -import '../../dees-actionbar/dees-actionbar.js'; -import type { DeesActionbar } from '../../dees-actionbar/dees-actionbar.js'; +import '../../00group-feedback/dees-actionbar/dees-actionbar.js'; +import type { DeesActionbar } from '../../00group-feedback/dees-actionbar/dees-actionbar.js'; import '../dees-workspace-diff-editor/dees-workspace-diff-editor.js'; declare global { @@ -197,7 +197,7 @@ testSmartPromise(); `; }; - public static demoGroup = 'Workspace'; + public static demoGroups = ['Workspace']; // INSTANCE @property({ type: Object }) diff --git a/ts_web/elements/dees-preview/dees-preview.ts b/ts_web/elements/dees-preview/dees-preview.ts deleted file mode 100644 index e69de29..0000000 diff --git a/ts_web/elements/index.ts b/ts_web/elements/index.ts index da77ef4..e83d988 100644 --- a/ts_web/elements/index.ts +++ b/ts_web/elements/index.ts @@ -6,38 +6,17 @@ export * from './00group-appui/index.js'; export * from './00group-button/index.js'; export * from './00group-chart/index.js'; export * from './00group-dataview/index.js'; -export * from './00group-workspace/index.js'; +export * from './00group-feedback/index.js'; export * from './00group-form/index.js'; export * from './00group-input/index.js'; -export * from './00group-pdf/index.js'; +export * from './00group-layout/index.js'; +export * from './00group-media/index.js'; +export * from './00group-overlay/index.js'; export * from './00group-runtime/index.js'; export * from './00group-simple/index.js'; +export * from './00group-utility/index.js'; +export * from './00group-workspace/index.js'; // Standalone Components -export * from './dees-actionbar/index.js'; -export * from './dees-badge/index.js'; -export * from './dees-chips/index.js'; -export * from './dees-contextmenu/index.js'; -export * from './dees-dashboardgrid/index.js'; -export * from './dees-heading/index.js'; -export * from './dees-hint/index.js'; -export * from './dees-icon/index.js'; -export * from './dees-label/index.js'; -export * from './dees-mobilenavigation/index.js'; -export * from './dees-modal/index.js'; -export * from './dees-pagination/index.js'; -export * from './dees-panel/index.js'; -export * from './dees-progressbar/index.js'; -export * from './dees-searchbar/index.js'; -export * from './dees-shopping-productcard/index.js'; -export * from './dees-speechbubble/index.js'; -export * from './dees-spinner/index.js'; -export * from './dees-statsgrid/index.js'; -export * from './dees-stepper/index.js'; -export * from './dees-table/index.js'; -// dees-terminal is now part of 00group-workspace as dees-workspace-terminal -export * from './dees-toast/index.js'; -export * from './dees-updater/index.js'; -export * from './dees-windowcontrols/index.js'; -export * from './dees-windowlayer/index.js'; -export * from './dees-theme/index.js'; +export * from './dees-search/index.js'; +export * from './dees-tooltip/index.js'; diff --git a/ts_web/pages/zindex-showcase.ts b/ts_web/pages/zindex-showcase.ts index f8cc23b..126dcdd 100644 --- a/ts_web/pages/zindex-showcase.ts +++ b/ts_web/pages/zindex-showcase.ts @@ -1,11 +1,11 @@ import { html, css, cssManager } from '@design.estate/dees-element'; -import { DeesModal } from '../elements/dees-modal/dees-modal.js'; -import { DeesToast } from '../elements/dees-toast/dees-toast.js'; -import { DeesContextmenu } from '../elements/dees-contextmenu/dees-contextmenu.js'; +import { DeesModal } from '../elements/00group-overlay/dees-modal/dees-modal.js'; +import { DeesToast } from '../elements/00group-feedback/dees-toast/dees-toast.js'; +import { DeesContextmenu } from '../elements/00group-overlay/dees-contextmenu/dees-contextmenu.js'; import '../elements/00group-button/dees-button/dees-button.js'; import '../elements/00group-input/dees-input-dropdown/dees-input-dropdown.js'; import '../elements/00group-form/dees-form/dees-form.js'; -import '../elements/dees-panel/dees-panel.js'; +import '../elements/00group-layout/dees-panel/dees-panel.js'; import '../elements/00group-input/dees-input-text/dees-input-text.js'; import '../elements/00group-input/dees-input-radiogroup/dees-input-radiogroup.js'; import '../elements/00group-input/dees-input-tags/dees-input-tags.js';