Compare commits
69 Commits
Author | SHA1 | Date | |
---|---|---|---|
4eef9fc731 | |||
cd86001713 | |||
f7e4582fde | |||
4635e3fce5 | |||
af3dc5c466 | |||
12861b2230 | |||
b7f672e0f2 | |||
fcb44dfd24 | |||
f17b880b59 | |||
68785d9a72 | |||
ab4396297a | |||
ef369f2955 | |||
1e73a9527b | |||
23a4faa5d1 | |||
b0020ace16 | |||
bb78d32dbf | |||
e83ad8d504 | |||
765b01afe0 | |||
00e34e7e6c | |||
bf2ee25390 | |||
bf6d8d0bc6 | |||
3399004e75 | |||
6c2f36f020 | |||
71f4d44782 | |||
6df2eb5acc | |||
469f8e0f21 | |||
3712f6ef90 | |||
d2646cd62c | |||
f29ca0ba0b | |||
0c273a818d | |||
6e8099c6f4 | |||
07c68b82a4 | |||
afd19dc912 | |||
f02572665f | |||
f93082e9b0 | |||
08f3bad5f9 | |||
563958813e | |||
1ae1703133 | |||
d2771dfc31 | |||
dd46d3e2f4 | |||
ae641801e1 | |||
719e63c667 | |||
e26da1bb8f | |||
f5fad07038 | |||
68992301ff | |||
d529c27a68 | |||
56e8d868c9 | |||
14e1d4a9f5 | |||
efe49469aa | |||
39500f802a | |||
a64d38dbb1 | |||
e2d3ae8949 | |||
1c4fd0a2da | |||
d0e85da308 | |||
6a0b0aa741 | |||
4c620f480c | |||
b7ebcc4cef | |||
e6275bfeb3 | |||
d4585654b6 | |||
1a8562dc6f | |||
2148959c35 | |||
28a84f7c1a | |||
e935dc3983 | |||
ab30b51c9e | |||
8377d94f81 | |||
14ebeeaee8 | |||
fdc8cb44ab | |||
f72936d1a7 | |||
04170d4834 |
128
.gitlab-ci.yml
128
.gitlab-ci.yml
@ -1,128 +0,0 @@
|
||||
# gitzone ci_default
|
||||
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||
|
||||
cache:
|
||||
paths:
|
||||
- .npmci_cache/
|
||||
key: '$CI_BUILD_STAGE'
|
||||
|
||||
stages:
|
||||
- security
|
||||
- test
|
||||
- release
|
||||
- metadata
|
||||
|
||||
before_script:
|
||||
- pnpm install -g pnpm
|
||||
- pnpm install -g @shipzone/npmci
|
||||
- npmci npm prepare
|
||||
|
||||
# ====================
|
||||
# security stage
|
||||
# ====================
|
||||
# ====================
|
||||
# security stage
|
||||
# ====================
|
||||
auditProductionDependencies:
|
||||
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||
stage: security
|
||||
script:
|
||||
- npmci command npm config set registry https://registry.npmjs.org
|
||||
- npmci command pnpm audit --audit-level=high --prod
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
allow_failure: true
|
||||
|
||||
auditDevDependencies:
|
||||
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||
stage: security
|
||||
script:
|
||||
- npmci command npm config set registry https://registry.npmjs.org
|
||||
- npmci command pnpm audit --audit-level=high --dev
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
allow_failure: true
|
||||
|
||||
# ====================
|
||||
# test stage
|
||||
# ====================
|
||||
|
||||
testStable:
|
||||
stage: test
|
||||
script:
|
||||
- npmci node install stable
|
||||
- npmci npm install
|
||||
- npmci npm test
|
||||
coverage: /\d+.?\d+?\%\s*coverage/
|
||||
tags:
|
||||
- docker
|
||||
|
||||
testBuild:
|
||||
stage: test
|
||||
script:
|
||||
- npmci node install stable
|
||||
- npmci npm install
|
||||
- npmci npm build
|
||||
coverage: /\d+.?\d+?\%\s*coverage/
|
||||
tags:
|
||||
- docker
|
||||
|
||||
release:
|
||||
stage: release
|
||||
script:
|
||||
- npmci node install stable
|
||||
- npmci npm publish
|
||||
only:
|
||||
- tags
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
|
||||
# ====================
|
||||
# metadata stage
|
||||
# ====================
|
||||
codequality:
|
||||
stage: metadata
|
||||
allow_failure: true
|
||||
only:
|
||||
- tags
|
||||
script:
|
||||
- npmci command npm install -g typescript
|
||||
- npmci npm prepare
|
||||
- npmci npm install
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- priv
|
||||
|
||||
trigger:
|
||||
stage: metadata
|
||||
script:
|
||||
- npmci trigger
|
||||
only:
|
||||
- tags
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
|
||||
pages:
|
||||
stage: metadata
|
||||
script:
|
||||
- npmci node install stable
|
||||
- npmci npm install
|
||||
- npmci command npm run buildDocs
|
||||
tags:
|
||||
- lossless
|
||||
- docker
|
||||
- notpriv
|
||||
only:
|
||||
- tags
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
paths:
|
||||
- public
|
||||
allow_failure: true
|
509
changelog.md
Normal file
509
changelog.md
Normal file
@ -0,0 +1,509 @@
|
||||
# Changelog
|
||||
|
||||
## 2025-06-10 - 1.8.1 - fix(dees-statsgrid)
|
||||
Adjust stats grid styling for better alignment and improved visualizations in gauge and trend tiles.
|
||||
|
||||
- Center-align tile header elements by setting align-items to center and ensuring full width.
|
||||
- Increase tile content height to 90px and center its content.
|
||||
- Update gauge visualization: reduce circle radius from 40 to 30, adjust stroke dasharray (from 251.2 to 188.5), and decrease gauge text font size.
|
||||
- Refine trend chart layout: set trend-svg height to 40px, center trend value and adjust typography to larger, bolder text.
|
||||
- Ensure overall grid responsiveness with adjusted gap and column sizing.
|
||||
|
||||
## 2025-04-25 - 1.8.0 - feat(dees-pagination)
|
||||
Add new pagination component to the library along with its demo and integration in the main export.
|
||||
|
||||
- Introduced dees-pagination component with support for various page range scenarios.
|
||||
- Created demo file to showcase pagination with both small and large sets of pages.
|
||||
- Updated the module's index to export the new pagination component.
|
||||
|
||||
## 2025-04-22 - 1.7.0 - feat(dees-searchbar)
|
||||
Add dees-searchbar component with live search and filter demo
|
||||
|
||||
- Introduces a new dees-searchbar element with an input field, a search button, and filters
|
||||
- Wires up events for 'search-changed' and 'search-submit' to provide real‐time feedback
|
||||
- Adds a demo file to showcase usage and logging of search events
|
||||
|
||||
## 2025-04-22 - 1.6.0 - feat(documentation/dees-heading)
|
||||
Add codex documentation overview and dees-heading component demo
|
||||
|
||||
- Introduce 'codex.md' to provide a high-level overview of project layout, component patterns, and build workflow
|
||||
- Add and update dees-heading component with demo to support multiple heading levels and horizontal rule styles
|
||||
- Update component export index to include dees-heading
|
||||
|
||||
## 2025-04-18 - 1.5.6 - fix(dependencies)
|
||||
Bump dependency versions and update demo code references
|
||||
|
||||
- Upgrade @design.estate/dees-element from ^2.0.39 to ^2.0.41
|
||||
- Upgrade @tsclass/tsclass from ^4.4.0 to ^9.0.0
|
||||
- Upgrade lucide from ^0.488.0 to ^0.501.0
|
||||
- Update @types/node from ^22.10.7 to ^22.14.1
|
||||
- Update dees-icon demo: scope search to demo container and adjust hover scaling
|
||||
- Replace resolveExec with directives.resolveExec in dees-table for proper rendering
|
||||
|
||||
## 2025-04-12 - 1.5.5 - fix(catalog)
|
||||
No code or documentation changes were detected. This commit records an empty update in commit information and confirms that the current state remains stable.
|
||||
|
||||
- Verified that there are no modifications in source, documentation, or demos
|
||||
- Commit metadata and build configuration remain unchanged
|
||||
|
||||
## 2025-04-11 - 1.5.4 - fix(readme)
|
||||
Update readme with company and trademark guidelines, clarifying legal usage without exposing licensing details.
|
||||
|
||||
- Added sections detailing company information and trademark guidelines.
|
||||
- Outlined legal disclaimers for trademark usage.
|
||||
|
||||
## 2025-04-11 - 1.5.3 - fix(readme)
|
||||
Update readme.md: remove redundant usage section and refine component documentation with improved examples.
|
||||
|
||||
- Removed the standalone manual import and usage example for components.
|
||||
- Added refined examples demonstrating both basic and option-based usage (e.g. for DeesButton).
|
||||
- Improved markdown formatting and consistency across component documentation.
|
||||
|
||||
## 2025-04-11 - 1.5.3 - fix(readme)
|
||||
Update readme.md for clearer documentation: removed redundant 'Usage' section and refined component examples (e.g., DeesButton's basic and options usage) for improved clarity and consistency.
|
||||
|
||||
- Removed standalone usage example showing manual import and creation of components
|
||||
- Added refined examples demonstrating both basic and option-based usage of components
|
||||
- Improved overall readme formatting and consistency across component documentation
|
||||
|
||||
## 2025-04-11 - 1.5.2 - fix(ci)
|
||||
Remove obsolete GitLab CI configuration file
|
||||
|
||||
- Deleted .gitlab-ci.yml as the CI pipeline configuration is now managed elsewhere.
|
||||
- Cleaned up CI stages for security, testing, release, and metadata.
|
||||
|
||||
## 2025-04-11 - 1.5.1 - fix(readme)
|
||||
Update readme with comprehensive reference documentation: add a usage snippet for components like DeesButton, introduce a detailed overview table of all component categories, and enhance documentation sections for each component group.
|
||||
|
||||
- Added a code example showing how to import and use DeesButton.
|
||||
- Introduced a components overview table that categorizes Core UI, Forms, Layout, Data Display, Visualization, Dialogs & Overlays, Navigation, and Development components.
|
||||
- Expanded detailed documentation with usage examples for each component type.
|
||||
- Reorganized content to improve clarity and ease of navigation for developers.
|
||||
|
||||
## 2025-04-11 - 1.5.0 - feat(badge)
|
||||
Add dees-badge component with demo file and update packageManager field in package.json
|
||||
|
||||
- Introduce a new badge component allowing different types (default, primary, success, warning, error) with an optional rounded style
|
||||
- Provide a demo for the badge component
|
||||
- Export the badge component in the main elements index
|
||||
- Update package.json to include an explicit packageManager field
|
||||
|
||||
## 2025-01-20 - 1.4.1 - fix(dependencies)
|
||||
Update dependency versions for smartpromise, webcontainer/api, tapbundle, and @types/node
|
||||
|
||||
- Update @push.rocks/smartpromise to version ^4.2.0
|
||||
- Downgrade @webcontainer/api to version 1.2.0
|
||||
- Update @push.rocks/tapbundle to version ^5.5.6
|
||||
- Update @types/node to version ^22.10.7
|
||||
|
||||
## 2025-01-20 - 1.4.0 - feat(dees-terminal)
|
||||
Enhanced the dees-terminal component to support environment variable settings and improved setup command execution.
|
||||
|
||||
- Added environment property to pass custom environment variables.
|
||||
- Introduced webcontainerDeferred to handle the promise for web container creation.
|
||||
- Enhanced demo to illustrate environment variable usage.
|
||||
- Improved async interaction with the terminal for setting environment variables and executing setup commands.
|
||||
|
||||
## 2025-01-15 - 1.3.4 - fix(chart)
|
||||
Fix chart rendering and appearance issues in the DeesChartArea component.
|
||||
|
||||
- Resolved issues with chart dimensions calculation based on padding.
|
||||
- Adjusted grid and axis lines appearance for better visibility.
|
||||
- Updated tooltip and grid line styling for better accessibility.
|
||||
- Improved series data representation as time-series for more accurate display.
|
||||
|
||||
## 2024-12-17 - 1.3.3 - fix(dees-input-multitoggle)
|
||||
Add missing TypeScript declaration for dees-input-multitoggle
|
||||
|
||||
- Added a missing declaration to the HTMLElementTagNameMap for 'dees-input-multitoggle' element.
|
||||
|
||||
## 2024-12-09 - 1.3.2 - fix(metadata)
|
||||
Updated package metadata and readme for better project description and structure.
|
||||
|
||||
- Updated package.json and npmextra.json with a detailed project description and list of keywords.
|
||||
- Enhanced readme.md with installation instructions, component usage examples, and detailed component descriptions for clarity.
|
||||
|
||||
## 2024-11-07 - 1.3.1 - fix(DeesSimpleAppDash)
|
||||
Fix: add border to controlbar in DeesSimpleAppDash
|
||||
|
||||
- Fixed the missing border at the top of the controlbar in DeesSimpleAppDash.
|
||||
|
||||
## 2024-11-07 - 1.3.0 - feat(dees-simple-appdash)
|
||||
Enhance responsive styling and terminal setup command
|
||||
|
||||
- Added a new property `terminalSetupCommand` for configuring terminal setup commands.
|
||||
- Improved responsive styling and positioning for components to achieve a fluid layout.
|
||||
- Fixed layout shifts by switching positions to `absolute` for `appbar` and `appcontent`.
|
||||
|
||||
## 2024-10-07 - 1.2.0 - feat(index.ts)
|
||||
Add export for colors module in index.ts
|
||||
|
||||
- The index.ts file now exports the colors module, making color utilities available for external use.
|
||||
|
||||
## 2024-10-06 - 1.1.13 - fix(dees-button)
|
||||
Fix styling issue in button component.
|
||||
|
||||
- Moved the .button.disabled styling block to its correct position after the .button.highlighted block.
|
||||
|
||||
## 2024-10-06 - 1.1.12 - fix(dees-button)
|
||||
Fix reflect attribute for disabled property on dees-button component
|
||||
|
||||
- Added reflect: true to the 'disabled' property ensuring changes reflect in the DOM attribute.
|
||||
|
||||
## 2024-10-05 - 1.1.11 - fix(DeesStepper)
|
||||
Adjusted CSS properties in DeesStepper component
|
||||
|
||||
- Increased border-radius from 8px to 16px for step container elements
|
||||
- Adjusted font-size and font-weight for the title in the step container to improve readability
|
||||
|
||||
## 2024-10-04 - 1.1.10 - fix(dependencies)
|
||||
Reverted @webcontainer/api version
|
||||
|
||||
- Changed @webcontainer/api version from ^1.3.0 to 1.2.0 in package.json
|
||||
|
||||
## 2024-10-04 - 1.1.9 - fix(dependencies)
|
||||
Update various dependencies for compatibility and stability.
|
||||
|
||||
- Update @design.estate/dees-domtools to version ^2.0.61
|
||||
- Update @design.estate/dees-element to version ^2.0.39
|
||||
- Update @webcontainer/api to version ^1.3.0
|
||||
- Update apexcharts to version ^3.54.0
|
||||
- Update monaco-editor to version ^0.52.0
|
||||
- Update pdfjs-dist to version ^4.6.82
|
||||
- Update @push.rocks/tapbundle to version ^5.3.0
|
||||
- Update @types/node to version ^22.7.4
|
||||
|
||||
## 2024-09-02 - 1.1.8 - fix(dees-simple-appdash)
|
||||
Corrected viewTab active background color
|
||||
|
||||
- Corrected the background color of the viewTab in active state for better visual consistency.
|
||||
|
||||
## 2024-09-02 - 1.1.7 - fix(dependencies)
|
||||
Update dependencies to their latest versions
|
||||
|
||||
- Update dependency versions in package.json:
|
||||
- - @design.estate/dees-element from ^2.0.34 to ^2.0.36
|
||||
- - @fortawesome/fontawesome-svg-core from ^6.5.2 to ^6.6.0
|
||||
- - @fortawesome/free-brands-svg-icons from ^6.5.2 to ^6.6.0
|
||||
- - @fortawesome/free-regular-svg-icons from ^6.5.2 to ^6.6.0
|
||||
- - @fortawesome/free-solid-svg-icons from ^6.5.2 to ^6.6.0
|
||||
- - @tsclass/tsclass from ^4.0.63 to ^4.1.2
|
||||
- - apexcharts from ^3.49.2 to ^3.53.0
|
||||
- - highlight.js from 11.9.0 to 11.10.0
|
||||
- - monaco-editor from ^0.50.0 to ^0.51.0
|
||||
- - pdfjs-dist from ^4.3.136 to ^4.5.136
|
||||
- - @git.zone/tsbuild from ^2.1.82 to ^2.1.84
|
||||
- - @push.rocks/tapbundle from ^5.0.23 to ^5.0.24
|
||||
- - @types/node from ^20.14.9 to ^22.5.2
|
||||
|
||||
## 2024-07-01 - 1.1.6 - fix(dees-dataview-codebox)
|
||||
Corrected the font-family order for better font rendering.
|
||||
|
||||
- Corrected the font-family order in dees-dataview-codebox.ts to ensure 'Intel One Mono' is prioritized over 'Geist Mono'.
|
||||
|
||||
## 2024-07-01 - 1.1.5 - fix(dees-dataview-codebox)
|
||||
Adjusted line number font weight in codebox
|
||||
|
||||
- Changed the line number font weight from 400 to 200 in the codebox for better visual alignment.
|
||||
|
||||
## 2024-07-01 - 1.1.4 - fix(UI)
|
||||
Fixed font-family order for code and value elements
|
||||
|
||||
- Updated font-family order in dees-dataview-codebox.ts
|
||||
- Updated font-family order in dees-dataview-statusobject.ts
|
||||
|
||||
## 2024-07-01 - 1.1.3 - fix(dees-dataview-codebox)
|
||||
Adjusted codebox font weight and font family.
|
||||
|
||||
- Changed font weight from 200 to 400 for better readability.
|
||||
- Updated font-family to include 'Geist Mono' for uniform appearance.
|
||||
|
||||
## 2024-06-30 - 1.1.2 - fix(elements)
|
||||
Fix various UI components and improve styles
|
||||
|
||||
- Updated styles for multiple components for better appearance in dark mode.
|
||||
- Added missing event handling in `dees-input-fileupload` component.
|
||||
- Implemented tooltip support in `dees-label` component.
|
||||
- Fixed alignment issues in `dees-appui-*` components.
|
||||
- Resolved various accessibility issues in form elements.
|
||||
|
||||
## 2024-06-30 - 1.1.1 - fix(build)
|
||||
Fix build script by updating source folders.
|
||||
|
||||
- Updated build script to correctly reference 'tsfolders' folder.
|
||||
|
||||
## 2024-06-30 - 1.1.0 - feat(project dependencies)
|
||||
Updated various dependencies and internal fonts
|
||||
|
||||
- Updated dependencies in package.json with the latest versions.
|
||||
- Updated font-family references from 'Roboto' and 'Inter' to 'Geist Sans' across multiple components.
|
||||
|
||||
## 2024-04-20 - 1.0.289 - Documentation Update
|
||||
Updated the project documentation.
|
||||
|
||||
## 2024-02-05 to 2024-02-13 - 1.0.277 to 1.0.288 - Core Fixes
|
||||
Series of core updates and patches.
|
||||
|
||||
## 2024-01-22 to 2024-02-05 - 1.0.257 to 1.0.276 - Core Fixes
|
||||
More core updates and patches.
|
||||
|
||||
## 2024-01-21 - 1.0.256 to 1.0.257 - Core Fixes
|
||||
Minor bugfixes for core functionalities.
|
||||
|
||||
## 2024-01-18 - 1.0.246 - Core Fixes
|
||||
Bugfixes for core functionalities.
|
||||
|
||||
## 2024-01-15 - 1.0.242 to 1.0.245 - Core Fixes
|
||||
Various core bugfixes.
|
||||
|
||||
## 2024-01-11 - 1.0.241 to 1.0.242 - Core Fixes
|
||||
Bugfixes for core functionalities.
|
||||
|
||||
## 2024-01-10 - 1.0.240 to 1.0.241 - Core Fixes
|
||||
Minor core fixes and improvements.
|
||||
|
||||
## 2024-01-09 - 1.0.239 to 1.0.240 - Core Fixes
|
||||
Core updates and patches.
|
||||
|
||||
## 2023-12-26 - 1.0.238 to 1.0.239 - Core Fixes
|
||||
Updates to core functionalities.
|
||||
|
||||
## 2023-12-20 - 1.0.236 to 1.0.238 - Core Fixes
|
||||
Bugfixes and updates for core functionalities.
|
||||
|
||||
## 2023-12-08 - 1.0.233 to 1.0.236 - Core Fixes
|
||||
Multiple updates to core functionalities.
|
||||
|
||||
## 2023-11-29 - 1.0.231 to 1.0.232 - Core Fixes
|
||||
Minor core patches.
|
||||
|
||||
## 2023-10-31 - 1.0.229 to 1.0.230 - Core Fixes
|
||||
Various updates and fixes for core.
|
||||
|
||||
## 2023-10-24 - 1.0.228 to 1.0.229 - Core Fixes
|
||||
More core updates and patches.
|
||||
|
||||
## 2023-10-23 - 1.0.226 to 1.0.228 - Core Fixes
|
||||
Series of updates and fixes for core functionalities.
|
||||
|
||||
## 2023-10-20 - 1.0.223 to 1.0.225 - Core Fixes
|
||||
Minor updates and fixes for core.
|
||||
|
||||
## 2023-10-18 - 1.0.222 to 1.0.223 - Core Fixes
|
||||
Core patches and bugfixes.
|
||||
|
||||
## 2023-10-17 - 1.0.221 to 1.0.222 - Core Fixes
|
||||
Further updates to core functionalities.
|
||||
|
||||
## 2023-10-12 - 1.0.220 to 1.0.221 - Core Fixes
|
||||
Minor core updates.
|
||||
|
||||
## 2023-10-11 - 1.0.219 to 1.0.220 - Core Fixes
|
||||
Bugfixes and updates for core.
|
||||
|
||||
## 2023-10-07 - 1.0.217 to 1.0.219 - Core Fixes
|
||||
Series of core updates and patches.
|
||||
|
||||
## 2023-10-05 - 1.0.216 to 1.0.217 - Core Fixes
|
||||
Minor updates for core functionalities.
|
||||
|
||||
## 2023-09-22 - 1.0.212 to 1.0.215 - Core Fixes
|
||||
Various updates and fixes for core.
|
||||
|
||||
## 2023-09-20 - 1.0.210 to 1.0.211 - Core Fixes
|
||||
Series of core patches.
|
||||
|
||||
## 2023-09-18 - 1.0.209 to 1.0.210 - Core Fixes
|
||||
Bugfixes and improvements to core.
|
||||
|
||||
## 2023-09-17 - 1.0.207 to 1.0.209 - Core Fixes
|
||||
Minor updates and fixes.
|
||||
|
||||
## 2023-09-15 - 1.0.203 to 1.0.206 - Core Fixes
|
||||
Series of core improvements and fixes.
|
||||
|
||||
## 2023-09-14 - 1.0.199 to 1.0.202 - Core Fixes
|
||||
Patches for core functionalities.
|
||||
|
||||
## 2023-09-13 - 1.0.194 to 1.0.198 - Core Fixes
|
||||
Various bugfixes and updates for core.
|
||||
|
||||
## 2023-09-12 - 1.0.190 to 1.0.193 - Core Fixes
|
||||
Minor core patches.
|
||||
|
||||
## 2023-09-09 - 1.0.188 to 1.0.189 - Core Fixes
|
||||
Updates and bugfixes for core.
|
||||
|
||||
## 2023-09-07 - 1.0.186 to 1.0.187 - Core Fixes
|
||||
Core patches and improvements.
|
||||
|
||||
## 2023-09-04 - 1.0.184 to 1.0.185 - Core Fixes
|
||||
Series of updates and bugfixes for core.
|
||||
|
||||
## 2023-09-01 - 1.0.180 to 1.0.183 - Core Fixes
|
||||
Various core updates and fixes.
|
||||
|
||||
## 2023-08-28 - 1.0.177 to 1.0.179 - Core Fixes
|
||||
Minor bugfixes and updates.
|
||||
|
||||
## 2023-08-26 - 1.0.176 to 1.0.177 - Core Fixes
|
||||
Bugfixes for core functionalities.
|
||||
|
||||
## 2023-08-20 - 1.0.173 to 1.0.175 - Core Fixes
|
||||
Series of updates and fixes for core.
|
||||
|
||||
## 2023-08-08 - 1.0.172 to 1.0.173 - Core Fixes
|
||||
Minor core updates.
|
||||
|
||||
## 2023-08-07 - 1.0.171 to 1.0.172 - Core Fixes
|
||||
Various updates to core.
|
||||
|
||||
## 2023-04-12 - 1.0.169 to 1.0.170 - Core Fixes
|
||||
Bugfixes for core functionalities.
|
||||
|
||||
## 2023-04-10 - 1.0.163 to 1.0.168 - Core Fixes
|
||||
Series of core updates and patches.
|
||||
|
||||
## 2023-04-07 - 1.0.160 to 1.0.162 - Core Fixes
|
||||
Various updates for core functionalities.
|
||||
|
||||
## 2023-04-06 - 1.0.155 to 1.0.159 - Core Fixes
|
||||
Bugfixes and improvements to core.
|
||||
|
||||
## 2023-03-27 - 1.0.150 to 1.0.154 - Core Fixes
|
||||
Minor updates and patches for core functionalities.
|
||||
|
||||
## 2023-03-09 - 1.0.149 to 1.0.150 - Core Fixes
|
||||
Bugfixes for core functionalities.
|
||||
|
||||
## 2023-01-17 - 1.0.146 to 1.0.148 - Core Fixes
|
||||
Updates and fixes for core.
|
||||
|
||||
## 2023-01-16 - 1.0.144 to 1.0.145 - Core Fixes
|
||||
Series of updates and bugfixes for core.
|
||||
|
||||
## 2023-01-13 - 1.0.134 to 1.0.143 - Core Fixes
|
||||
Various core patches and improvements.
|
||||
|
||||
## 2023-01-12 - 1.0.132 to 1.0.133 - Core Fixes
|
||||
Minor fixes for core functionalities.
|
||||
|
||||
## 2023-01-11 - 1.0.126 to 1.0.131 - Core Fixes
|
||||
Series of updates and fixes for core.
|
||||
|
||||
## 2023-01-09 - 1.0.122 to 1.0.123 - Core Fixes
|
||||
Minor core patches and updates.
|
||||
|
||||
## 2023-01-07 - 1.0.113 to 1.0.121 - Core Fixes
|
||||
Updates and bugfixes for core functionalities.
|
||||
|
||||
## 2023-01-03 - 1.0.107 to 1.0.110 - Core Fixes
|
||||
Series of core updates and fixes.
|
||||
|
||||
## 2022-12-12 - 1.0.105 to 1.0.106 - Core Fixes
|
||||
Various core patches.
|
||||
|
||||
## 2022-12-07 - 1.0.104 to 1.0.105 - Core Fixes
|
||||
Bugfixes and improvements to core functionalities.
|
||||
|
||||
## 2022-12-06 - 1.0.103 to 1.0.104 - Core Fixes
|
||||
Series of updates and patches for core.
|
||||
|
||||
## 2022-08-18 - 1.0.98 to 1.0.102 - Core Fixes
|
||||
Updates and bugfixes for core functionalities.
|
||||
|
||||
## 2022-07-14 - 1.0.93 to 1.0.94 - Core Fixes
|
||||
Minor core updates.
|
||||
|
||||
## 2022-06-26 - 1.0.92 to 1.0.93 - Core Fixes
|
||||
Bugfixes for core functionalities.
|
||||
|
||||
## 2022-06-10 - 1.0.91 to 1.0.92 - Core Fixes
|
||||
Updates and patches for core.
|
||||
|
||||
## 2022-05-30 - 1.0.90 to 1.0.91 - Core Fixes
|
||||
Minor updates and bugfixes.
|
||||
|
||||
## 2022-05-26 - 1.0.87 to 1.0.89 - Core Fixes
|
||||
Series of core updates and patches.
|
||||
|
||||
## 2022-05-24 to 2022-05-20 - 1.0.83 to 1.0.86 - Core Fixes
|
||||
Various updates and bugfixes for core functionalities.
|
||||
|
||||
## 2022-05-03 - 1.0.79 to 1.0.80 - Core Fixes
|
||||
Updates and patches for core functionalities.
|
||||
|
||||
## 2022-03-18 - 1.0.74 to 1.0.77 - Core Fixes
|
||||
Bugfixes and updates for core functionalities.
|
||||
|
||||
## 2022-01-24 - 1.0.73 to 1.0.74 - Core Fixes
|
||||
Minor core patches.
|
||||
|
||||
## 2021-12-10 - 1.0.71 to 1.0.72 - Core Fixes
|
||||
Series of updates and fixes for core functionalities.
|
||||
|
||||
## 2021-11-27 - 1.0.70 to 1.0.71 - Core Fixes
|
||||
Bugfixes and improvements to core.
|
||||
|
||||
## 2021-10-08 - 1.0.68 to 1.0.69 - Core Fixes
|
||||
Various core updates and patches.
|
||||
|
||||
## 2021-10-07 - 1.0.67 to 1.0.68 - Core Fixes
|
||||
Minor updates and improvements for core.
|
||||
|
||||
## 2021-09-15 - 1.0.64 to 1.0.66 - Core Fixes
|
||||
Bugfixes and improvements to core functionalities.
|
||||
|
||||
## 2021-09-14 - 1.0.61 to 1.0.62 - Core Fixes
|
||||
Minor patches and updates for core.
|
||||
|
||||
## 2021-09-10 - 1.0.57 to 1.0.60 - Core Fixes
|
||||
Series of updates and fixes for core functionalities.
|
||||
|
||||
## 2021-09-09 - 1.0.54 to 1.0.56 - Core Fixes
|
||||
Various core updates and patches.
|
||||
|
||||
## 2021-09-01 - 1.0.51 to 1.0.53 - Core Fixes
|
||||
Minor updates for core functionalities.
|
||||
|
||||
## 2021-08-29 - 1.0.49 to 1.0.50 - Core Fixes
|
||||
Bugfixes and patches for core.
|
||||
|
||||
## 2021-08-27 - 1.0.44 to 1.0.48 - Core Fixes
|
||||
Series of updates and improvements for core functionalities.
|
||||
|
||||
## 2021-08-26 - 1.0.42 to 1.0.43 - Core Fixes
|
||||
Minor updates and bugfixes for core.
|
||||
|
||||
## 2021-08-25 - 1.0.38 to 1.0.41 - Core Fixes
|
||||
Extracted series of core updates and patches.
|
||||
|
||||
## 2021-08-24 - 1.0.37 - Core Fix
|
||||
Bugfixes for core functionalities.
|
||||
|
||||
## 2021-08-20 - 1.0.34 to 1.0.36 - Core Fixes
|
||||
Core functionalities updates and patches.
|
||||
|
||||
## 2021-05-05 - 1.0.32 to 1.0.33 - Core Fixes
|
||||
Series of core bugfixes.
|
||||
|
||||
## 2021-03-06 - 1.0.29 to 1.0.31 - Core Fixes
|
||||
Updates and improvements for core functionalities.
|
||||
|
||||
## 2021-02-13 - 1.0.27 to 1.0.28 - Core Fixes
|
||||
Bugfixes and patches for core functionalities.
|
||||
|
||||
## 2020-12-10 - 1.0.25 to 1.0.26 - Core Fixes
|
||||
Various core updates and improvements.
|
||||
|
||||
## 2020-12-02 - 1.0.23 to 1.0.24 - Core Fixes
|
||||
Minor updates for core functionalities.
|
||||
|
||||
## 2020-12-01 - 1.0.21 to 1.0.22 - Core Fixes
|
||||
Bugfixes and patches for core.
|
||||
|
||||
## 2020-09-13 - 1.0.19 to 1.0.20 - Core Fixes
|
||||
Updates and bugfixes for core functionalities.
|
||||
|
||||
## 2020-05-11 - 1.0.17 to 1.0.18 - Core Fixes
|
||||
Core functionalities updates.
|
43
codex.md
Normal file
43
codex.md
Normal file
@ -0,0 +1,43 @@
|
||||
# Codex: Project Overview and Codebase Structure
|
||||
|
||||
## Project Overview
|
||||
- Package: `@design.estate/dees-catalog`
|
||||
- Focus: Web Components library providing UI elements and layouts for modern web apps.
|
||||
|
||||
## Directory Layout
|
||||
- ts_web/: TypeScript source files
|
||||
- elements/: Individual Web Component definitions
|
||||
- pages/: Page-level templates for composite layouts
|
||||
- html/: Demo/app entry point loading the bundled scripts
|
||||
- dist_bundle/: Bundled browser JS and source maps
|
||||
- dist_ts_web/: ES module outputs for TypeScript/web consumers
|
||||
- dist_watch/: Watch-mode development bundle with live reload
|
||||
- test/: Browser-based tests using `@push.rocks/tapbundle`
|
||||
|
||||
## Component Patterns
|
||||
- Each component in ts_web/elements/:
|
||||
- Decorated with `@customElement('tag-name')`
|
||||
- Extends `DeesElement` from `@design.estate/dees-element`
|
||||
- Uses `@property` for reactive, reflected attributes
|
||||
- Defines `static styles = [cssManager.defaultStyles, css`...`]`
|
||||
- Implements `render()` returning a Lit `html` template with slots or markup
|
||||
- Exposes a demo via `public static demo` linking to `.demo.ts` files
|
||||
|
||||
## Build & Development Workflow
|
||||
- Install dependencies: `npm install` or `pnpm install`
|
||||
- Build production bundle: `npm run build`
|
||||
- Start dev watch mode: `npm run watch`
|
||||
- Run tests: `npm test` (launches browser fixtures)
|
||||
|
||||
## Theming & Utilities
|
||||
- Default global styles via `cssManager.defaultStyles`
|
||||
- Theme-aware values with `cssManager.bdTheme(light, dark)`
|
||||
- DOM utilities set up in `html/index.ts` using `@design.estate/dees-domtools`
|
||||
|
||||
## Documentation
|
||||
- `readme.md` provides an overview of all components and basic usage
|
||||
- Live examples in `.demo.ts` files
|
||||
accessible via component `demo` static property
|
||||
|
||||
## Updates to this file
|
||||
If you have pattern insisights or general changes to the codebase, please update this file.
|
@ -2,17 +2,46 @@
|
||||
"gitzone": {
|
||||
"projectType": "wcc",
|
||||
"module": {
|
||||
"githost": "gitlab.com",
|
||||
"githost": "code.foss.global",
|
||||
"gitscope": "design.estate",
|
||||
"gitrepo": "dees-catalog",
|
||||
"description": "a webcomponents catalog for handling daily stuff on the web",
|
||||
"description": "A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.",
|
||||
"npmPackagename": "@design.estate/dees-catalog",
|
||||
"license": "MIT",
|
||||
"projectDomain": "design.estate"
|
||||
"projectDomain": "design.estate",
|
||||
"keywords": [
|
||||
"Web Components",
|
||||
"User Interface",
|
||||
"UI Library",
|
||||
"Component Library",
|
||||
"JavaScript",
|
||||
"TypeScript",
|
||||
"Dynamic Components",
|
||||
"Modular Architecture",
|
||||
"Reusable Components",
|
||||
"Web Development",
|
||||
"Application UI",
|
||||
"Custom Elements",
|
||||
"Shadow DOM",
|
||||
"UI Elements",
|
||||
"Dashboard Interfaces",
|
||||
"Form Handling",
|
||||
"Data Display",
|
||||
"Visualization",
|
||||
"Charting",
|
||||
"Interactive Components",
|
||||
"Responsive Design",
|
||||
"Web Applications",
|
||||
"Modern Web",
|
||||
"Frontend Development"
|
||||
]
|
||||
}
|
||||
},
|
||||
"npmci": {
|
||||
"npmGlobalTools": [],
|
||||
"npmAccessLevel": "public"
|
||||
},
|
||||
"tsdoc": {
|
||||
"legal": "\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. \n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
|
||||
}
|
||||
}
|
78
package.json
78
package.json
@ -1,48 +1,49 @@
|
||||
{
|
||||
"name": "@design.estate/dees-catalog",
|
||||
"version": "1.0.289",
|
||||
"version": "1.8.1",
|
||||
"private": false,
|
||||
"description": "website for lossless.com",
|
||||
"description": "A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.",
|
||||
"main": "dist_ts_web/index.js",
|
||||
"typings": "dist_ts_web/index.d.ts",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"test": "tstest test/ --web",
|
||||
"build": "tsbuild element --allowimplicitany && tsbundle element --production",
|
||||
"build": "tsbuild tsfolders --allowimplicitany && tsbundle element --production",
|
||||
"watch": "tswatch element",
|
||||
"buildDocs": "tsdoc"
|
||||
},
|
||||
"author": "Lossless GmbH",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@design.estate/dees-domtools": "^2.0.57",
|
||||
"@design.estate/dees-element": "^2.0.34",
|
||||
"@design.estate/dees-wcctools": "^1.0.87",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.5.1",
|
||||
"@fortawesome/free-brands-svg-icons": "^6.5.1",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.5.1",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.5.1",
|
||||
"@design.estate/dees-domtools": "^2.1.1",
|
||||
"@design.estate/dees-element": "^2.0.41",
|
||||
"@design.estate/dees-wcctools": "^1.0.90",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.7.2",
|
||||
"@fortawesome/free-brands-svg-icons": "^6.7.2",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.7.2",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.7.2",
|
||||
"@push.rocks/smarti18n": "^1.0.4",
|
||||
"@push.rocks/smartpromise": "^4.0.3",
|
||||
"@push.rocks/smartstring": "^4.0.13",
|
||||
"@tsclass/tsclass": "^4.0.51",
|
||||
"@webcontainer/api": "^1.1.9",
|
||||
"apexcharts": "^3.45.2",
|
||||
"highlight.js": "11.9.0",
|
||||
"ibantools": "^4.3.9",
|
||||
"monaco-editor": "^0.46.0",
|
||||
"pdfjs-dist": "^4.0.379",
|
||||
"@push.rocks/smartpromise": "^4.2.0",
|
||||
"@push.rocks/smartstring": "^4.0.15",
|
||||
"@tsclass/tsclass": "^9.0.0",
|
||||
"@webcontainer/api": "1.2.0",
|
||||
"apexcharts": "^4.3.0",
|
||||
"highlight.js": "11.11.1",
|
||||
"ibantools": "^4.5.1",
|
||||
"lucide": "^0.501.0",
|
||||
"monaco-editor": "^0.52.2",
|
||||
"pdfjs-dist": "^4.10.38",
|
||||
"xterm": "^5.3.0",
|
||||
"xterm-addon-fit": "^0.8.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@git.zone/tsbuild": "^2.1.72",
|
||||
"@git.zone/tsbuild": "^2.1.84",
|
||||
"@git.zone/tsbundle": "^2.0.15",
|
||||
"@git.zone/tstest": "^1.0.86",
|
||||
"@git.zone/tswatch": "^2.0.23",
|
||||
"@git.zone/tstest": "^1.0.90",
|
||||
"@git.zone/tswatch": "^2.0.37",
|
||||
"@push.rocks/projectinfo": "^5.0.2",
|
||||
"@push.rocks/tapbundle": "^5.0.15",
|
||||
"@types/node": "^20.11.17"
|
||||
"@push.rocks/tapbundle": "^5.5.6",
|
||||
"@types/node": "^22.14.1"
|
||||
},
|
||||
"files": [
|
||||
"ts/**/*",
|
||||
@ -58,5 +59,32 @@
|
||||
],
|
||||
"browserslist": [
|
||||
"last 1 chrome versions"
|
||||
]
|
||||
],
|
||||
"keywords": [
|
||||
"Web Components",
|
||||
"User Interface",
|
||||
"UI Library",
|
||||
"Component Library",
|
||||
"JavaScript",
|
||||
"TypeScript",
|
||||
"Dynamic Components",
|
||||
"Modular Architecture",
|
||||
"Reusable Components",
|
||||
"Web Development",
|
||||
"Application UI",
|
||||
"Custom Elements",
|
||||
"Shadow DOM",
|
||||
"UI Elements",
|
||||
"Dashboard Interfaces",
|
||||
"Form Handling",
|
||||
"Data Display",
|
||||
"Visualization",
|
||||
"Charting",
|
||||
"Interactive Components",
|
||||
"Responsive Design",
|
||||
"Web Applications",
|
||||
"Modern Web",
|
||||
"Frontend Development"
|
||||
],
|
||||
"packageManager": "pnpm@10.7.0+sha512.6b865ad4b62a1d9842b61d674a393903b871d9244954f652b8842c2b553c72176b278f64c463e52d40fff8aba385c235c8c9ecf5cc7de4fd78b8bb6d49633ab6"
|
||||
}
|
||||
|
13280
pnpm-lock.yaml
generated
13280
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
4
readme.hints.md
Normal file
4
readme.hints.md
Normal file
@ -0,0 +1,4 @@
|
||||
!!! Please pay attention to the following points when writing the readme: !!!
|
||||
* Give a short rundown of components and a few points abputspecific features on each.
|
||||
* Try to list all components in a summary.
|
||||
* Then list all components with a short description.
|
@ -1,8 +1,8 @@
|
||||
/**
|
||||
* autocreated commitinfo by @pushrocks/commitinfo
|
||||
* autocreated commitinfo by @push.rocks/commitinfo
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@design.estate/dees-catalog',
|
||||
version: '1.0.289',
|
||||
description: 'website for lossless.com'
|
||||
version: '1.8.1',
|
||||
description: 'A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.'
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ export class DeesAppuiActivitylog extends DeesElement {
|
||||
padding-top: 8px;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
font-family: 'Roboto', 'Inter', sans-serif;
|
||||
font-family: 'Geist Sans', sans-serif;
|
||||
}
|
||||
|
||||
.activityContainer {
|
||||
|
@ -71,7 +71,7 @@ export class DeesAppuiMainselector extends DeesElement {
|
||||
padding-left: 16px;
|
||||
padding-top: 8px;
|
||||
line-height: 24px;
|
||||
font-family: 'Roboto', 'Inter', sans-serif;
|
||||
font-family: 'Geist Sans', sans-serif;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
}
|
||||
@ -82,7 +82,7 @@ export class DeesAppuiMainselector extends DeesElement {
|
||||
padding-top: 8px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
font-family: 'Roboto', 'Inter', sans-serif;
|
||||
font-family: 'Geist Sans', sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
|
12
ts_web/elements/dees-badge.demo.ts
Normal file
12
ts_web/elements/dees-badge.demo.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { html } from '@design.estate/dees-element';
|
||||
|
||||
export const demoFunc = () => html`
|
||||
<div style="display: flex; gap: 8px; align-items: center;">
|
||||
<dees-badge .text=${'Default'}></dees-badge>
|
||||
<dees-badge .type=${'primary'} .text=${'Primary'}></dees-badge>
|
||||
<dees-badge .type=${'success'} .text=${'Success'}></dees-badge>
|
||||
<dees-badge .type=${'warning'} .text=${'Warning'}></dees-badge>
|
||||
<dees-badge .type=${'error'} .text=${'Error'}></dees-badge>
|
||||
<dees-badge .type=${'primary'} .rounded=${true} .text=${'Rounded'}></dees-badge>
|
||||
</div>
|
||||
`;
|
96
ts_web/elements/dees-badge.ts
Normal file
96
ts_web/elements/dees-badge.ts
Normal file
@ -0,0 +1,96 @@
|
||||
import {
|
||||
DeesElement,
|
||||
css,
|
||||
cssManager,
|
||||
customElement,
|
||||
html,
|
||||
property,
|
||||
type CSSResult,
|
||||
type TemplateResult,
|
||||
} from '@design.estate/dees-element';
|
||||
|
||||
import * as domtools from '@design.estate/dees-domtools';
|
||||
import { demoFunc } from './dees-badge.demo.js';
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'dees-badge': DeesBadge;
|
||||
}
|
||||
}
|
||||
|
||||
@customElement('dees-badge')
|
||||
export class DeesBadge extends DeesElement {
|
||||
public static demo = demoFunc;
|
||||
|
||||
@property({ type: String })
|
||||
public type: 'default' | 'primary' | 'success' | 'warning' | 'error' = 'default';
|
||||
|
||||
@property({ type: String })
|
||||
public text: string = '';
|
||||
|
||||
@property({ type: Boolean })
|
||||
public rounded: boolean = false;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
domtools.elementBasic.setup();
|
||||
}
|
||||
|
||||
public static styles = [
|
||||
cssManager.defaultStyles,
|
||||
css`
|
||||
:host {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 2px 8px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
line-height: 1.5;
|
||||
border-radius: 4px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.badge.rounded {
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.badge.default {
|
||||
background: ${cssManager.bdTheme('#f5f5f5', '#333')};
|
||||
color: ${cssManager.bdTheme('#666', '#ccc')};
|
||||
}
|
||||
|
||||
.badge.primary {
|
||||
background: #0050b9;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.badge.success {
|
||||
background: #2e7d32;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.badge.warning {
|
||||
background: #ed6c02;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.badge.error {
|
||||
background: #e4002b;
|
||||
color: #ffffff;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
public render(): TemplateResult {
|
||||
return html`
|
||||
<div class="badge ${this.type} ${this.rounded ? 'rounded' : ''}">
|
||||
${this.text}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
@ -35,7 +35,8 @@ export class DeesButton extends DeesElement {
|
||||
public eventDetailData: string;
|
||||
|
||||
@property({
|
||||
type: Boolean
|
||||
type: Boolean,
|
||||
reflect: true,
|
||||
})
|
||||
public disabled = false;
|
||||
|
||||
@ -64,7 +65,7 @@ export class DeesButton extends DeesElement {
|
||||
:host {
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
font-family: 'Roboto', 'monospace';
|
||||
font-family: 'Geist Sans', 'monospace';
|
||||
}
|
||||
:host([hidden]) {
|
||||
display: none;
|
||||
@ -103,13 +104,6 @@ export class DeesButton extends DeesElement {
|
||||
border-top: 1px solid #0069f2;
|
||||
}
|
||||
|
||||
.button.disabled {
|
||||
background: ${cssManager.bdTheme('#ffffff00', '#11111100')};
|
||||
border: 1px dashed ${cssManager.bdTheme('#666666', '#666666')};
|
||||
color: #9b9b9e;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.button.highlighted {
|
||||
background: #e4002b;
|
||||
border: none;
|
||||
@ -131,6 +125,14 @@ export class DeesButton extends DeesElement {
|
||||
.button.discreet:hover {
|
||||
background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.1)', 'rgba(255, 255, 255, 0.1)')};
|
||||
}
|
||||
|
||||
.button.disabled {
|
||||
background: ${cssManager.bdTheme('#ffffff00', '#11111100')};
|
||||
border: 1px dashed ${cssManager.bdTheme('#666666', '#666666')};
|
||||
color: #9b9b9e;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.button.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ export class DeesChartArea extends DeesElement {
|
||||
super();
|
||||
domtools.elementBasic.setup();
|
||||
|
||||
this.resizeObserver = new ResizeObserver(entries => {
|
||||
this.resizeObserver = new ResizeObserver((entries) => {
|
||||
for (let entry of entries) {
|
||||
if (entry.target.classList.contains('mainbox')) {
|
||||
this.resizeChart(); // Call resizeChart when the .mainbox size changes
|
||||
@ -55,14 +55,14 @@ export class DeesChartArea extends DeesElement {
|
||||
});
|
||||
this.registerGarbageFunction(async () => {
|
||||
this.resizeObserver.disconnect();
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
public static styles = [
|
||||
cssManager.defaultStyles,
|
||||
css`
|
||||
:host {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-family: 'Geist Sans', sans-serif;
|
||||
color: #ccc;
|
||||
font-weight: 600;
|
||||
font-size: 12px;
|
||||
@ -71,7 +71,7 @@ export class DeesChartArea extends DeesElement {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
background: #222;
|
||||
background: #111;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
@ -95,10 +95,12 @@ export class DeesChartArea extends DeesElement {
|
||||
];
|
||||
|
||||
public render(): TemplateResult {
|
||||
return html` <div class="mainbox">
|
||||
<div class="chartTitle">${this.label}</div>
|
||||
<div class="chartContainer"></div>
|
||||
</div> `;
|
||||
return html`
|
||||
<div class="mainbox">
|
||||
<div class="chartTitle">${this.label}</div>
|
||||
<div class="chartContainer"></div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
public async firstUpdated() {
|
||||
@ -107,11 +109,23 @@ export class DeesChartArea extends DeesElement {
|
||||
series: [
|
||||
{
|
||||
name: 'cpu',
|
||||
data: [31, 40, 28, 51, 42, 109, 100],
|
||||
data: [
|
||||
{ x: '2025-01-15T03:00:00', y: 25 },
|
||||
{ x: '2025-01-15T07:00:00', y: 30 },
|
||||
{ x: '2025-01-15T11:00:00', y: 20 },
|
||||
{ x: '2025-01-15T15:00:00', y: 35 },
|
||||
{ x: '2025-01-15T19:00:00', y: 25 },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'memory',
|
||||
data: [11, 32, 45, 32, 34, 52, 41],
|
||||
data: [
|
||||
{ x: '2025-01-15T03:00:00', y: 10 },
|
||||
{ x: '2025-01-15T07:00:00', y: 12 },
|
||||
{ x: '2025-01-15T11:00:00', y: 10 },
|
||||
{ x: '2025-01-15T15:00:00', y: 30 },
|
||||
{ x: '2025-01-15T19:00:00', y: 40 },
|
||||
],
|
||||
},
|
||||
],
|
||||
chart: {
|
||||
@ -130,35 +144,62 @@ export class DeesChartArea extends DeesElement {
|
||||
curve: 'smooth',
|
||||
},
|
||||
xaxis: {
|
||||
crosshairs: {
|
||||
stroke: {
|
||||
width: 1,
|
||||
color: '#444',
|
||||
type: 'datetime', // Time-series data
|
||||
labels: {
|
||||
format: 'hh:mm A', // Time formatting
|
||||
style: {
|
||||
colors: '#9e9e9e', // Label color
|
||||
fontSize: '12px',
|
||||
},
|
||||
},
|
||||
type: 'datetime',
|
||||
categories: [
|
||||
'2018-09-19T00:00:00.000Z',
|
||||
'2018-09-19T01:30:00.000Z',
|
||||
'2018-09-19T02:30:00.000Z',
|
||||
'2018-09-19T03:30:00.000Z',
|
||||
'2018-09-19T04:30:00.000Z',
|
||||
'2018-09-19T05:30:00.000Z',
|
||||
'2018-09-19T06:30:00.000Z',
|
||||
],
|
||||
axisBorder: {
|
||||
show: false, // Hide x-axis border
|
||||
},
|
||||
axisTicks: {
|
||||
show: false, // Hide x-axis ticks
|
||||
},
|
||||
},
|
||||
yaxis: {
|
||||
crosshairs: {
|
||||
stroke: {
|
||||
width: 1,
|
||||
color: '#444',
|
||||
min: 0,
|
||||
labels: {
|
||||
formatter: function (val: number) {
|
||||
return `${val} Mbps`; // Format Y-axis labels
|
||||
},
|
||||
style: {
|
||||
colors: '#9e9e9e', // Label color
|
||||
fontSize: '12px',
|
||||
},
|
||||
},
|
||||
axisBorder: {
|
||||
show: false, // Hide y-axis border
|
||||
},
|
||||
axisTicks: {
|
||||
show: false, // Hide y-axis ticks
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
shared: true, // Enables the tooltip to display across series
|
||||
intersect: false, // Allows hovering anywhere on the chart
|
||||
followCursor: true, // Makes tooltip follow mouse even between points
|
||||
x: {
|
||||
format: 'dd/MM/yy HH:mm',
|
||||
},
|
||||
custom: function ({ series, seriesIndex, dataPointIndex, w }) {
|
||||
// Get the x value
|
||||
const xValue = w.globals.labels[dataPointIndex];
|
||||
// Iterate through each series and get its value
|
||||
let tooltipContent = `<div style="padding: 10px; background: #1e1e2f; color: white; border-radius: 5px;">`;
|
||||
tooltipContent += ``; // `<strong>Time:</strong> ${xValue}<br/>`;
|
||||
|
||||
series.forEach((s, index) => {
|
||||
const label = w.globals.seriesNames[index]; // Get series label
|
||||
const value = s[dataPointIndex]; // Get value at data point
|
||||
tooltipContent += `<strong>${label}:</strong> ${value} Mbps<br/>`;
|
||||
});
|
||||
|
||||
tooltipContent += `</div>`;
|
||||
return tooltipContent;
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
xaxis: {
|
||||
@ -171,8 +212,8 @@ export class DeesChartArea extends DeesElement {
|
||||
show: true,
|
||||
},
|
||||
},
|
||||
borderColor: '#666', // Set the color of the grid lines
|
||||
strokeDashArray: 2, // Solid line
|
||||
borderColor: '#333', // Set the color of the grid lines
|
||||
strokeDashArray: 0, // Solid line
|
||||
row: {
|
||||
colors: [], // This can be used to alternate the shading of the horizontal rows
|
||||
opacity: 0.1,
|
||||
@ -182,6 +223,15 @@ export class DeesChartArea extends DeesElement {
|
||||
opacity: 0.1,
|
||||
},
|
||||
},
|
||||
fill: {
|
||||
type: 'gradient', // Gradient fill for the area
|
||||
gradient: {
|
||||
shade: 'dark',
|
||||
type: 'vertical',
|
||||
gradientToColors: ['#9c27b0'], // Gradient color ending
|
||||
stops: [0, 100],
|
||||
},
|
||||
},
|
||||
};
|
||||
this.chart = new ApexCharts(this.shadowRoot.querySelector('.chartContainer'), options);
|
||||
await this.chart.render();
|
||||
@ -189,20 +239,22 @@ export class DeesChartArea extends DeesElement {
|
||||
}
|
||||
|
||||
public async resizeChart() {
|
||||
const element = this.shadowRoot.querySelector('.chartContainer');
|
||||
const mainbox: HTMLDivElement = this.shadowRoot.querySelector('.mainbox');
|
||||
const chartContainer: HTMLDivElement = this.shadowRoot.querySelector('.chartContainer');
|
||||
|
||||
// Get computed style of the element
|
||||
const style = window.getComputedStyle(element);
|
||||
const styleMainbox = window.getComputedStyle(mainbox);
|
||||
const styleChartContainer = window.getComputedStyle(chartContainer);
|
||||
|
||||
// Extract padding values
|
||||
const paddingTop = parseInt(style.paddingTop, 10);
|
||||
const paddingBottom = parseInt(style.paddingBottom, 10);
|
||||
const paddingLeft = parseInt(style.paddingLeft, 10);
|
||||
const paddingRight = parseInt(style.paddingRight, 10);
|
||||
const paddingTop = parseInt(styleChartContainer.paddingTop, 10);
|
||||
const paddingBottom = parseInt(styleChartContainer.paddingBottom, 10);
|
||||
const paddingLeft = parseInt(styleChartContainer.paddingLeft, 10);
|
||||
const paddingRight = parseInt(styleChartContainer.paddingRight, 10);
|
||||
|
||||
// Calculate the actual width and height to use, subtracting padding
|
||||
const actualWidth = element.clientWidth - paddingLeft - paddingRight;
|
||||
const actualHeight = element.clientHeight - paddingTop - paddingBottom;
|
||||
const actualWidth = mainbox.clientWidth - paddingLeft - paddingRight;
|
||||
const actualHeight = mainbox.offsetHeight - paddingTop - paddingBottom;
|
||||
|
||||
await this.chart.updateOptions({
|
||||
chart: {
|
||||
|
@ -41,7 +41,7 @@ export class DeesChartLog extends DeesElement {
|
||||
cssManager.defaultStyles,
|
||||
css`
|
||||
:host {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-family: 'Geist Sans', sans-serif;
|
||||
color: #ccc;
|
||||
font-weight: 600;
|
||||
font-size: 12px;
|
||||
|
@ -48,7 +48,7 @@ export class DeesDataviewCodebox extends DeesElement {
|
||||
display: block;
|
||||
text-align: left;
|
||||
font-size: 16px;
|
||||
font-family: 'Roboto', 'Inter', sans-serif;
|
||||
font-family: 'Geist Sans', sans-serif;
|
||||
}
|
||||
.mainbox {
|
||||
position: relative;
|
||||
@ -142,7 +142,7 @@ export class DeesDataviewCodebox extends DeesElement {
|
||||
.lineNumbers {
|
||||
line-height: 1.4em;
|
||||
font-weight: 200;
|
||||
font-family: 'Intel One Mono', 'monospace';
|
||||
font-family: 'Intel One Mono', 'Geist Mono', 'monospace';
|
||||
}
|
||||
|
||||
.hljs-string {
|
||||
|
@ -133,7 +133,7 @@ export class DeesDataviewStatusobject extends DeesElement {
|
||||
|
||||
.detail .detailsText .value {
|
||||
font-size: 14px;
|
||||
font-family: 'Intel One Mono';
|
||||
font-family: 'Intel One Mono', 'Geist Mono';
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
14
ts_web/elements/dees-heading.demo.ts
Normal file
14
ts_web/elements/dees-heading.demo.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { html } from '@design.estate/dees-element';
|
||||
|
||||
export function demoFunc() {
|
||||
return html`
|
||||
<dees-heading level="1">This is a H1 heading</dees-heading>
|
||||
<dees-heading level="2">This is a H2 heading</dees-heading>
|
||||
<dees-heading level="3">This is a H3 heading</dees-heading>
|
||||
<dees-heading level="4">This is a H4 heading</dees-heading>
|
||||
<dees-heading level="5">This is a H5 heading</dees-heading>
|
||||
<dees-heading level="6">This is a H6 heading</dees-heading>
|
||||
<dees-heading level="hr">This is an hr heading</dees-heading>
|
||||
<dees-heading level="hr-small">This is an hr small heading</dees-heading>
|
||||
`;
|
||||
}
|
115
ts_web/elements/dees-heading.ts
Normal file
115
ts_web/elements/dees-heading.ts
Normal file
@ -0,0 +1,115 @@
|
||||
import {
|
||||
customElement,
|
||||
html,
|
||||
css,
|
||||
property,
|
||||
cssManager,
|
||||
type TemplateResult,
|
||||
DeesElement,
|
||||
type CSSResult,
|
||||
} from '@design.estate/dees-element';
|
||||
|
||||
import { demoFunc } from './dees-heading.demo.js';
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'dees-heading': DeesHeading;
|
||||
}
|
||||
}
|
||||
|
||||
@customElement('dees-heading')
|
||||
export class DeesHeading extends DeesElement {
|
||||
// demo
|
||||
public static demo = demoFunc;
|
||||
|
||||
// properties
|
||||
/**
|
||||
* Heading level: 1-6 for h1-h6, or 'hr' for horizontal rule style
|
||||
*/
|
||||
@property({ type: String, reflect: true })
|
||||
public level: '1' | '2' | '3' | '4' | '5' | '6' | 'hr' | 'hr-small' = '1';
|
||||
|
||||
// STATIC STYLES
|
||||
public static styles: CSSResult[] = [
|
||||
cssManager.defaultStyles,
|
||||
css`
|
||||
/* Heading styles */
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
margin: 16px 0 8px;
|
||||
font-weight: 600;
|
||||
color: ${cssManager.bdTheme('#000', '#fff')};
|
||||
}
|
||||
h1 { font-size: 32px; font-family: 'Cal Sans'; letter-spacing: 0.025em;}
|
||||
h2 { font-size: 28px; }
|
||||
h3 { font-size: 24px; }
|
||||
h4 { font-size: 20px; }
|
||||
h5 { font-size: 16px; }
|
||||
h6 { font-size: 14px; }
|
||||
/* Horizontal rule style heading */
|
||||
.heading-hr {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
margin: 16px 0;
|
||||
color: ${cssManager.bdTheme('#000', '#fff')};
|
||||
}
|
||||
/* Fade lines toward and away from text for hr style */
|
||||
.heading-hr::before {
|
||||
content: '';
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
/* fade in toward center */
|
||||
background: ${cssManager.bdTheme(
|
||||
'linear-gradient(to right, transparent, #ccc)',
|
||||
'linear-gradient(to right, transparent, #333)'
|
||||
)};
|
||||
margin: 0 8px;
|
||||
}
|
||||
.heading-hr::after {
|
||||
content: '';
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
/* fade out away from center */
|
||||
background: ${cssManager.bdTheme(
|
||||
'linear-gradient(to right, #ccc, transparent)',
|
||||
'linear-gradient(to right, #333, transparent)'
|
||||
)};
|
||||
margin: 0 8px;
|
||||
}
|
||||
/* Small hr variant with reduced margins */
|
||||
.heading-hr.heading-hr-small {
|
||||
margin: 8px 0;
|
||||
font-size: 12px;
|
||||
}
|
||||
.heading-hr.heading-hr-small::before,
|
||||
.heading-hr.heading-hr-small::after {
|
||||
margin: 0 8px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
|
||||
// INSTANCE
|
||||
public render(): TemplateResult {
|
||||
switch (this.level) {
|
||||
case '1':
|
||||
return html`<h1><slot></slot></h1>`;
|
||||
case '2':
|
||||
return html`<h2><slot></slot></h2>`;
|
||||
case '3':
|
||||
return html`<h3><slot></slot></h3>`;
|
||||
case '4':
|
||||
return html`<h4><slot></slot></h4>`;
|
||||
case '5':
|
||||
return html`<h5><slot></slot></h5>`;
|
||||
case '6':
|
||||
return html`<h6><slot></slot></h6>`;
|
||||
case 'hr':
|
||||
return html`<div class="heading-hr"><slot></slot></div>`;
|
||||
case 'hr-small':
|
||||
return html`<div class="heading-hr heading-hr-small"><slot></slot></div>`;
|
||||
default:
|
||||
return html`<h1><slot></slot></h1>`;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,31 +1,155 @@
|
||||
import { html } from '@design.estate/dees-element';
|
||||
import { icons, type IconWithPrefix } from './dees-icon.js';
|
||||
import * as lucideIcons from 'lucide';
|
||||
|
||||
import { faIcons } from './dees-icon.js';
|
||||
export const demoFunc = () => {
|
||||
// Group FontAwesome icons by type
|
||||
const faIcons = Object.keys(icons.fa);
|
||||
|
||||
// Extract Lucide icons from the lucideIcons object directly
|
||||
// Log the first few keys to understand the structure
|
||||
console.log('First few Lucide keys:', Object.keys(lucideIcons).slice(0, 5));
|
||||
|
||||
// Get all icon functions from lucideIcons (they have PascalCase names)
|
||||
const lucideIconsList = Object.keys(lucideIcons)
|
||||
.filter(key => {
|
||||
// Skip utility functions and focus on icon components (first letter is uppercase)
|
||||
const isUppercaseFirst = key[0] === key[0].toUpperCase() && key[0] !== key[0].toLowerCase();
|
||||
const isFunction = typeof lucideIcons[key] === 'function';
|
||||
const notUtility = !['createElement', 'createIcons', 'default'].includes(key);
|
||||
return isFunction && isUppercaseFirst && notUtility;
|
||||
})
|
||||
.map(pascalName => {
|
||||
// Convert PascalCase to camelCase
|
||||
return pascalName.charAt(0).toLowerCase() + pascalName.slice(1);
|
||||
});
|
||||
|
||||
// Log how many icons we found
|
||||
console.log(`Found ${lucideIconsList.length} Lucide icons`);
|
||||
|
||||
// If we didn't find any, try an alternative approach
|
||||
if (lucideIconsList.length === 0) {
|
||||
console.log('Trying alternative approach to find Lucide icons');
|
||||
|
||||
// Try to get icon names from a known property if available
|
||||
if (lucideIcons.icons) {
|
||||
const iconSource = lucideIcons.icons || {};
|
||||
lucideIconsList.push(...Object.keys(iconSource));
|
||||
console.log(`Found ${lucideIconsList.length} icons via alternative method`);
|
||||
}
|
||||
}
|
||||
|
||||
export const demoFunc = () => html`
|
||||
// Define the functions in TS scope instead of script tags
|
||||
const searchIcons = (event: InputEvent) => {
|
||||
const searchTerm = (event.target as HTMLInputElement).value.toLowerCase().trim();
|
||||
// Get the demo container first, then search within it
|
||||
const demoContainer = (event.target as HTMLElement).closest('.demoContainer');
|
||||
const containers = demoContainer.querySelectorAll('.iconContainer');
|
||||
|
||||
containers.forEach(container => {
|
||||
const iconName = container.getAttribute('data-name');
|
||||
|
||||
if (searchTerm === '') {
|
||||
container.classList.remove('hidden');
|
||||
} else if (iconName && iconName.includes(searchTerm)) {
|
||||
container.classList.remove('hidden');
|
||||
} else {
|
||||
container.classList.add('hidden');
|
||||
}
|
||||
});
|
||||
|
||||
// Update counts - search within demoContainer
|
||||
demoContainer.querySelectorAll('.section-container').forEach(section => {
|
||||
const visibleIcons = section.querySelectorAll('.iconContainer:not(.hidden)').length;
|
||||
const countElement = section.querySelector('.icon-count');
|
||||
if (countElement) {
|
||||
const totalIconsCount = section.classList.contains('fa-section')
|
||||
? faIcons.length
|
||||
: lucideIconsList.length;
|
||||
|
||||
countElement.textContent = visibleIcons === totalIconsCount
|
||||
? `${totalIconsCount} icons`
|
||||
: `${visibleIcons} of ${totalIconsCount} icons`;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const copyIconName = (iconNameToCopy: string, type: 'fa' | 'lucide') => {
|
||||
// Use the new prefix format
|
||||
const textToCopy = `${type}:${iconNameToCopy}`;
|
||||
|
||||
navigator.clipboard.writeText(textToCopy).then(() => {
|
||||
// Find the event target
|
||||
const currentEvent = window.event as MouseEvent;
|
||||
const currentTarget = currentEvent.currentTarget as HTMLElement;
|
||||
// Show feedback
|
||||
const tooltip = currentTarget.querySelector('.copy-tooltip');
|
||||
if (tooltip) {
|
||||
tooltip.textContent = 'Copied!';
|
||||
|
||||
setTimeout(() => {
|
||||
tooltip.textContent = 'Click to copy';
|
||||
}, 2000);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return html`
|
||||
<style>
|
||||
.demoContainer {
|
||||
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
background: #111111;
|
||||
padding: 10px; font-size: 30px;
|
||||
padding: 20px;
|
||||
font-size: 30px;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||
}
|
||||
|
||||
.search-container {
|
||||
width: 100%;
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#iconSearch {
|
||||
flex: 1;
|
||||
padding: 12px 16px;
|
||||
font-size: 16px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
background: #222;
|
||||
color: #fff;
|
||||
border: 1px solid #333;
|
||||
}
|
||||
|
||||
#iconSearch:focus {
|
||||
outline: none;
|
||||
border-color: #e4002b;
|
||||
}
|
||||
|
||||
dees-icon {
|
||||
transition: color 0.02s;
|
||||
transition: all 0.2s ease;
|
||||
color: #ffffff;
|
||||
}
|
||||
dees-icon:hover {
|
||||
color: #e4002b;
|
||||
}
|
||||
|
||||
.iconContainer {
|
||||
display: block;
|
||||
padding: 16px 16px 0px 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 20px 16px 0px 16px;
|
||||
border: 1px solid #333333;
|
||||
margin-right: 8px;
|
||||
margin-bottom: 8px;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 4px;
|
||||
transition: background-color 0.2s;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.iconContainer:hover {
|
||||
background-color: #222;
|
||||
}
|
||||
|
||||
.iconName {
|
||||
@ -33,23 +157,136 @@ export const demoFunc = () => html`
|
||||
text-align: center;
|
||||
color: #ccc;
|
||||
background: #333333;
|
||||
padding: 4px 8px;
|
||||
padding-bottom: 4px;
|
||||
padding: 6px 10px;
|
||||
margin-left: -16px;
|
||||
margin-right: -16px;
|
||||
margin-top: 16px;
|
||||
margin-top: 20px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 120px;
|
||||
border-radius: 0 0 4px 4px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
width: 100%;
|
||||
color: #ffffff;
|
||||
font-size: 24px;
|
||||
margin: 20px 0;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #333333;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.api-note {
|
||||
font-size: 14px;
|
||||
color: #e4002b;
|
||||
margin-bottom: 20px;
|
||||
padding: 10px;
|
||||
border: 1px solid #e4002b;
|
||||
border-radius: 4px;
|
||||
background: rgba(228, 0, 43, 0.1);
|
||||
}
|
||||
|
||||
.icon-count {
|
||||
font-size: 14px;
|
||||
color: #888;
|
||||
font-weight: normal;
|
||||
background: #222;
|
||||
padding: 5px 10px;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.icons-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.section-container {
|
||||
width: 100%;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.copy-tooltip {
|
||||
position: absolute;
|
||||
background: #333;
|
||||
color: white;
|
||||
padding: 5px 10px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
top: -30px;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.iconContainer:hover .copy-tooltip {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.iconContainer:hover dees-icon {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="demoContainer">
|
||||
${Object.keys(faIcons).map(
|
||||
(iconName) => html`
|
||||
<div class="iconContainer">
|
||||
<dees-icon .iconFA=${iconName as any}></dees-icon>
|
||||
<div class="iconName">${iconName}</div>
|
||||
</div>
|
||||
`
|
||||
)}
|
||||
<div class="demoContainer">
|
||||
<div class="search-container">
|
||||
<input type="text" id="iconSearch" placeholder="Search icons..." @input=${searchIcons}>
|
||||
</div>
|
||||
|
||||
`;
|
||||
|
||||
<div class="api-note">
|
||||
New API: Use <code>icon="fa:iconName"</code> or <code>icon="lucide:iconName"</code> instead of <code>iconFA</code>.
|
||||
Click any icon to copy its new format to clipboard.
|
||||
</div>
|
||||
|
||||
<div class="section-container fa-section">
|
||||
<div class="section-title">
|
||||
FontAwesome Icons
|
||||
<span class="icon-count">${faIcons.length} icons</span>
|
||||
</div>
|
||||
<div class="icons-grid">
|
||||
${faIcons.map(
|
||||
(iconName) => {
|
||||
const prefixedName = `fa:${iconName}`;
|
||||
return html`
|
||||
<div class="iconContainer fa-icon" data-name=${iconName.toLowerCase()} @click=${() => copyIconName(iconName, 'fa')}>
|
||||
<dees-icon .icon=${prefixedName as IconWithPrefix} iconSize="24"></dees-icon>
|
||||
<div class="iconName">${iconName}</div>
|
||||
<span class="copy-tooltip">Click to copy</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section-container lucide-section">
|
||||
<div class="section-title">
|
||||
Lucide Icons
|
||||
<span class="icon-count">${lucideIconsList.length} icons</span>
|
||||
</div>
|
||||
<div class="icons-grid">
|
||||
${lucideIconsList.map(
|
||||
(iconName) => {
|
||||
const prefixedName = `lucide:${iconName}`;
|
||||
return html`
|
||||
<div class="iconContainer lucide-icon" data-name=${iconName.toLowerCase()} @click=${() => copyIconName(iconName, 'lucide')}>
|
||||
<dees-icon .icon=${prefixedName as IconWithPrefix} iconSize="24"></dees-icon>
|
||||
<div class="iconName">${iconName}</div>
|
||||
<span class="copy-tooltip">Click to copy</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
};
|
||||
|
@ -75,7 +75,12 @@ import {
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
import { demoFunc } from './dees-icon.demo.js';
|
||||
|
||||
export const faIcons = {
|
||||
// Import Lucide icons and the createElement function
|
||||
import * as lucideIcons from 'lucide';
|
||||
import { createElement } from 'lucide';
|
||||
|
||||
// Collect FontAwesome icons
|
||||
const faIcons = {
|
||||
// normal
|
||||
arrowRight: faArrowRightSolid,
|
||||
arrowUpRightFromSquare: faArrowUpRightFromSquareSolid,
|
||||
@ -136,7 +141,32 @@ export const faIcons = {
|
||||
twitter: faTwitter,
|
||||
};
|
||||
|
||||
export type TIconKey = keyof typeof faIcons;
|
||||
// Create a string literal type for all FA icons
|
||||
type FAIconKey = keyof typeof faIcons;
|
||||
|
||||
// Create union types for the icons with prefixes
|
||||
export type IconWithPrefix = `fa:${FAIconKey}` | `lucide:${string}`;
|
||||
|
||||
// Export only FontAwesome icons directly
|
||||
export const icons = {
|
||||
fa: faIcons
|
||||
};
|
||||
|
||||
// Legacy type for backward compatibility
|
||||
export type TIconKey = FAIconKey | `lucide:${string}`;
|
||||
|
||||
// Use a global static cache for all icons to reduce rendering
|
||||
const iconCache = new Map<string, string>();
|
||||
|
||||
// Clear cache items occasionally to prevent memory leaks
|
||||
const MAX_CACHE_SIZE = 500;
|
||||
function limitCacheSize() {
|
||||
if (iconCache.size > MAX_CACHE_SIZE) {
|
||||
// Remove oldest entries (first 20% of items)
|
||||
const keysToDelete = Array.from(iconCache.keys()).slice(0, MAX_CACHE_SIZE / 5);
|
||||
keysToDelete.forEach(key => iconCache.delete(key));
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
@ -148,31 +178,170 @@ declare global {
|
||||
export class DeesIcon extends DeesElement {
|
||||
public static demo = demoFunc;
|
||||
|
||||
/**
|
||||
* @deprecated Use the `icon` property instead with format "fa:iconName" or "lucide:iconName"
|
||||
*/
|
||||
@property({
|
||||
type: String
|
||||
type: String,
|
||||
converter: {
|
||||
// Convert attribute string to property (for reflected attributes)
|
||||
fromAttribute: (value: string): TIconKey => value as TIconKey,
|
||||
// Convert property to attribute (for reflection)
|
||||
toAttribute: (value: TIconKey): string => value
|
||||
}
|
||||
})
|
||||
public iconFA: keyof typeof faIcons;
|
||||
public iconFA?: TIconKey;
|
||||
|
||||
@property()
|
||||
/**
|
||||
* The preferred icon property. Use format "fa:iconName" or "lucide:iconName"
|
||||
* Examples: "fa:check", "lucide:menu"
|
||||
*/
|
||||
@property({
|
||||
type: String,
|
||||
converter: {
|
||||
fromAttribute: (value: string): IconWithPrefix => value as IconWithPrefix,
|
||||
toAttribute: (value: IconWithPrefix): string => value
|
||||
}
|
||||
})
|
||||
public icon?: IconWithPrefix;
|
||||
|
||||
@property({ type: Number })
|
||||
public iconSize: number;
|
||||
|
||||
@property({ type: String })
|
||||
public color: string = 'currentColor';
|
||||
|
||||
@property({ type: Number })
|
||||
public strokeWidth: number = 2;
|
||||
|
||||
// For tracking when we need to re-render
|
||||
private lastIcon: IconWithPrefix | TIconKey | null = null;
|
||||
private lastIconSize: number | null = null;
|
||||
private lastColor: string | null = null;
|
||||
private lastStrokeWidth: number | null = null;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
domtools.elementBasic.setup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the effective icon value, supporting both the new `icon` property
|
||||
* and the legacy `iconFA` property for backward compatibility.
|
||||
* Prefers `icon` if both are set.
|
||||
*/
|
||||
private getEffectiveIcon(): IconWithPrefix | TIconKey | null {
|
||||
// Prefer the new API
|
||||
if (this.icon) {
|
||||
return this.icon;
|
||||
}
|
||||
|
||||
// Fall back to the old API
|
||||
if (this.iconFA) {
|
||||
// If iconFA is already in the proper format (lucide:name), use it directly
|
||||
if (this.iconFA.startsWith('lucide:')) {
|
||||
return this.iconFA;
|
||||
}
|
||||
|
||||
// For FontAwesome icons with no prefix, add the prefix
|
||||
return `fa:${this.iconFA}` as IconWithPrefix;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an icon string into its type and name parts
|
||||
* @param iconStr The icon string in format "type:name"
|
||||
* @returns Object with type and name properties
|
||||
*/
|
||||
private parseIconString(iconStr: string): { type: 'fa' | 'lucide', name: string } {
|
||||
if (iconStr.startsWith('fa:')) {
|
||||
return {
|
||||
type: 'fa',
|
||||
name: iconStr.substring(3) // Remove 'fa:' prefix
|
||||
};
|
||||
} else if (iconStr.startsWith('lucide:')) {
|
||||
return {
|
||||
type: 'lucide',
|
||||
name: iconStr.substring(7) // Remove 'lucide:' prefix
|
||||
};
|
||||
} else {
|
||||
// For backward compatibility, assume FontAwesome if no prefix
|
||||
return {
|
||||
type: 'fa',
|
||||
name: iconStr
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private renderLucideIcon(iconName: string): string {
|
||||
// Create a cache key based on all visual properties
|
||||
const cacheKey = `lucide:${iconName}:${this.iconSize}:${this.color}:${this.strokeWidth}`;
|
||||
|
||||
// Check if we already have this icon in the cache
|
||||
if (iconCache.has(cacheKey)) {
|
||||
return iconCache.get(cacheKey) || '';
|
||||
}
|
||||
|
||||
try {
|
||||
// Get the Pascal case icon name (Menu instead of menu)
|
||||
const pascalCaseName = iconName.charAt(0).toUpperCase() + iconName.slice(1);
|
||||
|
||||
// Check if the icon exists in lucideIcons
|
||||
if (!lucideIcons[pascalCaseName]) {
|
||||
console.warn(`Lucide icon '${pascalCaseName}' not found in lucideIcons object`);
|
||||
return '';
|
||||
}
|
||||
|
||||
// Use the exact pattern from Lucide documentation
|
||||
const svgElement = createElement(lucideIcons[pascalCaseName], {
|
||||
color: this.color,
|
||||
size: this.iconSize,
|
||||
strokeWidth: this.strokeWidth
|
||||
});
|
||||
|
||||
if (!svgElement) {
|
||||
console.warn(`createElement returned empty result for ${pascalCaseName}`);
|
||||
return '';
|
||||
}
|
||||
|
||||
// Get the HTML
|
||||
const result = svgElement.outerHTML;
|
||||
|
||||
// Cache the result for future use
|
||||
iconCache.set(cacheKey, result);
|
||||
limitCacheSize();
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error(`Error rendering Lucide icon ${iconName}:`, error);
|
||||
|
||||
// Create a fallback SVG with the icon name
|
||||
return `<svg xmlns="http://www.w3.org/2000/svg" width="${this.iconSize}" height="${this.iconSize}" viewBox="0 0 24 24" fill="none" stroke="${this.color}" stroke-width="${this.strokeWidth}" stroke-linecap="round" stroke-linejoin="round">
|
||||
<text x="50%" y="50%" font-size="6" text-anchor="middle" dominant-baseline="middle" fill="${this.color}">${iconName}</text>
|
||||
</svg>`;
|
||||
}
|
||||
}
|
||||
|
||||
public static styles = [
|
||||
cssManager.defaultStyles,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
display: flex;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
line-height: 1;
|
||||
vertical-align: middle;
|
||||
}
|
||||
* {
|
||||
transition: inherit !important;
|
||||
|
||||
/* Improve rendering performance */
|
||||
#iconContainer svg {
|
||||
display: block;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
will-change: transform; /* Helps with animations */
|
||||
contain: strict; /* Performance optimization */
|
||||
}
|
||||
`,
|
||||
];
|
||||
@ -181,8 +350,8 @@ export class DeesIcon extends DeesElement {
|
||||
return html`
|
||||
${domtools.elementBasic.styles}
|
||||
<style>
|
||||
#iconContainer svg {
|
||||
display: block;
|
||||
#iconContainer {
|
||||
width: ${this.iconSize}px;
|
||||
height: ${this.iconSize}px;
|
||||
}
|
||||
</style>
|
||||
@ -190,14 +359,95 @@ export class DeesIcon extends DeesElement {
|
||||
`;
|
||||
}
|
||||
|
||||
public async updated() {
|
||||
public updated() {
|
||||
// If size is not specified, use font size as a base
|
||||
if (!this.iconSize) {
|
||||
this.iconSize = parseInt(globalThis.getComputedStyle(this).fontSize.replace(/\D/g,''));
|
||||
}
|
||||
if (this.iconFA) {
|
||||
this.shadowRoot.querySelector('#iconContainer').innerHTML = this.iconFA
|
||||
? icon(faIcons[this.iconFA]).html[0]
|
||||
: 'icon not found';
|
||||
|
||||
// Get the effective icon (either from icon or iconFA property)
|
||||
const effectiveIcon = this.getEffectiveIcon();
|
||||
|
||||
// Check if we actually need to update the icon
|
||||
// This prevents unnecessary DOM operations when properties haven't changed
|
||||
if (this.lastIcon === effectiveIcon &&
|
||||
this.lastIconSize === this.iconSize &&
|
||||
this.lastColor === this.color &&
|
||||
this.lastStrokeWidth === this.strokeWidth) {
|
||||
return; // No visual changes - skip update
|
||||
}
|
||||
|
||||
// Update our "last properties" for future change detection
|
||||
this.lastIcon = effectiveIcon;
|
||||
this.lastIconSize = this.iconSize;
|
||||
this.lastColor = this.color;
|
||||
this.lastStrokeWidth = this.strokeWidth;
|
||||
|
||||
const container = this.shadowRoot?.querySelector('#iconContainer');
|
||||
if (!container || !effectiveIcon) return;
|
||||
|
||||
try {
|
||||
// Parse the icon string to get type and name
|
||||
const { type, name } = this.parseIconString(effectiveIcon);
|
||||
|
||||
if (type === 'lucide') {
|
||||
// For Lucide, use direct DOM manipulation as shown in the docs
|
||||
// This approach avoids HTML string issues
|
||||
container.innerHTML = ''; // Clear container
|
||||
|
||||
try {
|
||||
// Convert to PascalCase
|
||||
const pascalCaseName = name.charAt(0).toUpperCase() + name.slice(1);
|
||||
|
||||
if (lucideIcons[pascalCaseName]) {
|
||||
// Use the documented pattern from Lucide docs
|
||||
const svgElement = createElement(lucideIcons[pascalCaseName], {
|
||||
color: this.color,
|
||||
size: this.iconSize,
|
||||
strokeWidth: this.strokeWidth
|
||||
});
|
||||
|
||||
if (svgElement) {
|
||||
// Directly append the element
|
||||
container.appendChild(svgElement);
|
||||
return; // Exit early since we've added the element
|
||||
}
|
||||
}
|
||||
|
||||
// If we reach here, something went wrong
|
||||
throw new Error(`Could not create element for ${pascalCaseName}`);
|
||||
} catch (error) {
|
||||
console.error(`Error rendering Lucide icon:`, error);
|
||||
|
||||
// Fall back to the string-based approach
|
||||
const iconHtml = this.renderLucideIcon(name);
|
||||
if (iconHtml) {
|
||||
container.innerHTML = iconHtml;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Use FontAwesome rendering via HTML string
|
||||
const faIcon = icons.fa[name as FAIconKey];
|
||||
if (faIcon) {
|
||||
const iconHtml = icon(faIcon).html[0];
|
||||
container.innerHTML = iconHtml;
|
||||
} else {
|
||||
console.warn(`FontAwesome icon not found: ${name}`);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error updating icon ${effectiveIcon}:`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up resources when element is removed
|
||||
async disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
|
||||
// Clear our references
|
||||
this.lastIcon = null;
|
||||
this.lastIconSize = null;
|
||||
this.lastColor = null;
|
||||
this.lastStrokeWidth = null;
|
||||
}
|
||||
}
|
@ -142,7 +142,7 @@ export class DeesInputFileupload extends DeesElement {
|
||||
text-align: left;
|
||||
border-radius: 3px;
|
||||
color: ${cssManager.bdTheme('#666', '#ccc')};
|
||||
font-family: 'Roboto', 'Inter', sans-serif;
|
||||
font-family: 'Geist Sans', sans-serif;
|
||||
cursor: default;
|
||||
transition: all 0.2s;
|
||||
border-top: 1px solid #ffffff10;
|
||||
|
@ -12,6 +12,12 @@ import {
|
||||
|
||||
const { demoFunc } = await import('./dees-input-multitoggle.demo.js');
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'dees-input-multitoggle': DeesInputMultitoggle;
|
||||
}
|
||||
}
|
||||
|
||||
@customElement('dees-input-multitoggle')
|
||||
export class DeesInputMultitoggle extends DeesElement {
|
||||
public static demo = demoFunc;
|
||||
|
@ -176,7 +176,7 @@ export class DeesInputText extends DeesElement {
|
||||
return html`
|
||||
<style>
|
||||
input {
|
||||
font-family: ${this.isPasswordBool ? 'monospace' : 'Roboto'};
|
||||
font-family: ${this.isPasswordBool ? 'monospace' : 'Geist Sans'};
|
||||
letter-spacing: ${this.isPasswordBool ? '1px' : 'normal'};
|
||||
color: ${this.goBright ? '#333' : '#ccc'};
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ export class DeesMobilenavigation extends DeesElement {
|
||||
text-align: left;
|
||||
font-size: 24px;
|
||||
padding: 8px 0px;
|
||||
font-family: 'Roboto', 'Inter', sans-serif;
|
||||
font-family: 'Geist Sans', sans-serif;
|
||||
font-weight: 300;
|
||||
border-bottom: 1px dashed #444;
|
||||
margin-top: 16px;
|
||||
|
@ -71,7 +71,7 @@ export class DeesModal extends DeesElement {
|
||||
cssManager.defaultStyles,
|
||||
css`
|
||||
:host {
|
||||
font-family: 'Roboto', 'Inter', sans-serif;
|
||||
font-family: 'Geist Sans', sans-serif;
|
||||
color: ${cssManager.bdTheme('#333', '#fff')};
|
||||
will-change: transform;
|
||||
}
|
||||
@ -113,7 +113,7 @@ export class DeesModal extends DeesElement {
|
||||
|
||||
.modal .heading {
|
||||
height: 32px;
|
||||
font-family: 'Roboto', 'Inter', sans-serif;
|
||||
font-family: 'Geist Sans', sans-serif;
|
||||
line-height: 32px;
|
||||
text-align: center;
|
||||
font-weight: 600;
|
||||
|
28
ts_web/elements/dees-pagination.demo.ts
Normal file
28
ts_web/elements/dees-pagination.demo.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { html } from '@design.estate/dees-element';
|
||||
|
||||
/**
|
||||
* Demo for dees-pagination component
|
||||
*/
|
||||
export const demoFunc = () => html`
|
||||
<div style="display: flex; align-items: center; gap: 16px;">
|
||||
<!-- Small set of pages -->
|
||||
<div style="display: flex; flex-direction: column; gap: 4px;">
|
||||
<span>5 pages, starting at 1:</span>
|
||||
<dees-pagination
|
||||
.total=${5}
|
||||
.page=${1}
|
||||
@page-change=${(e: CustomEvent) => console.log('Page changed to', e.detail.page)}
|
||||
></dees-pagination>
|
||||
</div>
|
||||
|
||||
<!-- Larger set of pages -->
|
||||
<div style="display: flex; flex-direction: column; gap: 4px;">
|
||||
<span>15 pages, starting at 8:</span>
|
||||
<dees-pagination
|
||||
.total=${15}
|
||||
.page=${8}
|
||||
@page-change=${(e: CustomEvent) => console.log('Page changed to', e.detail.page)}
|
||||
></dees-pagination>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
133
ts_web/elements/dees-pagination.ts
Normal file
133
ts_web/elements/dees-pagination.ts
Normal file
@ -0,0 +1,133 @@
|
||||
import { customElement, html, DeesElement, property, css, cssManager, type TemplateResult } from '@design.estate/dees-element';
|
||||
import { demoFunc } from './dees-pagination.demo.js';
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'dees-pagination': DeesPagination;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple pagination component.
|
||||
* @fires page-change - Emitted when the page is changed. detail: { page: number }
|
||||
*/
|
||||
@customElement('dees-pagination')
|
||||
export class DeesPagination extends DeesElement {
|
||||
public static demo = demoFunc;
|
||||
/** Current page (1-based) */
|
||||
@property({ type: Number, reflect: true })
|
||||
public page = 1;
|
||||
|
||||
/** Total number of pages */
|
||||
@property({ type: Number, reflect: true })
|
||||
public total = 1;
|
||||
|
||||
public static styles = [
|
||||
cssManager.defaultStyles,
|
||||
css`
|
||||
:host {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
button {
|
||||
background: none;
|
||||
border: none;
|
||||
margin: 0 2px;
|
||||
padding: 6px 10px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
color: ${cssManager.bdTheme('#333', '#ccc')};
|
||||
border-radius: 3px;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
button:hover:not(:disabled) {
|
||||
background: ${cssManager.bdTheme('#eee', '#444')};
|
||||
}
|
||||
button:disabled {
|
||||
cursor: default;
|
||||
color: ${cssManager.bdTheme('#aaa', '#666')};
|
||||
}
|
||||
button.current {
|
||||
background: #0050b9;
|
||||
color: #fff;
|
||||
cursor: default;
|
||||
}
|
||||
span.ellipsis {
|
||||
margin: 0 4px;
|
||||
color: ${cssManager.bdTheme('#333', '#ccc')};
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
private get pages(): (number | string)[] {
|
||||
const pages: (number | string)[] = [];
|
||||
const total = this.total;
|
||||
const current = this.page;
|
||||
if (total <= 7) {
|
||||
for (let i = 1; i <= total; i++) {
|
||||
pages.push(i);
|
||||
}
|
||||
} else {
|
||||
pages.push(1);
|
||||
if (current > 4) {
|
||||
pages.push('...');
|
||||
}
|
||||
const start = Math.max(2, current - 2);
|
||||
const end = Math.min(total - 1, current + 2);
|
||||
for (let i = start; i <= end; i++) {
|
||||
pages.push(i);
|
||||
}
|
||||
if (current < total - 3) {
|
||||
pages.push('...');
|
||||
}
|
||||
pages.push(total);
|
||||
}
|
||||
return pages;
|
||||
}
|
||||
|
||||
public render(): TemplateResult {
|
||||
return html`
|
||||
<button
|
||||
@click=${() => this.changePage(this.page - 1)}
|
||||
?disabled=${this.page <= 1}
|
||||
aria-label="Previous page"
|
||||
>
|
||||
‹
|
||||
</button>
|
||||
${this.pages.map((p) =>
|
||||
p === '...'
|
||||
? html`<span class="ellipsis">…</span>`
|
||||
: html`
|
||||
<button
|
||||
class="${p === this.page ? 'current' : ''}"
|
||||
@click=${() => this.changePage(p as number)}
|
||||
?disabled=${p === this.page}
|
||||
aria-label="Page ${p}"
|
||||
>
|
||||
${p}
|
||||
</button>
|
||||
`
|
||||
)}
|
||||
<button
|
||||
@click=${() => this.changePage(this.page + 1)}
|
||||
?disabled=${this.page >= this.total}
|
||||
aria-label="Next page"
|
||||
>
|
||||
›
|
||||
</button>
|
||||
`;
|
||||
}
|
||||
|
||||
private changePage(newPage: number) {
|
||||
if (newPage < 1 || newPage > this.total || newPage === this.page) {
|
||||
return;
|
||||
}
|
||||
this.page = newPage;
|
||||
this.dispatchEvent(
|
||||
new CustomEvent('page-change', {
|
||||
detail: { page: this.page },
|
||||
bubbles: true,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
@ -32,7 +32,7 @@ export class DeesPdf extends DeesElement {
|
||||
return html`
|
||||
<style>
|
||||
:host {
|
||||
font-family: 'Roboto', 'Inter', sans-serif;
|
||||
font-family: 'Geist Sans', sans-serif;
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
max-width: 800px;
|
||||
|
46
ts_web/elements/dees-searchbar.demo.ts
Normal file
46
ts_web/elements/dees-searchbar.demo.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import { html } from '@design.estate/dees-element';
|
||||
|
||||
export const demoFunc = () => {
|
||||
const onChanged = (e: CustomEvent) => {
|
||||
// find the demo wrapper and update the 'changed' log inside it
|
||||
const wrapper = (e.target as HTMLElement).closest('.demoWrapper');
|
||||
const el = wrapper?.querySelector('#changed');
|
||||
if (el) el.textContent = `search-changed: ${e.detail.value}`;
|
||||
};
|
||||
const onSubmit = (e: CustomEvent) => {
|
||||
// find the demo wrapper and update the 'submitted' log inside it
|
||||
const wrapper = (e.target as HTMLElement).closest('.demoWrapper');
|
||||
const el = wrapper?.querySelector('#submitted');
|
||||
if (el) el.textContent = `search-submit: ${e.detail.value}`;
|
||||
};
|
||||
return html`
|
||||
<style>
|
||||
.demoWrapper {
|
||||
display: block;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
background: #888888;
|
||||
}
|
||||
.logs {
|
||||
padding: 16px;
|
||||
width: 600px;
|
||||
color: #fff;
|
||||
font-family: monospace;
|
||||
}
|
||||
.logs div {
|
||||
margin: 4px 0;
|
||||
}
|
||||
</style>
|
||||
<div class="demoWrapper">
|
||||
<dees-searchbar
|
||||
@search-changed=${onChanged}
|
||||
@search-submit=${onSubmit}
|
||||
></dees-searchbar>
|
||||
<div class="logs">
|
||||
<div id="changed">search-changed:</div>
|
||||
<div id="submitted">search-submit:</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
};
|
160
ts_web/elements/dees-searchbar.ts
Normal file
160
ts_web/elements/dees-searchbar.ts
Normal file
@ -0,0 +1,160 @@
|
||||
import {
|
||||
customElement,
|
||||
DeesElement,
|
||||
property,
|
||||
html,
|
||||
cssManager,
|
||||
unsafeCSS,
|
||||
css,
|
||||
type TemplateResult,
|
||||
domtools,
|
||||
query,
|
||||
} from '@design.estate/dees-element';
|
||||
|
||||
import * as colors from './00colors.js';
|
||||
import { demoFunc } from './dees-searchbar.demo.js';
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'dees-searchbar': DeesSearchbar;
|
||||
}
|
||||
}
|
||||
|
||||
@customElement('dees-searchbar')
|
||||
export class DeesSearchbar extends DeesElement {
|
||||
// DEMO
|
||||
public static demo = demoFunc;
|
||||
|
||||
// STATIC
|
||||
public static styles = [
|
||||
cssManager.defaultStyles,
|
||||
css`
|
||||
:host {
|
||||
padding: 40px;
|
||||
font-family: Dees Sans;
|
||||
display: block;
|
||||
background: ${cssManager.bdTheme('#eeeeeb', '#000000')};
|
||||
}
|
||||
|
||||
.searchboxContainer {
|
||||
position: relative;
|
||||
margin: auto;
|
||||
max-width: 800px;
|
||||
background: ${cssManager.bdTheme('#00000015', '#ffffff15')};
|
||||
--boxHeight: 60px;
|
||||
height: var(--boxHeight);
|
||||
border-radius: var(--boxHeight);
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 140px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-top: 1px solid ${cssManager.bdTheme('#00000015', '#ffffff20')};
|
||||
}
|
||||
|
||||
input {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border: none;
|
||||
background: none;
|
||||
color: ${cssManager.bdTheme('#000000', '#eeeeeb')};
|
||||
padding-left: 25px;
|
||||
margin-right: -8px;
|
||||
outline: none;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.searchButton {
|
||||
--buttonPadding: 8px;
|
||||
background: ${cssManager.bdTheme('#eeeeeb', '#000000')};
|
||||
color: ${cssManager.bdTheme('#000000', '#eeeeeb')};
|
||||
line-height: calc(var(--boxHeight) - (var(--buttonPadding) * 2));
|
||||
border-radius: var(--boxHeight);
|
||||
transform: scale(1) ;
|
||||
transform-origin: 50% 50%;
|
||||
text-align: center;
|
||||
|
||||
transition: transform 0.1s, background 0.1s;
|
||||
margin-right: var(--buttonPadding);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.searchButton:hover {
|
||||
color: #fff;
|
||||
background: ${cssManager.bdTheme(colors.bright.blue, colors.dark.blue)};
|
||||
}
|
||||
|
||||
.searchButton:active {
|
||||
color: #fff;
|
||||
background: ${cssManager.bdTheme(colors.bright.blueActive, colors.dark.blueActive)};
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.filters {
|
||||
margin: auto;
|
||||
max-width: 800px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
// INSTANCE
|
||||
|
||||
@property()
|
||||
public filters = [];
|
||||
|
||||
|
||||
@query('input')
|
||||
public searchInput!: HTMLInputElement;
|
||||
@query('.searchButton')
|
||||
public searchButton!: HTMLElement;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public render(): TemplateResult {
|
||||
return html`
|
||||
<div class="searchboxContainer">
|
||||
<input type="text" placeholder="Your Skills (e.g. TypeScript, Rust, Projectmanagement)" />
|
||||
<div class="searchButton">Search -></div>
|
||||
</div>
|
||||
${this.filters.length > 0 ? html`
|
||||
<div class="filters">
|
||||
<dees-heading level="hr-small">Filters</dees-heading>
|
||||
<dees-input-dropdown .label=${'location'}></dees-input-dropdown>
|
||||
</div>
|
||||
` : html``}
|
||||
`;
|
||||
}
|
||||
/**
|
||||
* Lifecycle: after first render, wire up events for input and submit actions
|
||||
*/
|
||||
public firstUpdated(): void {
|
||||
// dispatch change on each input
|
||||
this.searchInput.addEventListener('input', () => {
|
||||
this.dispatchEvent(new CustomEvent('search-changed', {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
detail: { value: this.searchInput.value }
|
||||
}));
|
||||
});
|
||||
// submit on Enter key
|
||||
this.searchInput.addEventListener('keydown', (e: KeyboardEvent) => {
|
||||
if (e.key === 'Enter') {
|
||||
this._dispatchSubmit();
|
||||
}
|
||||
});
|
||||
// submit on button click
|
||||
this.searchButton.addEventListener('click', () => this._dispatchSubmit());
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch a submit event with the current search value
|
||||
*/
|
||||
private _dispatchSubmit(): void {
|
||||
this.dispatchEvent(new CustomEvent('search-submit', {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
detail: { value: this.searchInput.value }
|
||||
}));
|
||||
}
|
||||
}
|
@ -39,6 +39,9 @@ export class DeesSimpleAppDash extends DeesElement {
|
||||
@property()
|
||||
public viewTabs: IView[] = [];
|
||||
|
||||
@property()
|
||||
public terminalSetupCommand: string = `pnpm install @serve.zone/cli && clear && servezone info`;
|
||||
|
||||
public static styles = [
|
||||
cssManager.defaultStyles,
|
||||
css`
|
||||
@ -46,41 +49,45 @@ export class DeesSimpleAppDash extends DeesElement {
|
||||
color: ${cssManager.bdTheme('#333', '#ccc')};
|
||||
user-select: none;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.maincontainer {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.appbar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
height: 32px;
|
||||
width: 100%;
|
||||
background: ${cssManager.bdTheme('#eeeeeb', '#222')};
|
||||
border-bottom: 1px solid ${cssManager.bdTheme('#ccc', '#ffffff10')};
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
height: calc(100% - 24px);
|
||||
width: 200px;
|
||||
background: ${cssManager.bdTheme('#eeeeeb', '#000')};
|
||||
border-right: 1px solid ${cssManager.bdTheme('#ccc', '#ffffff20')};
|
||||
font-size: 14px;
|
||||
line-height: 32px;
|
||||
font-family: 'Roboto', 'Inter', sans-serif;
|
||||
font-family: 'Geist Sans', sans-serif;
|
||||
padding: 0px 16px;
|
||||
z-index: 2;
|
||||
box-shadow: 0px 4px 10px 0px rgba(0, 0, 0, 0.8);
|
||||
display: grid;
|
||||
grid-template-columns: min-content 1fr auto;
|
||||
grid-template-rows: min-content auto min-content;
|
||||
}
|
||||
|
||||
.appbar .viewTabs {
|
||||
padding: 0px 16px;
|
||||
margin-left: -8px;
|
||||
margin-right: -8px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
align-items: top;
|
||||
}
|
||||
|
||||
.viewTab {
|
||||
@ -88,17 +95,18 @@ export class DeesSimpleAppDash extends DeesElement {
|
||||
}
|
||||
|
||||
.viewTab:hover {
|
||||
background: ${cssManager.bdTheme(colors.bright.blue, colors.dark.blue)};
|
||||
background: ${cssManager.bdTheme('#ccc', '#ffffff10')};
|
||||
color: ${cssManager.bdTheme('#000', '#fff')};
|
||||
}
|
||||
|
||||
.viewTab:active {
|
||||
background: ${cssManager.bdTheme(colors.bright.blueActive, colors.dark.blueActive)};
|
||||
background: ${cssManager.bdTheme('#aaa', '#ffffff20')};
|
||||
color: ${cssManager.bdTheme('#000', '#fff')};
|
||||
}
|
||||
|
||||
.appName {
|
||||
white-space: nowrap;
|
||||
color: ${cssManager.bdTheme('#666', '#999')};
|
||||
}
|
||||
|
||||
.appActions {
|
||||
@ -113,11 +121,12 @@ export class DeesSimpleAppDash extends DeesElement {
|
||||
|
||||
.appcontent {
|
||||
z-index: 1;
|
||||
position: fixed;
|
||||
top: 32px;
|
||||
height: calc(100vh - 32px - 24px);
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
height: calc(100vh - 24px);
|
||||
bottom: 24px;
|
||||
width: 100%;
|
||||
width: calc(100vw - 200px);
|
||||
overflow: auto;
|
||||
background: ${cssManager.bdTheme('#eeeeeb', '#000')};
|
||||
overscroll-behavior: contain;
|
||||
@ -129,6 +138,7 @@ export class DeesSimpleAppDash extends DeesElement {
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
border-top: 1px solid #44444480;
|
||||
height: 24px;
|
||||
background: ${cssManager.bdTheme(colors.bright.blueMuted, colors.dark.blueMuted)};
|
||||
z-index: 2;
|
||||
@ -189,14 +199,17 @@ export class DeesSimpleAppDash extends DeesElement {
|
||||
await this.loadView(this.viewTabs[0]);
|
||||
}
|
||||
|
||||
public currentTerminal: DeesTerminal;
|
||||
public async launchTerminal() {
|
||||
const maincontainer = this.shadowRoot.querySelector('.maincontainer');
|
||||
const terminal = new DeesTerminal();
|
||||
terminal.setupCommand = this.terminalSetupCommand;
|
||||
this.currentTerminal = terminal;
|
||||
maincontainer.appendChild(terminal);
|
||||
terminal.style.position = 'absolute';
|
||||
terminal.style.zIndex = '1';
|
||||
terminal.style.top = '32px';
|
||||
terminal.style.left = '0px';
|
||||
terminal.style.top = '0px';
|
||||
terminal.style.left = '200px';
|
||||
terminal.style.right = '0px';
|
||||
terminal.style.bottom = '24px';
|
||||
terminal.style.opacity = '0';
|
||||
@ -205,6 +218,7 @@ export class DeesSimpleAppDash extends DeesElement {
|
||||
await domtools.plugins.smartdelay.delayFor(0);
|
||||
terminal.style.opacity = '1';
|
||||
terminal.style.transform = 'translateY(0px)';
|
||||
return terminal;
|
||||
}
|
||||
|
||||
private currentView: DeesElement;
|
||||
|
389
ts_web/elements/dees-statsgrid.demo.ts
Normal file
389
ts_web/elements/dees-statsgrid.demo.ts
Normal file
@ -0,0 +1,389 @@
|
||||
import { html, cssManager } from '@design.estate/dees-element';
|
||||
import type { IStatsTile } from './dees-statsgrid.js';
|
||||
|
||||
export const demoFunc = () => {
|
||||
// Demo data with different tile types
|
||||
const demoTiles: IStatsTile[] = [
|
||||
{
|
||||
id: 'revenue',
|
||||
title: 'Total Revenue',
|
||||
value: 125420,
|
||||
unit: '$',
|
||||
type: 'number',
|
||||
icon: 'faDollarSign',
|
||||
description: '+12.5% from last month',
|
||||
color: '#22c55e',
|
||||
actions: [
|
||||
{
|
||||
name: 'View Details',
|
||||
iconName: 'faChartLine',
|
||||
action: async () => {
|
||||
console.log('Viewing revenue details for tile:', 'revenue');
|
||||
console.log('Current value:', 125420);
|
||||
alert(`Revenue Details: $125,420 (+12.5%)`);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Export Data',
|
||||
iconName: 'faFileExport',
|
||||
action: async () => {
|
||||
console.log('Exporting revenue data');
|
||||
alert('Revenue data exported to CSV');
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'users',
|
||||
title: 'Active Users',
|
||||
value: 3847,
|
||||
type: 'number',
|
||||
icon: 'faUsers',
|
||||
description: '324 new this week',
|
||||
actions: [
|
||||
{
|
||||
name: 'View User List',
|
||||
iconName: 'faList',
|
||||
action: async () => {
|
||||
console.log('Viewing user list');
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'cpu',
|
||||
title: 'CPU Usage',
|
||||
value: 73,
|
||||
type: 'gauge',
|
||||
icon: 'faMicrochip',
|
||||
gaugeOptions: {
|
||||
min: 0,
|
||||
max: 100,
|
||||
thresholds: [
|
||||
{ value: 0, color: '#22c55e' },
|
||||
{ value: 60, color: '#f59e0b' },
|
||||
{ value: 80, color: '#ef4444' }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'storage',
|
||||
title: 'Storage Used',
|
||||
value: 65,
|
||||
type: 'percentage',
|
||||
icon: 'faHardDrive',
|
||||
description: '650 GB of 1 TB',
|
||||
color: '#3b82f6'
|
||||
},
|
||||
{
|
||||
id: 'memory',
|
||||
title: 'Memory Usage',
|
||||
value: 45,
|
||||
type: 'gauge',
|
||||
icon: 'faMemory',
|
||||
gaugeOptions: {
|
||||
min: 0,
|
||||
max: 100,
|
||||
thresholds: [
|
||||
{ value: 0, color: '#22c55e' },
|
||||
{ value: 70, color: '#f59e0b' },
|
||||
{ value: 90, color: '#ef4444' }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'requests',
|
||||
title: 'API Requests',
|
||||
value: '1.2k',
|
||||
unit: '/min',
|
||||
type: 'trend',
|
||||
icon: 'faServer',
|
||||
trendData: [45, 52, 38, 65, 72, 68, 75, 82, 79, 85, 88, 92]
|
||||
},
|
||||
{
|
||||
id: 'uptime',
|
||||
title: 'System Uptime',
|
||||
value: '99.95%',
|
||||
type: 'text',
|
||||
icon: 'faCheckCircle',
|
||||
color: '#22c55e',
|
||||
description: 'Last 30 days'
|
||||
},
|
||||
{
|
||||
id: 'latency',
|
||||
title: 'Response Time',
|
||||
value: 142,
|
||||
unit: 'ms',
|
||||
type: 'trend',
|
||||
icon: 'faClock',
|
||||
trendData: [150, 145, 148, 142, 138, 140, 135, 145, 142],
|
||||
description: 'P95 latency'
|
||||
},
|
||||
{
|
||||
id: 'errors',
|
||||
title: 'Error Rate',
|
||||
value: 0.03,
|
||||
unit: '%',
|
||||
type: 'number',
|
||||
icon: 'faExclamationTriangle',
|
||||
color: '#ef4444',
|
||||
actions: [
|
||||
{
|
||||
name: 'View Error Logs',
|
||||
iconName: 'faFileAlt',
|
||||
action: async () => {
|
||||
console.log('Viewing error logs');
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
// Grid actions for the demo
|
||||
const gridActions = [
|
||||
{
|
||||
name: 'Refresh',
|
||||
iconName: 'faSync',
|
||||
action: async () => {
|
||||
console.log('Refreshing stats...');
|
||||
// Simulate refresh animation
|
||||
const grid = document.querySelector('dees-statsgrid');
|
||||
if (grid) {
|
||||
grid.style.opacity = '0.5';
|
||||
setTimeout(() => {
|
||||
grid.style.opacity = '1';
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Export Report',
|
||||
iconName: 'faFileExport',
|
||||
action: async () => {
|
||||
console.log('Exporting stats report...');
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Settings',
|
||||
iconName: 'faCog',
|
||||
action: async () => {
|
||||
console.log('Opening settings...');
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
return html`
|
||||
<style>
|
||||
.demo-container {
|
||||
padding: 32px;
|
||||
background: ${cssManager.bdTheme('#f8f9fa', '#0a0a0a')};
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.demo-section {
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
|
||||
.demo-title {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 16px;
|
||||
color: ${cssManager.bdTheme('#333', '#fff')};
|
||||
}
|
||||
|
||||
.demo-description {
|
||||
font-size: 14px;
|
||||
color: ${cssManager.bdTheme('#666', '#aaa')};
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.theme-toggle {
|
||||
position: fixed;
|
||||
top: 16px;
|
||||
right: 16px;
|
||||
padding: 8px 16px;
|
||||
background: ${cssManager.bdTheme('#fff', '#1a1a1a')};
|
||||
border: 1px solid ${cssManager.bdTheme('#e0e0e0', '#2a2a2a')};
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
z-index: 100;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="demo-container">
|
||||
<button class="theme-toggle" @click=${() => {
|
||||
document.body.classList.toggle('bright');
|
||||
}}>Toggle Theme</button>
|
||||
|
||||
<div class="demo-section">
|
||||
<h2 class="demo-title">Full Featured Stats Grid</h2>
|
||||
<p class="demo-description">
|
||||
A comprehensive dashboard with various tile types, actions, and real-time updates.
|
||||
</p>
|
||||
<dees-statsgrid
|
||||
.tiles=${demoTiles}
|
||||
.gridActions=${gridActions}
|
||||
.minTileWidth=${250}
|
||||
.gap=${16}
|
||||
></dees-statsgrid>
|
||||
</div>
|
||||
|
||||
<div class="demo-section">
|
||||
<h2 class="demo-title">Compact Grid (Smaller Tiles)</h2>
|
||||
<p class="demo-description">
|
||||
Same data displayed with smaller minimum tile width for more compact layouts.
|
||||
</p>
|
||||
<dees-statsgrid
|
||||
.tiles=${demoTiles.slice(0, 6)}
|
||||
.minTileWidth=${180}
|
||||
.gap=${12}
|
||||
></dees-statsgrid>
|
||||
</div>
|
||||
|
||||
<div class="demo-section">
|
||||
<h2 class="demo-title">Simple Metrics (No Actions)</h2>
|
||||
<p class="demo-description">
|
||||
Clean display without interactive elements for pure visualization.
|
||||
</p>
|
||||
<dees-statsgrid
|
||||
.tiles=${[
|
||||
{
|
||||
id: 'metric1',
|
||||
title: 'Total Sales',
|
||||
value: 48293,
|
||||
type: 'number',
|
||||
icon: 'faShoppingCart'
|
||||
},
|
||||
{
|
||||
id: 'metric2',
|
||||
title: 'Conversion Rate',
|
||||
value: 3.4,
|
||||
unit: '%',
|
||||
type: 'number',
|
||||
icon: 'faChartLine'
|
||||
},
|
||||
{
|
||||
id: 'metric3',
|
||||
title: 'Avg Order Value',
|
||||
value: 127.50,
|
||||
unit: '$',
|
||||
type: 'number',
|
||||
icon: 'faReceipt'
|
||||
},
|
||||
{
|
||||
id: 'metric4',
|
||||
title: 'Customer Satisfaction',
|
||||
value: 92,
|
||||
type: 'percentage',
|
||||
icon: 'faSmile',
|
||||
color: '#22c55e'
|
||||
}
|
||||
]}
|
||||
.minTileWidth=${220}
|
||||
.gap=${16}
|
||||
></dees-statsgrid>
|
||||
</div>
|
||||
|
||||
<div class="demo-section">
|
||||
<h2 class="demo-title">Performance Monitoring</h2>
|
||||
<p class="demo-description">
|
||||
Real-time performance metrics with gauge visualizations and thresholds.
|
||||
</p>
|
||||
<dees-statsgrid
|
||||
.tiles=${[
|
||||
{
|
||||
id: 'perf1',
|
||||
title: 'Database Load',
|
||||
value: 42,
|
||||
type: 'gauge',
|
||||
icon: 'faDatabase',
|
||||
gaugeOptions: {
|
||||
min: 0,
|
||||
max: 100,
|
||||
thresholds: [
|
||||
{ value: 0, color: '#10b981' },
|
||||
{ value: 50, color: '#f59e0b' },
|
||||
{ value: 75, color: '#ef4444' }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'perf2',
|
||||
title: 'Network I/O',
|
||||
value: 856,
|
||||
unit: 'MB/s',
|
||||
type: 'trend',
|
||||
icon: 'faNetworkWired',
|
||||
trendData: [720, 780, 823, 845, 812, 876, 856]
|
||||
},
|
||||
{
|
||||
id: 'perf3',
|
||||
title: 'Cache Hit Rate',
|
||||
value: 94.2,
|
||||
type: 'percentage',
|
||||
icon: 'faBolt',
|
||||
color: '#3b82f6'
|
||||
},
|
||||
{
|
||||
id: 'perf4',
|
||||
title: 'Active Connections',
|
||||
value: 1428,
|
||||
type: 'number',
|
||||
icon: 'faLink',
|
||||
description: 'Peak: 2,100'
|
||||
}
|
||||
]}
|
||||
.gridActions=${[
|
||||
{
|
||||
name: 'Auto Refresh',
|
||||
iconName: 'faPlay',
|
||||
action: async () => {
|
||||
console.log('Starting auto refresh...');
|
||||
}
|
||||
}
|
||||
]}
|
||||
.minTileWidth=${280}
|
||||
.gap=${20}
|
||||
></dees-statsgrid>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Simulate real-time updates
|
||||
setInterval(() => {
|
||||
const grids = document.querySelectorAll('dees-statsgrid');
|
||||
grids.forEach(grid => {
|
||||
if (grid.tiles && grid.tiles.length > 0) {
|
||||
// Update some random values
|
||||
const updatedTiles = [...grid.tiles];
|
||||
|
||||
// Update trends with new data point
|
||||
updatedTiles.forEach(tile => {
|
||||
if (tile.type === 'trend' && tile.trendData) {
|
||||
tile.trendData = [...tile.trendData.slice(1),
|
||||
tile.trendData[tile.trendData.length - 1] + Math.random() * 10 - 5
|
||||
];
|
||||
}
|
||||
|
||||
// Randomly update some numeric values
|
||||
if (tile.type === 'number' && Math.random() > 0.7) {
|
||||
const currentValue = typeof tile.value === 'number' ? tile.value : parseFloat(tile.value);
|
||||
tile.value = Math.round(currentValue + (Math.random() * 10 - 5));
|
||||
}
|
||||
|
||||
// Update gauge values
|
||||
if (tile.type === 'gauge' && Math.random() > 0.5) {
|
||||
const currentValue = typeof tile.value === 'number' ? tile.value : parseFloat(tile.value);
|
||||
const newValue = currentValue + (Math.random() * 10 - 5);
|
||||
tile.value = Math.max(tile.gaugeOptions?.min || 0,
|
||||
Math.min(tile.gaugeOptions?.max || 100, Math.round(newValue)));
|
||||
}
|
||||
});
|
||||
|
||||
grid.tiles = updatedTiles;
|
||||
}
|
||||
});
|
||||
}, 3000);
|
||||
</script>
|
||||
</div>
|
||||
`;
|
||||
};
|
518
ts_web/elements/dees-statsgrid.ts
Normal file
518
ts_web/elements/dees-statsgrid.ts
Normal file
@ -0,0 +1,518 @@
|
||||
import { demoFunc } from './dees-statsgrid.demo.js';
|
||||
import * as plugins from './00plugins.js';
|
||||
import {
|
||||
customElement,
|
||||
html,
|
||||
DeesElement,
|
||||
property,
|
||||
state,
|
||||
css,
|
||||
unsafeCSS,
|
||||
cssManager,
|
||||
} from '@design.estate/dees-element';
|
||||
import type { TemplateResult } from '@design.estate/dees-element';
|
||||
|
||||
import './dees-icon.js';
|
||||
import './dees-contextmenu.js';
|
||||
import './dees-button.js';
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'dees-statsgrid': DeesStatsGrid;
|
||||
}
|
||||
}
|
||||
|
||||
export interface IStatsTile {
|
||||
id: string;
|
||||
title: string;
|
||||
value: number | string;
|
||||
unit?: string;
|
||||
type: 'number' | 'gauge' | 'percentage' | 'trend' | 'text';
|
||||
|
||||
// For gauge type
|
||||
gaugeOptions?: {
|
||||
min: number;
|
||||
max: number;
|
||||
thresholds?: Array<{value: number; color: string}>;
|
||||
};
|
||||
|
||||
// For trend type
|
||||
trendData?: number[];
|
||||
|
||||
// Visual customization
|
||||
color?: string;
|
||||
icon?: string;
|
||||
description?: string;
|
||||
|
||||
// Tile-specific actions
|
||||
actions?: plugins.tsclass.website.IMenuItem[];
|
||||
}
|
||||
|
||||
@customElement('dees-statsgrid')
|
||||
export class DeesStatsGrid extends DeesElement {
|
||||
public static demo = demoFunc;
|
||||
|
||||
@property({ type: Array })
|
||||
public tiles: IStatsTile[] = [];
|
||||
|
||||
@property({ type: Number })
|
||||
public minTileWidth: number = 250;
|
||||
|
||||
@property({ type: Number })
|
||||
public gap: number = 16;
|
||||
|
||||
@property({ type: Array })
|
||||
public gridActions: plugins.tsclass.website.IMenuItem[] = [];
|
||||
|
||||
@state()
|
||||
private contextMenuVisible = false;
|
||||
|
||||
@state()
|
||||
private contextMenuPosition = { x: 0, y: 0 };
|
||||
|
||||
@state()
|
||||
private contextMenuActions: plugins.tsclass.website.IMenuItem[] = [];
|
||||
|
||||
public static styles = [
|
||||
cssManager.defaultStyles,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.grid-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: ${unsafeCSS(16)}px;
|
||||
min-height: 32px;
|
||||
}
|
||||
|
||||
.grid-title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: ${cssManager.bdTheme('#333', '#fff')};
|
||||
}
|
||||
|
||||
.grid-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.grid-actions dees-button {
|
||||
font-size: 14px;
|
||||
min-width: auto;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(${unsafeCSS(250)}px, 1fr));
|
||||
gap: ${unsafeCSS(16)}px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.stats-tile {
|
||||
background: ${cssManager.bdTheme('#fff', '#1a1a1a')};
|
||||
border: 1px solid ${cssManager.bdTheme('#e0e0e0', '#2a2a2a')};
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
transition: all 0.3s ease;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.stats-tile:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px ${cssManager.bdTheme('rgba(0,0,0,0.1)', 'rgba(0,0,0,0.3)')};
|
||||
border-color: ${cssManager.bdTheme('#d0d0d0', '#3a3a3a')};
|
||||
}
|
||||
|
||||
.stats-tile.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tile-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tile-title {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: ${cssManager.bdTheme('#666', '#aaa')};
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.tile-icon {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.tile-content {
|
||||
height: 90px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tile-value {
|
||||
font-size: 32px;
|
||||
font-weight: 600;
|
||||
color: ${cssManager.bdTheme('#333', '#fff')};
|
||||
line-height: 1.2;
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tile-unit {
|
||||
font-size: 18px;
|
||||
font-weight: 400;
|
||||
color: ${cssManager.bdTheme('#666', '#aaa')};
|
||||
}
|
||||
|
||||
.tile-description {
|
||||
font-size: 12px;
|
||||
color: ${cssManager.bdTheme('#888', '#777')};
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.gauge-container {
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.gauge-svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.gauge-background {
|
||||
fill: none;
|
||||
stroke: ${cssManager.bdTheme('#e0e0e0', '#2a2a2a')};
|
||||
stroke-width: 6;
|
||||
}
|
||||
|
||||
.gauge-fill {
|
||||
fill: none;
|
||||
stroke-width: 6;
|
||||
stroke-linecap: round;
|
||||
transition: stroke-dashoffset 0.5s ease;
|
||||
}
|
||||
|
||||
.gauge-text {
|
||||
fill: ${cssManager.bdTheme('#333', '#fff')};
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
text-anchor: middle;
|
||||
}
|
||||
|
||||
.percentage-container {
|
||||
width: 100%;
|
||||
height: 24px;
|
||||
background: ${cssManager.bdTheme('#f0f0f0', '#2a2a2a')};
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.percentage-fill {
|
||||
height: 100%;
|
||||
background: ${cssManager.bdTheme('#0084ff', '#0066cc')};
|
||||
transition: width 0.5s ease;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.percentage-text {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: ${cssManager.bdTheme('#333', '#fff')};
|
||||
}
|
||||
|
||||
.trend-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.trend-svg {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.trend-line {
|
||||
fill: none;
|
||||
stroke: ${cssManager.bdTheme('#0084ff', '#0066cc')};
|
||||
stroke-width: 2;
|
||||
}
|
||||
|
||||
.trend-area {
|
||||
fill: ${cssManager.bdTheme('rgba(0, 132, 255, 0.1)', 'rgba(0, 102, 204, 0.2)')};
|
||||
}
|
||||
|
||||
.text-value {
|
||||
font-size: 32px;
|
||||
font-weight: 600;
|
||||
color: ${cssManager.bdTheme('#333', '#fff')};
|
||||
}
|
||||
|
||||
.trend-value {
|
||||
font-size: 32px;
|
||||
font-weight: 600;
|
||||
color: ${cssManager.bdTheme('#333', '#fff')};
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.trend-value .tile-unit {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
dees-contextmenu {
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public render(): TemplateResult {
|
||||
return html`
|
||||
${this.gridActions.length > 0 ? html`
|
||||
<div class="grid-header">
|
||||
<div class="grid-title">Statistics</div>
|
||||
<div class="grid-actions">
|
||||
${this.gridActions.map(action => html`
|
||||
<dees-button @clicked=${() => this.handleGridAction(action)}>
|
||||
${action.iconName ? html`<dees-icon .iconFA=${action.iconName} size="small"></dees-icon>` : ''}
|
||||
${action.name}
|
||||
</dees-button>
|
||||
`)}
|
||||
</div>
|
||||
</div>
|
||||
` : ''}
|
||||
|
||||
<div class="stats-grid" style="grid-template-columns: repeat(auto-fit, minmax(${this.minTileWidth}px, 1fr)); gap: ${this.gap}px;">
|
||||
${this.tiles.map(tile => this.renderTile(tile))}
|
||||
</div>
|
||||
|
||||
${this.contextMenuVisible ? html`
|
||||
<dees-contextmenu
|
||||
.x=${this.contextMenuPosition.x}
|
||||
.y=${this.contextMenuPosition.y}
|
||||
.menuItems=${this.contextMenuActions}
|
||||
@clicked=${() => this.contextMenuVisible = false}
|
||||
></dees-contextmenu>
|
||||
` : ''}
|
||||
`;
|
||||
}
|
||||
|
||||
private renderTile(tile: IStatsTile): TemplateResult {
|
||||
const hasActions = tile.actions && tile.actions.length > 0;
|
||||
const clickable = hasActions && tile.actions.length === 1;
|
||||
|
||||
return html`
|
||||
<div
|
||||
class="stats-tile ${clickable ? 'clickable' : ''}"
|
||||
@click=${clickable ? () => this.handleTileAction(tile.actions![0], tile) : undefined}
|
||||
@contextmenu=${hasActions ? (e: MouseEvent) => this.showContextMenu(e, tile) : undefined}
|
||||
>
|
||||
<div class="tile-header">
|
||||
<h3 class="tile-title">${tile.title}</h3>
|
||||
${tile.icon ? html`
|
||||
<dees-icon class="tile-icon" .iconFA=${tile.icon} size="small"></dees-icon>
|
||||
` : ''}
|
||||
</div>
|
||||
|
||||
<div class="tile-content">
|
||||
${this.renderTileContent(tile)}
|
||||
</div>
|
||||
|
||||
${tile.description ? html`
|
||||
<div class="tile-description">${tile.description}</div>
|
||||
` : ''}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private renderTileContent(tile: IStatsTile): TemplateResult {
|
||||
switch (tile.type) {
|
||||
case 'number':
|
||||
return html`
|
||||
<div class="tile-value" style="${tile.color ? `color: ${tile.color}` : ''}">
|
||||
<span>${tile.value}</span>
|
||||
${tile.unit ? html`<span class="tile-unit">${tile.unit}</span>` : ''}
|
||||
</div>
|
||||
`;
|
||||
|
||||
case 'gauge':
|
||||
return this.renderGauge(tile);
|
||||
|
||||
case 'percentage':
|
||||
return this.renderPercentage(tile);
|
||||
|
||||
case 'trend':
|
||||
return this.renderTrend(tile);
|
||||
|
||||
case 'text':
|
||||
return html`
|
||||
<div class="text-value" style="${tile.color ? `color: ${tile.color}` : ''}">
|
||||
${tile.value}
|
||||
</div>
|
||||
`;
|
||||
|
||||
default:
|
||||
return html`<div class="tile-value">${tile.value}</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
private renderGauge(tile: IStatsTile): TemplateResult {
|
||||
const value = typeof tile.value === 'number' ? tile.value : parseFloat(tile.value);
|
||||
const options = tile.gaugeOptions || { min: 0, max: 100 };
|
||||
const percentage = ((value - options.min) / (options.max - options.min)) * 100;
|
||||
const strokeDasharray = 188.5; // Circumference of circle with r=30
|
||||
const strokeDashoffset = strokeDasharray - (strokeDasharray * percentage) / 100;
|
||||
|
||||
let strokeColor = tile.color || cssManager.bdTheme('#0084ff', '#0066cc');
|
||||
if (options.thresholds) {
|
||||
for (const threshold of options.thresholds.reverse()) {
|
||||
if (value >= threshold.value) {
|
||||
strokeColor = threshold.color;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return html`
|
||||
<div class="gauge-container">
|
||||
<svg class="gauge-svg" viewBox="0 0 80 80">
|
||||
<circle
|
||||
class="gauge-background"
|
||||
cx="40"
|
||||
cy="40"
|
||||
r="30"
|
||||
transform="rotate(-90 40 40)"
|
||||
/>
|
||||
<circle
|
||||
class="gauge-fill"
|
||||
cx="40"
|
||||
cy="40"
|
||||
r="30"
|
||||
transform="rotate(-90 40 40)"
|
||||
stroke="${strokeColor}"
|
||||
stroke-dasharray="${strokeDasharray}"
|
||||
stroke-dashoffset="${strokeDashoffset}"
|
||||
/>
|
||||
<text class="gauge-text" x="40" y="40" dy="0.35em">
|
||||
${value}${tile.unit || ''}
|
||||
</text>
|
||||
</svg>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private renderPercentage(tile: IStatsTile): TemplateResult {
|
||||
const value = typeof tile.value === 'number' ? tile.value : parseFloat(tile.value);
|
||||
const percentage = Math.min(100, Math.max(0, value));
|
||||
|
||||
return html`
|
||||
<div class="percentage-container">
|
||||
<div
|
||||
class="percentage-fill"
|
||||
style="width: ${percentage}%; ${tile.color ? `background: ${tile.color}` : ''}"
|
||||
></div>
|
||||
<div class="percentage-text">${percentage}%</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private renderTrend(tile: IStatsTile): TemplateResult {
|
||||
if (!tile.trendData || tile.trendData.length < 2) {
|
||||
return html`<div class="tile-value">${tile.value}</div>`;
|
||||
}
|
||||
|
||||
const data = tile.trendData;
|
||||
const max = Math.max(...data);
|
||||
const min = Math.min(...data);
|
||||
const range = max - min || 1;
|
||||
const width = 200;
|
||||
const height = 40;
|
||||
const points = data.map((value, index) => {
|
||||
const x = (index / (data.length - 1)) * width;
|
||||
const y = height - ((value - min) / range) * height;
|
||||
return `${x},${y}`;
|
||||
}).join(' ');
|
||||
|
||||
const areaPoints = `0,${height} ${points} ${width},${height}`;
|
||||
|
||||
return html`
|
||||
<div class="trend-container">
|
||||
<svg class="trend-svg" viewBox="0 0 ${width} ${height}" preserveAspectRatio="none">
|
||||
<polygon class="trend-area" points="${areaPoints}" />
|
||||
<polyline class="trend-line" points="${points}" />
|
||||
</svg>
|
||||
<div class="trend-value">
|
||||
<span>${tile.value}</span>
|
||||
${tile.unit ? html`<span class="tile-unit">${tile.unit}</span>` : ''}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private async handleGridAction(action: plugins.tsclass.website.IMenuItem) {
|
||||
if (action.action) {
|
||||
await action.action();
|
||||
}
|
||||
}
|
||||
|
||||
private async handleTileAction(action: plugins.tsclass.website.IMenuItem, _tile: IStatsTile) {
|
||||
if (action.action) {
|
||||
await action.action();
|
||||
}
|
||||
// Note: tile data is available through closure when defining actions
|
||||
}
|
||||
|
||||
private showContextMenu(event: MouseEvent, tile: IStatsTile) {
|
||||
if (!tile.actions || tile.actions.length === 0) return;
|
||||
|
||||
event.preventDefault();
|
||||
this.contextMenuPosition = { x: event.clientX, y: event.clientY };
|
||||
this.contextMenuActions = tile.actions;
|
||||
this.contextMenuVisible = true;
|
||||
|
||||
// Close context menu on click outside
|
||||
const closeHandler = () => {
|
||||
this.contextMenuVisible = false;
|
||||
document.removeEventListener('click', closeHandler);
|
||||
};
|
||||
setTimeout(() => {
|
||||
document.addEventListener('click', closeHandler);
|
||||
}, 100);
|
||||
}
|
||||
}
|
@ -102,7 +102,7 @@ export class DeesStepper extends DeesElement {
|
||||
transition: all 0.7s ease-in-out;
|
||||
max-width: 500px;
|
||||
min-height: 300px;
|
||||
border-radius: 8px;
|
||||
border-radius: 16px;
|
||||
background: ${cssManager.bdTheme('#ffffff', '#181818')};
|
||||
border-top: 1px solid ${cssManager.bdTheme('#ffffff', '#181818')};
|
||||
color: ${cssManager.bdTheme('#333', '#fff')};
|
||||
@ -174,9 +174,10 @@ export class DeesStepper extends DeesElement {
|
||||
.step .title {
|
||||
text-align: center;
|
||||
padding-top: 50px;
|
||||
font-family: 'Roboto', 'Inter', sans-serif;
|
||||
font-size: 25px;
|
||||
font-weight: 300;
|
||||
font-family: 'Geist Sans', sans-serif;
|
||||
font-size: 22px;
|
||||
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.step .content {
|
||||
|
@ -12,7 +12,7 @@ import {
|
||||
unsafeCSS,
|
||||
type CSSResult,
|
||||
state,
|
||||
resolveExec,
|
||||
directives,
|
||||
} from '@design.estate/dees-element';
|
||||
|
||||
import { DeesContextmenu } from './dees-contextmenu.js';
|
||||
@ -171,7 +171,7 @@ export class DeesTable<T> extends DeesElement {
|
||||
css`
|
||||
.mainbox {
|
||||
color: ${cssManager.bdTheme('#333', '#fff')};
|
||||
font-family: 'Roboto', 'Inter', sans-serif;
|
||||
font-family: 'Geist Sans', sans-serif;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
padding: 16px;
|
||||
@ -190,7 +190,7 @@ export class DeesTable<T> extends DeesElement {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
font-family: 'Roboto', 'Inter', sans-serif;
|
||||
font-family: 'Geist Sans', sans-serif;
|
||||
}
|
||||
|
||||
.headingContainer {
|
||||
@ -289,7 +289,7 @@ export class DeesTable<T> extends DeesElement {
|
||||
|
||||
th {
|
||||
text-transform: none;
|
||||
font-family: 'Roboto', 'Inter', sans-serif;
|
||||
font-family: 'Geist Sans', sans-serif;
|
||||
font-weight: 500;
|
||||
}
|
||||
th,
|
||||
@ -366,7 +366,7 @@ export class DeesTable<T> extends DeesElement {
|
||||
}
|
||||
|
||||
.footer {
|
||||
font-family: 'Roboto', 'Inter', sans-serif;
|
||||
font-family: 'Geist Sans', sans-serif;
|
||||
font-size: 14px;
|
||||
color: ${cssManager.bdTheme('#111', '#ffffff90')};
|
||||
background: ${cssManager.bdTheme('#eeeeeb', '#00000050')};
|
||||
@ -415,7 +415,7 @@ export class DeesTable<T> extends DeesElement {
|
||||
<div class="heading heading2">${this.heading2}</div>
|
||||
</div>
|
||||
<div class="headerActions">
|
||||
${resolveExec(async () => {
|
||||
${directives.resolveExec(async () => {
|
||||
const resultArray: TemplateResult[] = [];
|
||||
for (const action of this.dataActions) {
|
||||
if (!action.type.includes('header')) continue;
|
||||
@ -634,7 +634,7 @@ export class DeesTable<T> extends DeesElement {
|
||||
selected
|
||||
</div>
|
||||
<div class="footerActions">
|
||||
${resolveExec(async () => {
|
||||
${directives.resolveExec(async () => {
|
||||
const resultArray: TemplateResult[] = [];
|
||||
for (const action of this.dataActions) {
|
||||
if (!action.type.includes('footer')) continue;
|
||||
|
@ -22,13 +22,25 @@ declare global {
|
||||
|
||||
@customElement('dees-terminal')
|
||||
export class DeesTerminal extends DeesElement {
|
||||
public static demo = () => html` <dees-terminal></dees-terminal> `;
|
||||
public static demo = () => html` <dees-terminal
|
||||
.environment=${{
|
||||
NODE_ENV: 'development',
|
||||
PORT: '3000',
|
||||
}}
|
||||
></dees-terminal> `;
|
||||
|
||||
// INSTANCE
|
||||
private resizeObserver: ResizeObserver;
|
||||
|
||||
@property()
|
||||
public setupCommand = `pnpm install @git.zone/tsbuild && clear && echo 'welcome'`;
|
||||
public setupCommand = `pnpm install @serve.zone/cli && servezone cli\n`;
|
||||
|
||||
@property()
|
||||
environment: {[key: string]: string} = {};
|
||||
|
||||
// exposing webcontainer
|
||||
private webcontainerDeferred = new domtools.plugins.smartpromise.Deferred<webcontainer.WebContainer>();
|
||||
public webcontainerPromise = this.webcontainerDeferred.promise;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@ -282,8 +294,15 @@ export class DeesTerminal extends DeesElement {
|
||||
input.write(data);
|
||||
});
|
||||
await this.waitForPrompt(term, '~/');
|
||||
// lets set the environment variables
|
||||
await this.setEnvironmentVariables(this.environment, webcontainerInstance);
|
||||
input.write(`source source.env\n`);
|
||||
await this.waitForPrompt(term, '~/');
|
||||
// lets run the setup command
|
||||
input.write(this.setupCommand);
|
||||
input.write(`\n`);
|
||||
await this.waitForPrompt(term, '~/');
|
||||
input.write(`clear && echo 'welcome'\n`);
|
||||
this.webcontainerDeferred.resolve(webcontainerInstance);
|
||||
}
|
||||
|
||||
async connectedCallback(): Promise<void> {
|
||||
@ -300,14 +319,16 @@ export class DeesTerminal extends DeesElement {
|
||||
this.fitAddon.fit();
|
||||
}
|
||||
|
||||
private async waitForPrompt(term: Terminal, prompt: string): Promise<void> {
|
||||
public async waitForPrompt(term: Terminal, prompt: string): Promise<void> {
|
||||
return new Promise<void>((resolve) => {
|
||||
const checkPrompt = () => {
|
||||
const lines = term.buffer.active;
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines.getLine(i);
|
||||
if (line && line.translateToString().includes(prompt)) {
|
||||
resolve();
|
||||
setTimeout(() => {
|
||||
resolve();
|
||||
}, 100);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -317,4 +338,18 @@ export class DeesTerminal extends DeesElement {
|
||||
checkPrompt();
|
||||
});
|
||||
}
|
||||
|
||||
public async setEnvironmentVariables(envArg: {[key: string]: string}, webcontainerInstanceArg?: webcontainer.WebContainer) {
|
||||
const webcontainerInstance = webcontainerInstanceArg ||await this.webcontainerPromise;
|
||||
let envFile = ``
|
||||
for (const key in envArg) {
|
||||
envFile += `export ${key}="${envArg[key]}"\n`;
|
||||
}
|
||||
|
||||
await webcontainerInstance.mount({'source.env': {
|
||||
file: {
|
||||
contents: envFile,
|
||||
}
|
||||
}});
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ export * from './dees-appui-base.js';
|
||||
export * from './dees-appui-maincontent.js';
|
||||
export * from './dees-appui-mainmenu.js';
|
||||
export * from './dees-appui-mainselector.js';
|
||||
export * from './dees-badge.js';
|
||||
export * from './dees-button-exit.js';
|
||||
export * from './dees-button.js';
|
||||
export * from './dees-chart-area.js';
|
||||
@ -17,6 +18,7 @@ export * from './dees-editor-markdown.js';
|
||||
export * from './dees-editor-markdownoutlet.js';
|
||||
export * from './dees-form-submit.js';
|
||||
export * from './dees-form.js';
|
||||
export * from './dees-heading.js';
|
||||
export * from './dees-hint.js';
|
||||
export * from './dees-icon.js';
|
||||
export * from './dees-input-checkbox.js';
|
||||
@ -34,10 +36,12 @@ export * from './dees-mobilenavigation.js';
|
||||
export * from './dees-modal.js';
|
||||
export * from './dees-input-multitoggle.js';
|
||||
export * from './dees-pdf.js';
|
||||
export * from './dees-searchbar.js';
|
||||
export * from './dees-simple-appdash.js';
|
||||
export * from './dees-simple-login.js';
|
||||
export * from './dees-speechbubble.js';
|
||||
export * from './dees-spinner.js';
|
||||
export * from './dees-statsgrid.js';
|
||||
export * from './dees-stepper.js';
|
||||
export * from './dees-table.js';
|
||||
export * from './dees-terminal.js';
|
||||
@ -45,3 +49,4 @@ export * from './dees-toast.js';
|
||||
export * from './dees-updater.js';
|
||||
export * from './dees-windowcontrols.js';
|
||||
export * from './dees-windowlayer.js';
|
||||
export * from './dees-pagination.js';
|
||||
|
@ -1,2 +1,4 @@
|
||||
export * from './elements/index.js';
|
||||
import * as colors from './elements/00colors.js';
|
||||
export { colors };
|
||||
export { commitinfo } from './00_commitinfo_data.js';
|
||||
|
Reference in New Issue
Block a user