feat(theme,interfaces): Introduce a global theming system and unify menu/tab interfaces; migrate components to use themeDefaultStyles and update APIs accordingly

This commit is contained in:
2025-12-29 01:20:24 +00:00
parent 9175799ec6
commit e38d3cd42a
78 changed files with 1413 additions and 616 deletions

View File

@@ -1,5 +1,15 @@
# Changelog # Changelog
## 2025-12-29 - 3.5.0 - feat(theme,interfaces)
Introduce a global theming system and unify menu/tab interfaces; migrate components to use themeDefaultStyles and update APIs accordingly
- Add a new theme module and component (00theme.ts + dees-theme) that provides CSS tokens and themeDefaultStyles to import into components
- Migrate many components to include themeDefaultStyles in their static styles and add TODOs to replace hardcoded values with CSS variables
- Rename ITab -> IMenuItem and replace group.tabs with group.items across interfaces and components (IMenuGroup shape changed) — this is a breaking API change
- Remove legacy interfaces (ISecondaryMenuGroup, ISelectionOption) and update method and property types in DeesAppui* components and app config to use IMenuItem/IMenuGroup
- Move @design.estate/dees-wcctools from dependencies to devDependencies and bump its version to ^3.3.0
- Add numerous demo files and expand README with usage, examples and theme documentation
## 2025-12-19 - 3.4.0 - feat(dees-appui-base) ## 2025-12-19 - 3.4.0 - feat(dees-appui-base)
overhaul AppUI core: replace simple view rendering with a full-featured ViewRegistry (caching, hide/show lifecycle, async lazy-loading), introduce view lifecycle hooks and activation context, add activity log API/component, remove built-in router and state manager, and update configuration interfaces and demos overhaul AppUI core: replace simple view rendering with a full-featured ViewRegistry (caching, hide/show lifecycle, async lazy-loading), introduce view lifecycle hooks and activation context, add activity log API/component, remove built-in router and state manager, and update configuration interfaces and demos

View File

@@ -18,7 +18,6 @@
"dependencies": { "dependencies": {
"@design.estate/dees-domtools": "^2.3.6", "@design.estate/dees-domtools": "^2.3.6",
"@design.estate/dees-element": "^2.1.3", "@design.estate/dees-element": "^2.1.3",
"@design.estate/dees-wcctools": "^3.1.0",
"@fortawesome/fontawesome-svg-core": "^7.1.0", "@fortawesome/fontawesome-svg-core": "^7.1.0",
"@fortawesome/free-brands-svg-icons": "^7.1.0", "@fortawesome/free-brands-svg-icons": "^7.1.0",
"@fortawesome/free-regular-svg-icons": "^7.1.0", "@fortawesome/free-regular-svg-icons": "^7.1.0",
@@ -45,6 +44,7 @@
"xterm-addon-fit": "^0.8.0" "xterm-addon-fit": "^0.8.0"
}, },
"devDependencies": { "devDependencies": {
"@design.estate/dees-wcctools": "^3.3.0",
"@git.zone/tsbuild": "^4.0.2", "@git.zone/tsbuild": "^4.0.2",
"@git.zone/tsbundle": "^2.6.3", "@git.zone/tsbundle": "^2.6.3",
"@git.zone/tstest": "^3.1.3", "@git.zone/tstest": "^3.1.3",

13
pnpm-lock.yaml generated
View File

@@ -15,8 +15,8 @@ importers:
specifier: ^2.1.3 specifier: ^2.1.3
version: 2.1.3 version: 2.1.3
'@design.estate/dees-wcctools': '@design.estate/dees-wcctools':
specifier: ^3.1.0 specifier: ^3.3.0
version: 3.1.0 version: 3.3.0
'@fortawesome/fontawesome-svg-core': '@fortawesome/fontawesome-svg-core':
specifier: ^7.1.0 specifier: ^7.1.0
version: 7.1.0 version: 7.1.0
@@ -350,8 +350,8 @@ packages:
'@design.estate/dees-wcctools@1.3.0': '@design.estate/dees-wcctools@1.3.0':
resolution: {integrity: sha512-+yd8c1gTIKNRQYCvG0xu6Am8dHsRm7ymluX2gnoBQN4aFOpZgIBi/v9CvGyPhTD1p/VRouIBz1wsUCejnwrFCA==} resolution: {integrity: sha512-+yd8c1gTIKNRQYCvG0xu6Am8dHsRm7ymluX2gnoBQN4aFOpZgIBi/v9CvGyPhTD1p/VRouIBz1wsUCejnwrFCA==}
'@design.estate/dees-wcctools@3.1.0': '@design.estate/dees-wcctools@3.3.0':
resolution: {integrity: sha512-EZsgvZZ736PORt8FkHvzKzsmsHDkYOngcWfL1eBEutT3HBQq4PW5X6PVWSHXFzbhI6rt3O07GJHEIa+xU2mSkQ==} resolution: {integrity: sha512-ZOxG5LkbLLsqDQWO+JCOjFkL77l9FuLDa7LBuZRkTSX0jRoYG6ICI1UoI9i6twxm4JKSzQ4iHjL/F5mHbQiKTg==}
'@emnapi/core@1.7.1': '@emnapi/core@1.7.1':
resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==} resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==}
@@ -5409,7 +5409,7 @@ snapshots:
- supports-color - supports-color
- vue - vue
'@design.estate/dees-wcctools@3.1.0': '@design.estate/dees-wcctools@3.3.0':
dependencies: dependencies:
'@design.estate/dees-domtools': 2.3.6 '@design.estate/dees-domtools': 2.3.6
'@design.estate/dees-element': 2.1.3 '@design.estate/dees-element': 2.1.3
@@ -6805,20 +6805,17 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- '@aws-sdk/credential-providers' - '@aws-sdk/credential-providers'
- '@mongodb-js/zstd' - '@mongodb-js/zstd'
- '@nuxt/kit'
- aws-crt - aws-crt
- bare-abort-controller - bare-abort-controller
- bufferutil - bufferutil
- gcp-metadata - gcp-metadata
- kerberos - kerberos
- mongodb-client-encryption - mongodb-client-encryption
- react
- react-native-b4a - react-native-b4a
- snappy - snappy
- socks - socks
- supports-color - supports-color
- utf-8-validate - utf-8-validate
- vue
'@push.rocks/taskbuffer@3.5.0': '@push.rocks/taskbuffer@3.5.0':
dependencies: dependencies:

588
readme.md
View File

@@ -1,32 +1,71 @@
# @design.estate/dees-catalog # @design.estate/dees-catalog
A comprehensive web components library built with TypeScript and LitElement, providing 75+ UI components for building modern web applications with consistent design and behavior.
## Development Guide A comprehensive web components library built with TypeScript and LitElement, providing **75+ UI components** for building modern web applications with consistent design and behavior. 🚀
For developers working on this library, please refer to the [UI Components Playbook](readme.playbook.md) for comprehensive patterns, best practices, and architectural guidelines.
## Install [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/)
To install the `@design.estate/dees-catalog` library, you can use npm or any other compatible JavaScript package manager: [![LitElement](https://img.shields.io/badge/LitElement-4.0+-orange.svg)](https://lit.dev/)
## Issue Reporting and Security
For reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly.
## ✨ Features
- 🎨 **Consistent Design System** - Beautiful, cohesive components following modern UI/UX principles
- 🌙 **Dark/Light Theme Support** - All components automatically adapt to your theme
- ⌨️ **Keyboard Accessible** - Full keyboard navigation and ARIA support
- 📱 **Responsive** - Mobile-first design that works across all screen sizes
- 🔧 **TypeScript-First** - Fully typed APIs with excellent IDE support
- 🧩 **Modular** - Use only what you need, tree-shakeable architecture
## 📦 Installation
```bash ```bash
npm install @design.estate/dees-catalog npm install @design.estate/dees-catalog
# or
pnpm add @design.estate/dees-catalog
``` ```
## Components Overview ## 🚀 Quick Start
```typescript
import { html, DeesElement, customElement } from '@design.estate/dees-element';
import '@design.estate/dees-catalog';
@customElement('my-app')
class MyApp extends DeesElement {
render() {
return html`
<dees-button type="highlighted" @click=${() => alert('Hello!')}>
Click me!
</dees-button>
`;
}
}
```
## 📖 Development Guide
For developers working on this library, please refer to the [UI Components Playbook](readme.playbook.md) for comprehensive patterns, best practices, and architectural guidelines.
## 📚 Components Overview
| Category | Components | | Category | Components |
|----------|------------| |----------|------------|
| Core UI | [`DeesButton`](#deesbutton), [`DeesButtonExit`](#deesbuttonexit), [`DeesButtonGroup`](#deesbuttongroup), [`DeesBadge`](#deesbadge), [`DeesChips`](#deeschips), [`DeesHeading`](#deesheading), [`DeesHint`](#deeshint), [`DeesIcon`](#deesicon), [`DeesLabel`](#deeslabel), [`DeesPanel`](#deespanel), [`DeesSearchbar`](#deessearchbar), [`DeesSpinner`](#deesspinner), [`DeesToast`](#deestoast), [`DeesWindowcontrols`](#deeswindowcontrols) | | **Core UI** | [`DeesButton`](#deesbutton), [`DeesButtonExit`](#deesbuttonexit), [`DeesButtonGroup`](#deesbuttongroup), [`DeesBadge`](#deesbadge), [`DeesChips`](#deeschips), [`DeesHeading`](#deesheading), [`DeesHint`](#deeshint), [`DeesIcon`](#deesicon), [`DeesLabel`](#deeslabel), [`DeesPanel`](#deespanel), [`DeesSearchbar`](#deessearchbar), [`DeesSpinner`](#deesspinner), [`DeesToast`](#deestoast), [`DeesWindowcontrols`](#deeswindowcontrols) |
| Forms | [`DeesForm`](#deesform), [`DeesInputText`](#deesinputtext), [`DeesInputCheckbox`](#deesinputcheckbox), [`DeesInputDropdown`](#deesinputdropdown), [`DeesInputRadiogroup`](#deesinputradiogroup), [`DeesInputFileupload`](#deesinputfileupload), [`DeesInputIban`](#deesinputiban), [`DeesInputPhone`](#deesinputphone), [`DeesInputQuantitySelector`](#deesinputquantityselector), [`DeesInputMultitoggle`](#deesinputmultitoggle), [`DeesInputTags`](#deesinputtags), [`DeesInputTypelist`](#deesinputtypelist), [`DeesInputRichtext`](#deesinputrichtext), [`DeesInputWysiwyg`](#deesinputwysiwyg), [`DeesInputDatepicker`](#deesinputdatepicker), [`DeesInputSearchselect`](#deesinputsearchselect), [`DeesFormSubmit`](#deesformsubmit) | | **Forms** | [`DeesForm`](#deesform), [`DeesInputText`](#deesinputtext), [`DeesInputCheckbox`](#deesinputcheckbox), [`DeesInputDropdown`](#deesinputdropdown), [`DeesInputRadiogroup`](#deesinputradiogroup), [`DeesInputFileupload`](#deesinputfileupload), [`DeesInputIban`](#deesinputiban), [`DeesInputPhone`](#deesinputphone), [`DeesInputQuantitySelector`](#deesinputquantityselector), [`DeesInputMultitoggle`](#deesinputmultitoggle), [`DeesInputTags`](#deesinputtags), [`DeesInputTypelist`](#deesinputtypelist), [`DeesInputRichtext`](#deesinputrichtext), [`DeesInputWysiwyg`](#deesinputwysiwyg), [`DeesInputDatepicker`](#deesinputdatepicker), [`DeesInputSearchselect`](#deesinputsearchselect), [`DeesFormSubmit`](#deesformsubmit) |
| Layout | [`DeesAppuiBase`](#deesappuibase), [`DeesAppuiMainmenu`](#deesappuimainmenu), [`DeesAppuiMainselector`](#deesappuimainselector), [`DeesAppuiMaincontent`](#deesappuimaincontent), [`DeesAppuiAppbar`](#deesappuiappbar), [`DeesAppuiActivitylog`](#deesappuiactivitylog), [`DeesAppuiProfiledropdown`](#deesappuiprofiledropdown), [`DeesAppuiTabs`](#deesappuitabs), [`DeesAppuiView`](#deesappuiview), [`DeesMobileNavigation`](#deesmobilenavigation), [`DeesDashboardGrid`](#deesdashboardgrid) | | **Layout** | [`DeesAppuiBase`](#deesappuibase), [`DeesAppuiMainmenu`](#deesappuimainmenu), [`DeesAppuiSecondarymenu`](#deesappuisecondarymenu), [`DeesAppuiMaincontent`](#deesappuimaincontent), [`DeesAppuiAppbar`](#deesappuiappbar), [`DeesAppuiActivitylog`](#deesappuiactivitylog), [`DeesAppuiProfiledropdown`](#deesappuiprofiledropdown), [`DeesAppuiTabs`](#deesappuitabs), [`DeesAppuiView`](#deesappuiview), [`DeesMobileNavigation`](#deesmobilenavigation), [`DeesDashboardGrid`](#deesdashboardgrid) |
| Data Display | [`DeesTable`](#deestable), [`DeesDataviewCodebox`](#deesdataviewcodebox), [`DeesDataviewStatusobject`](#deesdataviewstatusobject), [`DeesPdf`](#deespdf), [`DeesStatsGrid`](#deesstatsgrid), [`DeesPagination`](#deespagination) | | **Data Display** | [`DeesTable`](#deestable), [`DeesDataviewCodebox`](#deesdataviewcodebox), [`DeesDataviewStatusobject`](#deesdataviewstatusobject), [`DeesPdf`](#deespdf), [`DeesStatsGrid`](#deesstatsgrid), [`DeesPagination`](#deespagination) |
| Visualization | [`DeesChartArea`](#deeschartarea), [`DeesChartLog`](#deeschartlog) | | **Visualization** | [`DeesChartArea`](#deeschartarea), [`DeesChartLog`](#deeschartlog) |
| Dialogs & Overlays | [`DeesModal`](#deesmodal), [`DeesContextmenu`](#deescontextmenu), [`DeesSpeechbubble`](#deesspeechbubble), [`DeesWindowlayer`](#deeswindowlayer) | | **Dialogs & Overlays** | [`DeesModal`](#deesmodal), [`DeesContextmenu`](#deescontextmenu), [`DeesSpeechbubble`](#deesspeechbubble), [`DeesWindowlayer`](#deeswindowlayer) |
| Navigation | [`DeesStepper`](#deesstepper), [`DeesProgressbar`](#deesprogressbar) | | **Navigation** | [`DeesStepper`](#deesstepper), [`DeesProgressbar`](#deesprogressbar) |
| Development | [`DeesEditor`](#deeseditor), [`DeesEditorMarkdown`](#deeseditormarkdown), [`DeesEditorMarkdownoutlet`](#deeseditormarkdownoutlet), [`DeesTerminal`](#deesterminal), [`DeesUpdater`](#deesupdater) | | **Development** | [`DeesEditor`](#deeseditor), [`DeesEditorMarkdown`](#deeseditormarkdown), [`DeesEditorMarkdownoutlet`](#deeseditormarkdownoutlet), [`DeesTerminal`](#deesterminal), [`DeesUpdater`](#deesupdater) |
| Auth & Utilities | [`DeesSimpleAppdash`](#deessimpleappdash), [`DeesSimpleLogin`](#deessimplelogin) | | **Auth & Utilities** | [`DeesSimpleAppdash`](#deessimpleappdash), [`DeesSimpleLogin`](#deessimplelogin) |
| Shopping | [`DeesShoppingProductcard`](#deesshoppingproductcard) | | **Shopping** | [`DeesShoppingProductcard`](#deesshoppingproductcard) |
## Detailed Component Documentation ---
## 🎯 Detailed Component Documentation
### Core UI Components ### Core UI Components
@@ -84,7 +123,7 @@ Display icons from FontAwesome and Lucide icon libraries with library prefixes.
color="#22c55e" // Optional: custom color color="#22c55e" // Optional: custom color
></dees-icon> ></dees-icon>
// Lucide icons - use 'lucide:' prefix // Lucide icons - use 'lucide:' prefix
<dees-icon <dees-icon
icon="lucide:menu" // Lucide icon with lucide: prefix icon="lucide:menu" // Lucide icon with lucide: prefix
iconSize="24" // Size in pixels iconSize="24" // Size in pixels
@@ -148,16 +187,9 @@ const toast = await DeesToast.show({
// Later dismiss programmatically // Later dismiss programmatically
toast.dismiss(); toast.dismiss();
// Component usage (not typically used directly)
<dees-toast
message="Changes saved"
type="success"
duration="3000"
></dees-toast>
``` ```
Key Features: **Key Features:**
- Multiple toast types with distinct icons and colors - Multiple toast types with distinct icons and colors
- 6 position options for flexible placement - 6 position options for flexible placement
- Auto-dismiss with visual progress indicator - Auto-dismiss with visual progress indicator
@@ -254,6 +286,8 @@ Window control buttons (minimize, maximize, close) for desktop-like applications
></dees-windowcontrols> ></dees-windowcontrols>
``` ```
---
### Form Components ### Form Components
#### `DeesForm` #### `DeesForm`
@@ -427,7 +461,7 @@ Tag input component for managing lists of tags with auto-complete and validation
></dees-input-tags> ></dees-input-tags>
``` ```
Key Features: **Key Features:**
- Add tags by pressing Enter or typing comma/semicolon - Add tags by pressing Enter or typing comma/semicolon
- Remove tags with click or backspace - Remove tags with click or backspace
- Auto-complete suggestions with keyboard navigation - Auto-complete suggestions with keyboard navigation
@@ -464,7 +498,7 @@ Date and time picker component with calendar interface and manual typing support
minDate="2025-01-01" // Minimum selectable date minDate="2025-01-01" // Minimum selectable date
maxDate="2025-12-31" // Maximum selectable date maxDate="2025-12-31" // Maximum selectable date
.disabledDates=${[ // Array of disabled dates .disabledDates=${[ // Array of disabled dates
'2025-01-10', '2025-01-10',
'2025-01-11' '2025-01-11'
]} ]}
weekStartsOn={1} // 0 = Sunday, 1 = Monday weekStartsOn={1} // 0 = Sunday, 1 = Monday
@@ -473,7 +507,7 @@ Date and time picker component with calendar interface and manual typing support
></dees-input-datepicker> ></dees-input-datepicker>
``` ```
Key Features: **Key Features:**
- Interactive calendar popup - Interactive calendar popup
- Manual date typing with multiple formats - Manual date typing with multiple formats
- Optional time selection - Optional time selection
@@ -487,7 +521,7 @@ Key Features:
- Theme-aware styling - Theme-aware styling
- Live parsing and validation - Live parsing and validation
Manual Input Formats: **Manual Input Formats:**
```typescript ```typescript
// Date formats supported // Date formats supported
"2023-12-20" // ISO format (YYYY-MM-DD) "2023-12-20" // ISO format (YYYY-MM-DD)
@@ -500,8 +534,6 @@ Manual Input Formats:
"12/20/2023 16:00" "12/20/2023 16:00"
``` ```
The component automatically parses and validates input as you type, updating the internal date value when a valid date is recognized.
#### `DeesInputSearchselect` #### `DeesInputSearchselect`
Search-enabled dropdown selection component. Search-enabled dropdown selection component.
@@ -535,7 +567,7 @@ Rich text editor with formatting toolbar powered by TipTap.
></dees-input-richtext> ></dees-input-richtext>
``` ```
Key Features: **Key Features:**
- Full formatting toolbar (bold, italic, underline, strike, etc.) - Full formatting toolbar (bold, italic, underline, strike, etc.)
- Heading levels (H1-H6) - Heading levels (H1-H6)
- Lists (bullet, ordered) - Lists (bullet, ordered)
@@ -560,7 +592,7 @@ Advanced block-based editor with slash commands and rich content blocks.
></dees-input-wysiwyg> ></dees-input-wysiwyg>
``` ```
Key Features: **Key Features:**
- Slash commands for quick formatting - Slash commands for quick formatting
- Block-based editing (paragraphs, headings, lists, etc.) - Block-based editing (paragraphs, headings, lists, etc.)
- Drag and drop block reordering - Drag and drop block reordering
@@ -579,6 +611,8 @@ Submit button component specifically designed for `DeesForm`.
>Submit Form</dees-form-submit> >Submit Form</dees-form-submit>
``` ```
---
### Layout Components ### Layout Components
#### `DeesAppuiBase` #### `DeesAppuiBase`
@@ -640,41 +674,37 @@ Main navigation menu component for application-wide navigation.
```typescript ```typescript
<dees-appui-mainmenu <dees-appui-mainmenu
.menuItems=${[ .menuGroups=${[
{ {
key: 'dashboard', name: 'Main',
label: 'Dashboard', items: [
icon: 'home', { key: 'dashboard', iconName: 'lucide:home', action: () => navigate('dashboard') },
action: () => handleNavigation('dashboard') { key: 'settings', iconName: 'lucide:settings', action: () => navigate('settings') }
}, ]
{
key: 'settings',
label: 'Settings',
icon: 'cog',
action: () => handleNavigation('settings')
} }
]} ]}
collapsed // Optional: show collapsed version collapsed // Optional: show collapsed version
position="left" // Options: left, right
></dees-appui-mainmenu> ></dees-appui-mainmenu>
``` ```
#### `DeesAppuiMainselector` #### `DeesAppuiSecondarymenu`
Secondary navigation component for sub-section selection. Secondary navigation component for sub-section selection with collapsible groups and badges.
```typescript ```typescript
<dees-appui-mainselector <dees-appui-secondarymenu
.items=${[ .heading=${'Projects'}
.groups=${[
{ {
key: 'section1', name: 'Active',
label: 'Section 1', iconName: 'lucide:folder',
icon: 'folder', items: [
action: () => selectSection('section1') { key: 'Frontend App', iconName: 'lucide:code', action: () => select('frontend'), badge: 3, badgeVariant: 'warning' },
{ key: 'API Server', iconName: 'lucide:server', action: () => select('api') }
]
} }
]} ]}
selectedKey="section1" // Currently selected section @item-select=${handleSectionChange}
@selection-change=${handleSectionChange} ></dees-appui-secondarymenu>
></dees-appui-mainselector>
``` ```
#### `DeesAppuiMaincontent` #### `DeesAppuiMaincontent`
@@ -683,16 +713,13 @@ Main content area with tab management support.
```typescript ```typescript
<dees-appui-maincontent <dees-appui-maincontent
.tabs=${[ .tabs=${[
{ { key: 'Overview', iconName: 'lucide:home', action: () => selectTab('overview') },
key: 'tab1', { key: 'Details', iconName: 'lucide:info', action: () => selectTab('details') }
label: 'Tab 1',
content: html`<div>Tab 1 Content</div>`,
action: () => handleTabAction('tab1')
}
]} ]}
selectedTab="tab1" // Currently active tab @tab-select=${handleTabChange}
@tab-change=${handleTabChange} >
></dees-appui-maincontent> <!-- Content goes here -->
</dees-appui-maincontent>
``` ```
#### `DeesAppuiAppbar` #### `DeesAppuiAppbar`
@@ -705,91 +732,82 @@ Professional application bar component with hierarchical menus, breadcrumb navig
name: 'File', name: 'File',
action: async () => {}, // No-op for parent menu items action: async () => {}, // No-op for parent menu items
submenu: [ submenu: [
{ {
name: 'New File', name: 'New File',
shortcut: 'Cmd+N', shortcut: 'Cmd+N',
iconName: 'file-plus', iconName: 'file-plus',
action: async () => handleNewFile() action: async () => handleNewFile()
}, },
{ {
name: 'Open...', name: 'Open...',
shortcut: 'Cmd+O', shortcut: 'Cmd+O',
iconName: 'folder-open', iconName: 'folder-open',
action: async () => handleOpen() action: async () => handleOpen()
}, },
{ divider: true }, // Menu separator { divider: true }, // Menu separator
{ {
name: 'Save', name: 'Save',
shortcut: 'Cmd+S', shortcut: 'Cmd+S',
iconName: 'save', iconName: 'save',
action: async () => handleSave(), action: async () => handleSave(),
disabled: true // Disabled state disabled: true // Disabled state
} }
] ]
},
{
name: 'Edit',
action: async () => {},
submenu: [
{ name: 'Undo', shortcut: 'Cmd+Z', iconName: 'undo', action: async () => handleUndo() },
{ name: 'Redo', shortcut: 'Cmd+Shift+Z', iconName: 'redo', action: async () => handleRedo() }
]
} }
]} ]}
.breadcrumbs=${'Project > src > components > AppBar.ts'} .breadcrumbs=${'Project > src > components'}
.breadcrumbSeparator=${' > '}
.showWindowControls=${true} .showWindowControls=${true}
.showSearch=${true} .showSearch=${true}
.theme=${'dark'} // Options: 'light' | 'dark'
.user=${{ .user=${{
name: 'John Doe', name: 'John Doe',
avatar: '/path/to/avatar.jpg', // Optional avatar: '/path/to/avatar.jpg',
status: 'online' // Options: 'online' | 'offline' | 'busy' | 'away' status: 'online' // Options: 'online' | 'offline' | 'busy' | 'away'
}} }}
@menu-select=${(e) => handleMenuSelect(e.detail.item)} @menu-select=${(e) => handleMenuSelect(e.detail.item)}
@breadcrumb-navigate=${(e) => handleBreadcrumbClick(e.detail)} @breadcrumb-navigate=${(e) => handleBreadcrumbClick(e.detail)}
@search-click=${() => handleSearchClick()}
@user-menu-open=${() => handleUserMenuOpen()}
></dees-appui-appbar> ></dees-appui-appbar>
``` ```
Key Features: **Key Features:**
- **Hierarchical Menu System** - **Hierarchical Menu System** - Top-level menus with dropdown submenus, icons, and keyboard shortcuts
- Top-level text-only menus (following desktop UI standards) - **Keyboard Navigation** - Full keyboard support (Tab, Arrow keys, Enter, Escape)
- Dropdown submenus with icons and keyboard shortcuts - **Breadcrumb Navigation** - Customizable breadcrumb trail with click events
- Support for nested submenus - **User Account Section** - Avatar with status indicator
- Menu dividers for visual grouping - **Accessibility** - Full ARIA support with menubar roles
- Disabled state support
#### `DeesAppuiView`
- **Keyboard Navigation** View wrapper component for single-view layouts with internal tabs.
- Tab navigation between top-level items
- Arrow keys for dropdown navigation (Up/Down in dropdowns, Left/Right between top items) ```typescript
- Enter to select items <dees-appui-view
- Escape to close dropdowns .viewConfig=${{
- Home/End keys for first/last item id: 'settings',
name: 'Settings',
- **Breadcrumb Navigation** tabs: [
- Customizable breadcrumb trail { key: 'General', iconName: 'lucide:settings', action: () => {}, content: html`<div>General settings</div>` },
- Configurable separator { key: 'Security', iconName: 'lucide:shield', action: () => {}, content: html`<div>Security settings</div>` }
- Click events for navigation ]
}}
- **User Account Section** .paddingPx=${16} // Default padding for tab content
- User avatar with fallback to initials ></dees-appui-view>
- Status indicator (online, offline, busy, away) ```
- Click handler for user menu
#### `DeesAppuiTabs`
- **Visual Features** Reusable tab component with horizontal/vertical layout support.
- Light and dark theme support
- Smooth animations and transitions ```typescript
- Window controls integration <dees-appui-tabs
- Search icon with click handler .tabs=${[
- Responsive layout using CSS Grid { key: 'Home', iconName: 'lucide:home', action: () => console.log('Home') },
{ key: 'Settings', iconName: 'lucide:settings', action: () => console.log('Settings') }
- **Accessibility** ]}
- Full ARIA support (menubar, menuitem roles) tabStyle="horizontal" // Options: horizontal, vertical
- Keyboard navigation showTabIndicator={true}
- Focus management @tab-select=${handleTabSelect}
- Screen reader compatible ></dees-appui-tabs>
```
---
### Data Display Components ### Data Display Components
@@ -825,9 +843,7 @@ Advanced table component with sorting, filtering, and action support.
></dees-table> ></dees-table>
``` ```
##### DeesTable (Updated) **Advanced Features:**
Newer features available in `dees-table`:
- Schema-first columns or `displayFunction` rendering - Schema-first columns or `displayFunction` rendering
- Sorting via header clicks with `aria-sort` + `sortChange` - Sorting via header clicks with `aria-sort` + `sortChange`
- Global search with Lucene-like syntax; modes: `table`, `data`, `server` - Global search with Lucene-like syntax; modes: `table`, `data`, `server`
@@ -846,9 +862,9 @@ Code display component with syntax highlighting and line numbers.
progLang="typescript" // Programming language for syntax highlighting progLang="typescript" // Programming language for syntax highlighting
.codeToDisplay=${` .codeToDisplay=${`
import { html } from '@design.estate/dees-element'; import { html } from '@design.estate/dees-element';
export const myComponent = () => { export const myComponent = () => {
return html`<div>Hello World</div>`; return html\`<div>Hello World</div>\`;
}; };
`} `}
></dees-dataview-codebox> ></dees-dataview-codebox>
@@ -865,18 +881,8 @@ Status display component for complex objects with nested status indicators.
combinedStatus: 'partly_ok', combinedStatus: 'partly_ok',
combinedStatusText: 'Partially OK', combinedStatusText: 'Partially OK',
details: [ details: [
{ { name: 'Database', value: 'Connected', status: 'ok', statusText: 'OK' },
name: 'Database', { name: 'API Service', value: 'Degraded', status: 'partly_ok', statusText: 'Partially OK' }
value: 'Connected',
status: 'ok',
statusText: 'OK'
},
{
name: 'API Service',
value: 'Degraded',
status: 'partly_ok',
statusText: 'Partially OK'
}
] ]
}} }}
></dees-dataview-statusobject> ></dees-dataview-statusobject>
@@ -890,19 +896,13 @@ PDF viewer component with navigation and zoom controls.
source="path/to/document.pdf" // URL or base64 encoded PDF source="path/to/document.pdf" // URL or base64 encoded PDF
page={1} // Current page number page={1} // Current page number
scale={1.0} // Zoom level scale={1.0} // Zoom level
.controls=${[ // Optional: customize available controls .controls=${['zoom', 'download', 'print', 'navigation']}
'zoom',
'download',
'print',
'navigation'
]}
@page-change=${handlePageChange} @page-change=${handlePageChange}
@document-loaded=${handleDocumentLoaded}
></dees-pdf> ></dees-pdf>
``` ```
#### `DeesStatsGrid` #### `DeesStatsGrid`
A responsive grid component for displaying statistical data with various visualization types including numbers, gauges, percentages, and trends. A responsive grid component for displaying statistical data with various visualization types.
```typescript ```typescript
<dees-statsgrid <dees-statsgrid
@@ -915,23 +915,7 @@ A responsive grid component for displaying statistical data with various visuali
type: 'number', type: 'number',
icon: 'faDollarSign', icon: 'faDollarSign',
description: '+12.5% from last month', description: '+12.5% from last month',
color: '#22c55e', color: '#22c55e'
actions: [
{
name: 'View Details',
iconName: 'faChartLine',
action: async () => {
console.log('Viewing revenue details');
}
},
{
name: 'Export Data',
iconName: 'faFileExport',
action: async () => {
console.log('Exporting revenue data');
}
}
]
}, },
{ {
id: 'cpu', id: 'cpu',
@@ -940,8 +924,7 @@ A responsive grid component for displaying statistical data with various visuali
type: 'gauge', type: 'gauge',
icon: 'faMicrochip', icon: 'faMicrochip',
gaugeOptions: { gaugeOptions: {
min: 0, min: 0, max: 100,
max: 100,
thresholds: [ thresholds: [
{ value: 0, color: '#22c55e' }, { value: 0, color: '#22c55e' },
{ value: 60, color: '#f59e0b' }, { value: 60, color: '#f59e0b' },
@@ -949,15 +932,6 @@ A responsive grid component for displaying statistical data with various visuali
] ]
} }
}, },
{
id: 'storage',
title: 'Storage Used',
value: 65,
type: 'percentage',
icon: 'faHardDrive',
description: '650 GB of 1 TB',
color: '#3b82f6'
},
{ {
id: 'requests', id: 'requests',
title: 'API Requests', title: 'API Requests',
@@ -966,35 +940,10 @@ A responsive grid component for displaying statistical data with various visuali
type: 'trend', type: 'trend',
icon: 'faServer', icon: 'faServer',
trendData: [45, 52, 38, 65, 72, 68, 75, 82, 79, 85, 88, 92] 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'
} }
]} ]}
.gridActions=${[ .minTileWidth=${250}
{ .gap=${16}
name: 'Refresh',
iconName: 'faSync',
action: async () => {
console.log('Refreshing stats...');
}
},
{
name: 'Export Report',
iconName: 'faFileExport',
action: async () => {
console.log('Exporting stats report...');
}
}
]}
.minTileWidth=${250} // Minimum tile width in pixels
.gap=${16} // Gap between tiles in pixels
></dees-statsgrid> ></dees-statsgrid>
``` ```
@@ -1006,11 +955,13 @@ Pagination component for navigating through large datasets.
totalItems={500} totalItems={500}
itemsPerPage={20} itemsPerPage={20}
currentPage={1} currentPage={1}
maxVisiblePages={7} // Maximum page numbers to display maxVisiblePages={7}
@page-change=${handlePageChange} @page-change=${handlePageChange}
></dees-pagination> ></dees-pagination>
``` ```
---
### Visualization Components ### Visualization Components
#### `DeesChartArea` #### `DeesChartArea`
@@ -1018,7 +969,7 @@ Area chart component built on ApexCharts for visualizing time-series data.
```typescript ```typescript
<dees-chart-area <dees-chart-area
label="System Usage" // Chart title label="System Usage"
.series=${[ .series=${[
{ {
name: 'CPU', name: 'CPU',
@@ -1027,14 +978,6 @@ Area chart component built on ApexCharts for visualizing time-series data.
{ x: '2025-01-15T07:00:00', y: 30 }, { x: '2025-01-15T07:00:00', y: 30 },
{ x: '2025-01-15T11:00:00', y: 20 } { x: '2025-01-15T11:00:00', y: 20 }
] ]
},
{
name: 'Memory',
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 }
]
} }
]} ]}
></dees-chart-area> ></dees-chart-area>
@@ -1047,22 +990,16 @@ Specialized chart component for visualizing log data and events.
<dees-chart-log <dees-chart-log
label="System Events" label="System Events"
.data=${[ .data=${[
{ { timestamp: '2025-01-15T03:00:00', event: 'Server Start', type: 'info' },
timestamp: '2025-01-15T03:00:00', { timestamp: '2025-01-15T03:15:00', event: 'Error Detected', type: 'error' }
event: 'Server Start',
type: 'info'
},
{
timestamp: '2025-01-15T03:15:00',
event: 'Error Detected',
type: 'error'
}
]} ]}
.filters=${['info', 'warning', 'error']} // Event types to display .filters=${['info', 'warning', 'error']}
@event-click=${handleEventClick} @event-click=${handleEventClick}
></dees-chart-log> ></dees-chart-log>
``` ```
---
### Dialogs & Overlays Components ### Dialogs & Overlays Components
#### `DeesModal` #### `DeesModal`
@@ -1074,36 +1011,14 @@ DeesModal.createAndShow({
heading: 'Confirm Action', heading: 'Confirm Action',
content: html` content: html`
<dees-form> <dees-form>
<dees-input-text <dees-input-text .label=${'Enter reason'}></dees-input-text>
.label=${'Enter reason'}
></dees-input-text>
</dees-form> </dees-form>
`, `,
menuOptions: [ menuOptions: [
{ { name: 'Cancel', action: async (modal) => { modal.destroy(); return null; } },
name: 'Cancel', { name: 'Confirm', action: async (modal) => { /* handle */ modal.destroy(); return null; } }
action: async (modal) => {
modal.destroy();
return null;
}
},
{
name: 'Confirm',
action: async (modal) => {
// Handle confirmation
modal.destroy();
return null;
}
}
] ]
}); });
// Component usage
<dees-modal
heading="Settings"
.content=${settingsContent}
.menuOptions=${actions}
></dees-modal>
``` ```
#### `DeesContextmenu` #### `DeesContextmenu`
@@ -1112,19 +1027,10 @@ Context menu component for right-click actions.
```typescript ```typescript
<dees-contextmenu <dees-contextmenu
.items=${[ .items=${[
{ { label: 'Edit', icon: 'edit', action: () => handleEdit() },
label: 'Edit', { label: 'Delete', icon: 'trash', action: () => handleDelete() }
icon: 'edit',
action: () => handleEdit()
},
{
label: 'Delete',
icon: 'trash',
action: () => handleDelete()
}
]} ]}
position="right" // Options: right, left, auto position="right"
@item-click=${handleMenuItemClick}
></dees-contextmenu> ></dees-contextmenu>
``` ```
@@ -1134,39 +1040,22 @@ Tooltip-style speech bubble component for contextual information.
```typescript ```typescript
// Programmatic usage // Programmatic usage
const bubble = await DeesSpeechbubble.createAndShow( const bubble = await DeesSpeechbubble.createAndShow(
referenceElement, // Element to attach to referenceElement,
'Helpful information about this feature' 'Helpful information about this feature'
); );
// Component usage
<dees-speechbubble
.reffedElement=${targetElement}
text="Click here to continue"
></dees-speechbubble>
``` ```
#### `DeesWindowlayer` #### `DeesWindowlayer`
Base overlay component used by modal dialogs and other overlay components. Base overlay component used by modal dialogs and other overlay components.
```typescript ```typescript
// Programmatic usage
const layer = await DeesWindowLayer.createAndShow({ const layer = await DeesWindowLayer.createAndShow({
blur: true, // Enable backdrop blur blur: true,
}); });
// Component usage
<dees-windowlayer
.options=${{
blur: true
}}
@clicked=${handleOverlayClick}
>
<div class="content">
<!-- Overlay content -->
</div>
</dees-windowlayer>
``` ```
---
### Navigation Components ### Navigation Components
#### `DeesStepper` #### `DeesStepper`
@@ -1175,23 +1064,9 @@ Multi-step navigation component for guided user flows.
```typescript ```typescript
<dees-stepper <dees-stepper
.steps=${[ .steps=${[
{ { key: 'personal', label: 'Personal Info', content: html`<div>Form 1</div>` },
key: 'personal', { key: 'address', label: 'Address', content: html`<div>Form 2</div>` },
label: 'Personal Info', { key: 'confirm', label: 'Confirmation', content: html`<div>Review</div>` }
content: html`<div>Personal Information Form</div>`,
validation: () => validatePersonalInfo()
},
{
key: 'address',
label: 'Address',
content: html`<div>Address Form</div>`,
validation: () => validateAddress()
},
{
key: 'confirm',
label: 'Confirmation',
content: html`<div>Review and Confirm</div>`
}
]} ]}
currentStep="personal" currentStep="personal"
@step-change=${handleStepChange} @step-change=${handleStepChange}
@@ -1204,15 +1079,16 @@ Progress indicator component for tracking completion status.
```typescript ```typescript
<dees-progressbar <dees-progressbar
value={75} // Current progress (0-100) value={75}
label="Uploading" // Optional label label="Uploading"
showPercentage // Display percentage showPercentage
type="determinate" // Options: determinate, indeterminate type="determinate" // Options: determinate, indeterminate
status="normal" // Options: normal, success, warning, error status="normal" // Options: normal, success, warning, error
@progress=${handleProgress}
></dees-progressbar> ></dees-progressbar>
``` ```
---
### Development Components ### Development Components
#### `DeesEditor` #### `DeesEditor`
@@ -1239,12 +1115,7 @@ Markdown editor component with live preview.
<dees-editor-markdown <dees-editor-markdown
.value=${markdown} .value=${markdown}
@change=${handleMarkdownChange} @change=${handleMarkdownChange}
.options=${{ .options=${{ preview: true, toolbar: true, spellcheck: true }}
preview: true,
toolbar: true,
spellcheck: true,
autosave: true
}}
></dees-editor-markdown> ></dees-editor-markdown>
``` ```
@@ -1254,9 +1125,8 @@ Markdown preview component for rendering markdown content.
```typescript ```typescript
<dees-editor-markdownoutlet <dees-editor-markdownoutlet
.markdown=${markdownContent} .markdown=${markdownContent}
.theme=${'github'} // Options: github, dark, custom .theme=${'github'}
.plugins=${['mermaid', 'highlight']} // Optional plugins allowHtml={false}
allowHtml={false} // Security: disable raw HTML
></dees-editor-markdownoutlet> ></dees-editor-markdownoutlet>
``` ```
@@ -1271,8 +1141,6 @@ Terminal emulator component for command-line interface.
}} }}
.prompt=${'$'} .prompt=${'$'}
.welcomeMessage=${'Welcome! Type "help" for available commands.'} .welcomeMessage=${'Welcome! Type "help" for available commands.'}
.historySize=${100}
.autoFocus={true}
></dees-terminal> ></dees-terminal>
``` ```
@@ -1282,13 +1150,14 @@ Component for managing application updates and version control.
```typescript ```typescript
<dees-updater <dees-updater
.currentVersion=${'1.5.2'} .currentVersion=${'1.5.2'}
.checkInterval=${3600000} // Check every hour .checkInterval=${3600000}
.autoUpdate=${false} .autoUpdate=${false}
@update-available=${handleUpdateAvailable} @update-available=${handleUpdateAvailable}
@update-progress=${handleUpdateProgress}
></dees-updater> ></dees-updater>
``` ```
---
### Auth & Utilities Components ### Auth & Utilities Components
#### `DeesSimpleAppdash` #### `DeesSimpleAppdash`
@@ -1301,10 +1170,7 @@ Simple application dashboard component for quick prototyping.
{ name: 'Dashboard', icon: 'home', route: '/dashboard' }, { name: 'Dashboard', icon: 'home', route: '/dashboard' },
{ name: 'Settings', icon: 'settings', route: '/settings' } { name: 'Settings', icon: 'settings', route: '/settings' }
]} ]}
.user=${{ .user=${{ name: 'John Doe', role: 'Administrator' }}
name: 'John Doe',
role: 'Administrator'
}}
@menu-select=${handleMenuSelect} @menu-select=${handleMenuSelect}
> >
<!-- Dashboard content --> <!-- Dashboard content -->
@@ -1319,7 +1185,7 @@ Simple login form component with validation and customization.
.appName=${'My Application'} .appName=${'My Application'}
.logo=${'./assets/logo.png'} .logo=${'./assets/logo.png'}
.backgroundImage=${'./assets/background.jpg'} .backgroundImage=${'./assets/background.jpg'}
.fields=${['username', 'password']} // Options: username, email, password .fields=${['username', 'password']}
showForgotPassword showForgotPassword
showRememberMe showRememberMe
@login=${handleLogin} @login=${handleLogin}
@@ -1327,6 +1193,8 @@ Simple login form component with validation and customization.
></dees-simple-login> ></dees-simple-login>
``` ```
---
### Shopping Components ### Shopping Components
#### `DeesShoppingProductcard` #### `DeesShoppingProductcard`
@@ -1339,37 +1207,69 @@ Product card component for e-commerce applications.
category: 'Electronics', category: 'Electronics',
description: 'High-quality wireless headphones with noise cancellation', description: 'High-quality wireless headphones with noise cancellation',
price: 199.99, price: 199.99,
originalPrice: 249.99, // Shows strikethrough price originalPrice: 249.99,
currency: '$', currency: '$',
inStock: true, inStock: true,
stockText: 'In Stock', // Custom stock text imageUrl: '/images/headphones.jpg'
imageUrl: '/images/headphones.jpg',
iconName: 'lucide:headphones' // Fallback icon if no image
}} }}
quantity={1} // Current quantity quantity={1}
showQuantitySelector={true} // Show quantity selector showQuantitySelector={true}
selectable={false} // Enable selection mode @quantityChange=${handleQuantityChange}
selected={false} // Selection state
@quantityChange=${(e) => handleQuantityChange(e.detail)}
@selectionChange=${(e) => handleSelectionChange(e.detail)}
></dees-shopping-productcard> ></dees-shopping-productcard>
``` ```
---
## 🔧 TypeScript Interfaces
The library exports unified interfaces for consistent API patterns:
```typescript
// Base menu item interface (used by tabs, menus, etc.)
interface IMenuItem {
key: string;
iconName?: string;
action: () => void;
badge?: string | number;
badgeVariant?: 'default' | 'success' | 'warning' | 'error';
}
// Extended tab interface for views with content
interface IViewTab extends IMenuItem {
content?: TemplateResult | (() => TemplateResult);
useSlotName?: boolean;
slotName?: string;
paddingPx?: number;
}
// Menu group interface for organized menus
interface IMenuGroup {
name: string;
items: IMenuItem[];
collapsed?: boolean;
iconName?: string;
}
```
---
## License and Legal Information ## License and Legal Information
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the license file within this repository. This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [LICENSE](./LICENSE) file.
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. **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.
### Trademarks ### Trademarks
This 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. This 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 or third parties, 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 or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.
### Company Information ### Company Information
Task Venture Capital GmbH Task Venture Capital GmbH
Registered at District court Bremen HRB 35230 HB, Germany Registered at District Court Bremen HRB 35230 HB, Germany
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc. For any legal inquiries or further information, please contact us via email at hello@task.vc.
By 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. By 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.

View File

@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@design.estate/dees-catalog', name: '@design.estate/dees-catalog',
version: '3.4.0', version: '3.5.0',
description: 'A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.' description: 'A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.'
} }

View File

@@ -0,0 +1,45 @@
import { html, cssManager } from '@design.estate/dees-element';
import '@design.estate/dees-wcctools/demotools';
import type { DeesAppuiActivitylog } from './dees-appui-activitylog.js';
export const demoFunc = () => {
// Create the activity log element
const activityLog = document.createElement('dees-appui-activitylog') as DeesAppuiActivitylog;
// Add demo entries after the element is connected
setTimeout(() => {
activityLog.addMany([
{ type: 'login', user: 'John Doe', message: 'logged in from Chrome on macOS' },
{ type: 'create', user: 'John Doe', message: 'created a new project "Frontend App"' },
{ type: 'update', user: 'Jane Smith', message: 'updated API documentation' },
{ type: 'view', user: 'John Doe', message: 'viewed dashboard analytics' },
{ type: 'delete', user: 'Admin', message: 'removed deprecated endpoint' },
{ type: 'custom', user: 'System', message: 'scheduled backup completed', iconName: 'lucide:database' },
{ type: 'logout', user: 'Alice Brown', message: 'logged out' },
{ type: 'create', user: 'Jane Smith', message: 'created invoice #1234' },
]);
// Subscribe to updates
activityLog.entries$.subscribe((entries) => {
console.log('Activity log updated:', entries.length, 'entries');
});
}, 100);
return html`
<dees-demowrapper>
<style>
.demo-container {
display: flex;
justify-content: center;
align-items: center;
height: 600px;
background: ${cssManager.bdTheme('#f4f4f5', '#09090b')};
padding: 32px;
}
</style>
<div class="demo-container">
${activityLog}
</div>
</dees-demowrapper>
`;
};

View File

@@ -12,53 +12,14 @@ import {
import * as domtools from '@design.estate/dees-domtools'; import * as domtools from '@design.estate/dees-domtools';
import { DeesContextmenu } from '../../dees-contextmenu/dees-contextmenu.js'; import { DeesContextmenu } from '../../dees-contextmenu/dees-contextmenu.js';
import '../../dees-icon/dees-icon.js'; import '../../dees-icon/dees-icon.js';
import '@design.estate/dees-wcctools/demotools';
import type { IActivityEntry, IActivityLogAPI } from '../../interfaces/appconfig.js'; import type { IActivityEntry, IActivityLogAPI } from '../../interfaces/appconfig.js';
import { demoFunc } from './dees-appui-activitylog.demo.js';
import { themeDefaultStyles } from '../../00theme.js';
@customElement('dees-appui-activitylog') @customElement('dees-appui-activitylog')
export class DeesAppuiActivitylog extends DeesElement implements IActivityLogAPI { export class DeesAppuiActivitylog extends DeesElement implements IActivityLogAPI {
// STATIC // STATIC
public static demo = () => { public static demo = demoFunc;
// Create the activity log element
const activityLog = document.createElement('dees-appui-activitylog') as DeesAppuiActivitylog;
// Add demo entries after the element is connected
setTimeout(() => {
activityLog.addMany([
{ type: 'login', user: 'John Doe', message: 'logged in from Chrome on macOS' },
{ type: 'create', user: 'John Doe', message: 'created a new project "Frontend App"' },
{ type: 'update', user: 'Jane Smith', message: 'updated API documentation' },
{ type: 'view', user: 'John Doe', message: 'viewed dashboard analytics' },
{ type: 'delete', user: 'Admin', message: 'removed deprecated endpoint' },
{ type: 'custom', user: 'System', message: 'scheduled backup completed', iconName: 'lucide:database' },
{ type: 'logout', user: 'Alice Brown', message: 'logged out' },
{ type: 'create', user: 'Jane Smith', message: 'created invoice #1234' },
]);
// Subscribe to updates
activityLog.entries$.subscribe((entries) => {
console.log('Activity log updated:', entries.length, 'entries');
});
}, 100);
return html`
<dees-demowrapper>
<style>
.demo-container {
display: flex;
justify-content: center;
align-items: center;
height: 600px;
background: ${cssManager.bdTheme('#f4f4f5', '#09090b')};
padding: 32px;
}
</style>
<div class="demo-container">
${activityLog}
</div>
</dees-demowrapper>
`;
};
// INSTANCE PROPERTIES // INSTANCE PROPERTIES
@state() @state()
@@ -75,8 +36,10 @@ export class DeesAppuiActivitylog extends DeesElement implements IActivityLogAPI
// STYLES // STYLES
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
color: ${cssManager.bdTheme('#09090b', '#fafafa')}; color: ${cssManager.bdTheme('#09090b', '#fafafa')};
position: relative; position: relative;

View File

@@ -16,6 +16,7 @@ import type { DeesAppuiSecondarymenu } from '../dees-appui-secondarymenu/dees-ap
import type { DeesAppuiMaincontent } from '../dees-appui-maincontent/dees-appui-maincontent.js'; import type { DeesAppuiMaincontent } from '../dees-appui-maincontent/dees-appui-maincontent.js';
import type { DeesAppuiActivitylog } from '../dees-appui-activitylog/dees-appui-activitylog.js'; import type { DeesAppuiActivitylog } from '../dees-appui-activitylog/dees-appui-activitylog.js';
import { demoFunc } from './dees-appui-base.demo.js'; import { demoFunc } from './dees-appui-base.demo.js';
import { themeDefaultStyles } from '../../00theme.js';
// View registry for managing views // View registry for managing views
import { ViewRegistry } from './view.registry.js'; import { ViewRegistry } from './view.registry.js';
@@ -84,23 +85,23 @@ export class DeesAppuiBase extends DeesElement {
accessor mainmenuGroups: interfaces.IMenuGroup[] = []; accessor mainmenuGroups: interfaces.IMenuGroup[] = [];
@property({ type: Array }) @property({ type: Array })
accessor mainmenuBottomTabs: interfaces.ITab[] = []; accessor mainmenuBottomTabs: interfaces.IMenuItem[] = [];
@property({ type: Array }) @property({ type: Array })
accessor mainmenuTabs: interfaces.ITab[] = []; accessor mainmenuTabs: interfaces.IMenuItem[] = [];
@property({ type: Object }) @property({ type: Object })
accessor mainmenuSelectedTab: interfaces.ITab | undefined = undefined; accessor mainmenuSelectedTab: interfaces.IMenuItem | undefined = undefined;
// Properties for secondarymenu // Properties for secondarymenu
@property({ type: String }) @property({ type: String })
accessor secondarymenuHeading: string = ''; accessor secondarymenuHeading: string = '';
@property({ type: Array }) @property({ type: Array })
accessor secondarymenuGroups: interfaces.ISecondaryMenuGroup[] = []; accessor secondarymenuGroups: interfaces.IMenuGroup[] = [];
@property({ type: Object }) @property({ type: Object })
accessor secondarymenuSelectedItem: interfaces.ISecondaryMenuItem | undefined = undefined; accessor secondarymenuSelectedItem: interfaces.IMenuItem | undefined = undefined;
// Collapse states // Collapse states
@property({ type: Boolean }) @property({ type: Boolean })
@@ -111,10 +112,10 @@ export class DeesAppuiBase extends DeesElement {
// Properties for maincontent // Properties for maincontent
@property({ type: Array }) @property({ type: Array })
accessor maincontentTabs: interfaces.ITab[] = []; accessor maincontentTabs: interfaces.IMenuItem[] = [];
@property({ type: Object }) @property({ type: Object })
accessor maincontentSelectedTab: interfaces.ITab | undefined = undefined; accessor maincontentSelectedTab: interfaces.IMenuItem | undefined = undefined;
// References to child components // References to child components
@state() @state()
@@ -142,8 +143,10 @@ export class DeesAppuiBase extends DeesElement {
private searchCallback: ((query: string) => void) | null = null; private searchCallback: ((query: string) => void) | null = null;
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
position: absolute; position: absolute;
height: 100%; height: 100%;
@@ -370,12 +373,12 @@ export class DeesAppuiBase extends DeesElement {
/** /**
* Add a menu item to a specific group * Add a menu item to a specific group
*/ */
public addMainMenuItem(groupName: string, tab: interfaces.ITab): void { public addMainMenuItem(groupName: string, tab: interfaces.IMenuItem): void {
this.mainmenuGroups = this.mainmenuGroups.map(group => { this.mainmenuGroups = this.mainmenuGroups.map(group => {
if (group.name === groupName) { if (group.name === groupName) {
return { return {
...group, ...group,
tabs: [...(group.tabs || []), tab], items: [...(group.items || []), tab],
}; };
} }
return group; return group;
@@ -390,7 +393,7 @@ export class DeesAppuiBase extends DeesElement {
if (group.name === groupName) { if (group.name === groupName) {
return { return {
...group, ...group,
tabs: (group.tabs || []).filter(t => t.key !== tabKey), items: (group.items || []).filter(t => t.key !== tabKey),
}; };
} }
return group; return group;
@@ -402,7 +405,7 @@ export class DeesAppuiBase extends DeesElement {
*/ */
public setMainMenuSelection(tabKey: string): void { public setMainMenuSelection(tabKey: string): void {
for (const group of this.mainmenuGroups) { for (const group of this.mainmenuGroups) {
const tab = group.tabs?.find(t => t.key === tabKey); const tab = group.items?.find(t => t.key === tabKey);
if (tab) { if (tab) {
this.mainmenuSelectedTab = tab; this.mainmenuSelectedTab = tab;
return; return;
@@ -428,7 +431,7 @@ export class DeesAppuiBase extends DeesElement {
public setMainMenuBadge(tabKey: string, badge: string | number): void { public setMainMenuBadge(tabKey: string, badge: string | number): void {
this.mainmenuGroups = this.mainmenuGroups.map(group => ({ this.mainmenuGroups = this.mainmenuGroups.map(group => ({
...group, ...group,
tabs: (group.tabs || []).map(tab => items: (group.items || []).map(tab =>
tab.key === tabKey ? { ...tab, badge } : tab tab.key === tabKey ? { ...tab, badge } : tab
), ),
})); }));
@@ -444,7 +447,7 @@ export class DeesAppuiBase extends DeesElement {
public clearMainMenuBadge(tabKey: string): void { public clearMainMenuBadge(tabKey: string): void {
this.mainmenuGroups = this.mainmenuGroups.map(group => ({ this.mainmenuGroups = this.mainmenuGroups.map(group => ({
...group, ...group,
tabs: (group.tabs || []).map(tab => { items: (group.items || []).map(tab => {
if (tab.key === tabKey) { if (tab.key === tabKey) {
const { badge, ...rest } = tab; const { badge, ...rest } = tab;
return rest; return rest;
@@ -469,7 +472,7 @@ export class DeesAppuiBase extends DeesElement {
/** /**
* Set the secondary menu configuration * Set the secondary menu configuration
*/ */
public setSecondaryMenu(config: { heading?: string; groups: interfaces.ISecondaryMenuGroup[] }): void { public setSecondaryMenu(config: { heading?: string; groups: interfaces.IMenuGroup[] }): void {
if (config.heading !== undefined) { if (config.heading !== undefined) {
this.secondarymenuHeading = config.heading; this.secondarymenuHeading = config.heading;
} }
@@ -479,7 +482,7 @@ export class DeesAppuiBase extends DeesElement {
/** /**
* Update a specific secondary menu group * Update a specific secondary menu group
*/ */
public updateSecondaryMenuGroup(groupName: string, update: Partial<interfaces.ISecondaryMenuGroup>): void { public updateSecondaryMenuGroup(groupName: string, update: Partial<interfaces.IMenuGroup>): void {
this.secondarymenuGroups = this.secondarymenuGroups.map(group => this.secondarymenuGroups = this.secondarymenuGroups.map(group =>
group.name === groupName ? { ...group, ...update } : group group.name === groupName ? { ...group, ...update } : group
); );
@@ -490,7 +493,7 @@ export class DeesAppuiBase extends DeesElement {
*/ */
public addSecondaryMenuItem( public addSecondaryMenuItem(
groupName: string, groupName: string,
item: interfaces.ISecondaryMenuGroup['items'][0] item: interfaces.IMenuGroup['items'][0]
): void { ): void {
this.secondarymenuGroups = this.secondarymenuGroups.map(group => { this.secondarymenuGroups = this.secondarymenuGroups.map(group => {
if (group.name === groupName) { if (group.name === groupName) {
@@ -532,7 +535,7 @@ export class DeesAppuiBase extends DeesElement {
/** /**
* Set the content tabs * Set the content tabs
*/ */
public setContentTabs(tabs: interfaces.ITab[]): void { public setContentTabs(tabs: interfaces.IMenuItem[]): void {
this.maincontentTabs = [...tabs]; this.maincontentTabs = [...tabs];
if (tabs.length > 0 && !this.maincontentSelectedTab) { if (tabs.length > 0 && !this.maincontentSelectedTab) {
this.maincontentSelectedTab = tabs[0]; this.maincontentSelectedTab = tabs[0];
@@ -542,7 +545,7 @@ export class DeesAppuiBase extends DeesElement {
/** /**
* Add a content tab * Add a content tab
*/ */
public addContentTab(tab: interfaces.ITab): void { public addContentTab(tab: interfaces.IMenuItem): void {
this.maincontentTabs = [...this.maincontentTabs, tab]; this.maincontentTabs = [...this.maincontentTabs, tab];
} }
@@ -569,7 +572,7 @@ export class DeesAppuiBase extends DeesElement {
/** /**
* Get the currently selected content tab * Get the currently selected content tab
*/ */
public getSelectedContentTab(): interfaces.ITab | undefined { public getSelectedContentTab(): interfaces.IMenuItem | undefined {
return this.maincontentSelectedTab; return this.maincontentSelectedTab;
} }
@@ -779,7 +782,7 @@ export class DeesAppuiBase extends DeesElement {
return config.mainMenu.sections.map((section) => ({ return config.mainMenu.sections.map((section) => ({
name: section.name, name: section.name,
tabs: section.views items: section.views
.map((viewId) => { .map((viewId) => {
const view = this.viewRegistry.get(viewId); const view = this.viewRegistry.get(viewId);
if (!view) { if (!view) {
@@ -791,13 +794,13 @@ export class DeesAppuiBase extends DeesElement {
iconName: view.iconName, iconName: view.iconName,
action: () => this.navigateToView(viewId), action: () => this.navigateToView(viewId),
badge: view.badge, badge: view.badge,
} as interfaces.ITab; } as interfaces.IMenuItem;
}) })
.filter(Boolean) as interfaces.ITab[], .filter(Boolean) as interfaces.IMenuItem[],
})); }));
} }
private buildBottomTabsFromItems(items: string[]): interfaces.ITab[] { private buildBottomTabsFromItems(items: string[]): interfaces.IMenuItem[] {
return items return items
.map((viewId) => { .map((viewId) => {
const view = this.viewRegistry.get(viewId); const view = this.viewRegistry.get(viewId);
@@ -809,9 +812,9 @@ export class DeesAppuiBase extends DeesElement {
key: view.id, key: view.id,
iconName: view.iconName, iconName: view.iconName,
action: () => this.navigateToView(viewId), action: () => this.navigateToView(viewId),
} as interfaces.ITab; } as interfaces.IMenuItem;
}) })
.filter(Boolean) as interfaces.ITab[]; .filter(Boolean) as interfaces.IMenuItem[];
} }
private async loadView( private async loadView(

View File

@@ -13,6 +13,7 @@ import {
import * as domtools from '@design.estate/dees-domtools'; import * as domtools from '@design.estate/dees-domtools';
import '../dees-appui-tabs/dees-appui-tabs.js'; import '../dees-appui-tabs/dees-appui-tabs.js';
import type { DeesAppuiTabs } from '../dees-appui-tabs/dees-appui-tabs.js'; import type { DeesAppuiTabs } from '../dees-appui-tabs/dees-appui-tabs.js';
import { themeDefaultStyles } from '../../00theme.js';
@customElement('dees-appui-maincontent') @customElement('dees-appui-maincontent')
export class DeesAppuiMaincontent extends DeesElement { export class DeesAppuiMaincontent extends DeesElement {
@@ -35,16 +36,18 @@ export class DeesAppuiMaincontent extends DeesElement {
@property({ @property({
type: Array, type: Array,
}) })
accessor tabs: interfaces.ITab[] = [ accessor tabs: interfaces.IMenuItem[] = [
{ key: '⚠️ Please set tabs', action: () => console.warn('No tabs configured for maincontent') }, { key: '⚠️ Please set tabs', action: () => console.warn('No tabs configured for maincontent') },
]; ];
@property({ type: Object }) @property({ type: Object })
accessor selectedTab: interfaces.ITab | null = null; accessor selectedTab: interfaces.IMenuItem | null = null;
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
color: ${cssManager.bdTheme('#333', '#fff')}; color: ${cssManager.bdTheme('#333', '#fff')};
display: block; display: block;

View File

@@ -13,6 +13,7 @@ import {
} from '@design.estate/dees-element'; } from '@design.estate/dees-element';
import { DeesContextmenu } from '../../dees-contextmenu/dees-contextmenu.js'; import { DeesContextmenu } from '../../dees-contextmenu/dees-contextmenu.js';
import { demoFunc } from './dees-appui-mainmenu.demo.js'; import { demoFunc } from './dees-appui-mainmenu.demo.js';
import { themeDefaultStyles } from '../../00theme.js';
/** /**
* the most left menu * the most left menu
@@ -37,21 +38,23 @@ export class DeesAppuiMainmenu extends DeesElement {
// Bottom tabs (pinned to bottom) // Bottom tabs (pinned to bottom)
@property({ type: Array }) @property({ type: Array })
accessor bottomTabs: interfaces.ITab[] = []; accessor bottomTabs: interfaces.IMenuItem[] = [];
// Legacy tabs property (for backward compatibility) // Legacy tabs property (for backward compatibility)
@property({ type: Array }) @property({ type: Array })
accessor tabs: interfaces.ITab[] = []; accessor tabs: interfaces.IMenuItem[] = [];
@property() @property()
accessor selectedTab: interfaces.ITab; accessor selectedTab: interfaces.IMenuItem;
@property({ type: Boolean, reflect: true }) @property({ type: Boolean, reflect: true })
accessor collapsed: boolean = false; accessor collapsed: boolean = false;
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
--menu-width-expanded: 200px; --menu-width-expanded: 200px;
--menu-width-collapsed: 56px; --menu-width-collapsed: 56px;
@@ -390,7 +393,7 @@ export class DeesAppuiMainmenu extends DeesElement {
<div class="menuGroup"> <div class="menuGroup">
${group.name ? html`<div class="groupHeader">${group.name}</div>` : ''} ${group.name ? html`<div class="groupHeader">${group.name}</div>` : ''}
<div class="groupTabs"> <div class="groupTabs">
${group.tabs.map((tabArg) => this.renderTab(tabArg))} ${group.items.map((tabArg) => this.renderTab(tabArg))}
</div> </div>
</div> </div>
`)} `)}
@@ -407,7 +410,7 @@ export class DeesAppuiMainmenu extends DeesElement {
`; `;
} }
private renderTab(tabArg: interfaces.ITab): TemplateResult { private renderTab(tabArg: interfaces.IMenuItem): TemplateResult {
return html` return html`
<div <div
class="tab ${tabArg === this.selectedTab ? 'selectedTab' : ''}" class="tab ${tabArg === this.selectedTab ? 'selectedTab' : ''}"
@@ -422,15 +425,15 @@ export class DeesAppuiMainmenu extends DeesElement {
`; `;
} }
private getAllTabs(): interfaces.ITab[] { private getAllTabs(): interfaces.IMenuItem[] {
if (this.menuGroups.length > 0) { if (this.menuGroups.length > 0) {
const groupTabs = this.menuGroups.flatMap(group => group.tabs); const groupTabs = this.menuGroups.flatMap(group => group.items);
return [...groupTabs, ...this.bottomTabs]; return [...groupTabs, ...this.bottomTabs];
} }
return [...this.tabs, ...this.bottomTabs]; return [...this.tabs, ...this.bottomTabs];
} }
updateTab(tabArg: interfaces.ITab) { updateTab(tabArg: interfaces.IMenuItem) {
this.selectedTab = tabArg; this.selectedTab = tabArg;
this.selectedTab.action(); this.selectedTab.action();

View File

@@ -11,6 +11,7 @@ import {
cssManager, cssManager,
state, state,
} from '@design.estate/dees-element'; } from '@design.estate/dees-element';
import { themeDefaultStyles } from '../../00theme.js';
@customElement('dees-appui-profiledropdown') @customElement('dees-appui-profiledropdown')
export class DeesAppuiProfileDropdown extends DeesElement { export class DeesAppuiProfileDropdown extends DeesElement {
@@ -53,8 +54,10 @@ export class DeesAppuiProfileDropdown extends DeesElement {
accessor position: 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' = 'top-right'; accessor position: 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' = 'top-right';
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
display: block; display: block;
position: absolute; position: absolute;

View File

@@ -44,7 +44,7 @@ export const demoFunc = () => html`
{ key: 'Integrations', iconName: 'plug', action: () => console.log('Integrations'), badge: 5, badgeVariant: 'error' }, { key: 'Integrations', iconName: 'plug', action: () => console.log('Integrations'), badge: 5, badgeVariant: 'error' },
] ]
} }
] as interfaces.ISecondaryMenuGroup[]} ] as interfaces.IMenuGroup[]}
@item-select=${(e: CustomEvent) => console.log('Selected:', e.detail)} @item-select=${(e: CustomEvent) => console.log('Selected:', e.detail)}
></dees-appui-secondarymenu> ></dees-appui-secondarymenu>
<div class="spacer"></div> <div class="spacer"></div>

View File

@@ -15,6 +15,7 @@ import {
cssManager, cssManager,
} from '@design.estate/dees-element'; } from '@design.estate/dees-element';
import { demoFunc } from './dees-appui-secondarymenu.demo.js'; import { demoFunc } from './dees-appui-secondarymenu.demo.js';
import { themeDefaultStyles } from '../../00theme.js';
/** /**
* Secondary navigation menu for sub-navigation within MainMenu views * Secondary navigation menu for sub-navigation within MainMenu views
@@ -32,15 +33,15 @@ export class DeesAppuiSecondarymenu extends DeesElement {
/** Grouped items with collapse support */ /** Grouped items with collapse support */
@property({ type: Array }) @property({ type: Array })
accessor groups: interfaces.ISecondaryMenuGroup[] = []; accessor groups: interfaces.IMenuGroup[] = [];
/** Legacy flat list support for backward compatibility */ /** Legacy flat list support for backward compatibility */
@property({ type: Array }) @property({ type: Array })
accessor selectionOptions: (interfaces.ISelectionOption | { divider: true })[] = []; accessor selectionOptions: (interfaces.IMenuItem | { divider: true })[] = [];
/** Currently selected item */ /** Currently selected item */
@property({ type: Object }) @property({ type: Object })
accessor selectedItem: interfaces.ISecondaryMenuItem | null = null; accessor selectedItem: interfaces.IMenuItem | null = null;
/** Internal state for collapsed groups */ /** Internal state for collapsed groups */
@state() @state()
@@ -51,8 +52,10 @@ export class DeesAppuiSecondarymenu extends DeesElement {
accessor collapsed: boolean = false; accessor collapsed: boolean = false;
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
--sidebar-width-expanded: 240px; --sidebar-width-expanded: 240px;
--sidebar-width-collapsed: 56px; --sidebar-width-collapsed: 56px;
@@ -482,7 +485,7 @@ export class DeesAppuiSecondarymenu extends DeesElement {
`; `;
} }
private renderMenuItem(item: interfaces.ISecondaryMenuItem, group?: interfaces.ISecondaryMenuGroup): TemplateResult { private renderMenuItem(item: interfaces.IMenuItem, group?: interfaces.IMenuGroup): TemplateResult {
const isSelected = this.selectedItem?.key === item.key; const isSelected = this.selectedItem?.key === item.key;
return html` return html`
<div <div
@@ -507,7 +510,7 @@ export class DeesAppuiSecondarymenu extends DeesElement {
if ('divider' in option && option.divider) { if ('divider' in option && option.divider) {
return html`<div class="divider"></div>`; return html`<div class="divider"></div>`;
} }
const item = option as interfaces.ISelectionOption; const item = option as interfaces.IMenuItem;
return this.renderMenuItem({ return this.renderMenuItem({
key: item.key, key: item.key,
iconName: item.iconName, iconName: item.iconName,
@@ -537,7 +540,7 @@ export class DeesAppuiSecondarymenu extends DeesElement {
})); }));
} }
private selectItem(item: interfaces.ISecondaryMenuItem, group?: interfaces.ISecondaryMenuGroup): void { private selectItem(item: interfaces.IMenuItem, group?: interfaces.IMenuGroup): void {
this.selectedItem = item; this.selectedItem = item;
item.action(); item.action();
@@ -548,7 +551,7 @@ export class DeesAppuiSecondarymenu extends DeesElement {
})); }));
} }
private handleContextMenu(event: MouseEvent, item: interfaces.ISecondaryMenuItem): void { private handleContextMenu(event: MouseEvent, item: interfaces.IMenuItem): void {
DeesContextmenu.openContextMenuWithOptions(event, [ DeesContextmenu.openContextMenuWithOptions(event, [
{ {
name: 'View details', name: 'View details',
@@ -582,7 +585,7 @@ export class DeesAppuiSecondarymenu extends DeesElement {
} }
} else if (this.selectionOptions.length > 0) { } else if (this.selectionOptions.length > 0) {
// Legacy mode: select first non-divider option // Legacy mode: select first non-divider option
const firstOption = this.selectionOptions.find(opt => !('divider' in opt)) as interfaces.ISelectionOption; const firstOption = this.selectionOptions.find(opt => !('divider' in opt)) as interfaces.IMenuItem;
if (firstOption && !this.selectedItem) { if (firstOption && !this.selectedItem) {
this.selectItem({ this.selectItem({
key: firstOption.key, key: firstOption.key,

View File

@@ -0,0 +1,91 @@
import { html, cssManager } from '@design.estate/dees-element';
import * as interfaces from '../../interfaces/index.js';
export const demoFunc = () => {
const horizontalTabs: interfaces.IMenuItem[] = [
{ key: 'Home', iconName: 'lucide:home', action: () => console.log('Home clicked') },
{ key: 'Analytics Dashboard', iconName: 'lucide:lineChart', action: () => console.log('Analytics clicked') },
{ key: 'Reports', iconName: 'lucide:fileText', action: () => console.log('Reports clicked') },
{ key: 'User Settings', iconName: 'lucide:settings', action: () => console.log('Settings clicked') },
{ key: 'Help', iconName: 'lucide:helpCircle', action: () => console.log('Help clicked') },
];
const verticalTabs: interfaces.IMenuItem[] = [
{ key: 'Profile', iconName: 'lucide:user', action: () => console.log('Profile clicked') },
{ key: 'Security', iconName: 'lucide:shield', action: () => console.log('Security clicked') },
{ key: 'Notifications', iconName: 'lucide:bell', action: () => console.log('Notifications clicked') },
{ key: 'Integrations', iconName: 'lucide:link', action: () => console.log('Integrations clicked') },
{ key: 'Advanced', iconName: 'lucide:code', action: () => console.log('Advanced clicked') },
];
const noIndicatorTabs: interfaces.IMenuItem[] = [
{ key: 'All', action: () => console.log('All clicked') },
{ key: 'Active', action: () => console.log('Active clicked') },
{ key: 'Completed', action: () => console.log('Completed clicked') },
{ key: 'Archived', action: () => console.log('Archived clicked') },
];
const demoContent = (text: string) => html`
<div style="padding: 24px; color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};">
${text}
</div>
`;
return html`
<style>
.demo-container {
display: flex;
flex-direction: column;
gap: 32px;
padding: 48px;
background: ${cssManager.bdTheme('#f8f9fa', '#0a0a0a')};
min-height: 100vh;
}
.section {
background: ${cssManager.bdTheme('#ffffff', '#18181b')};
border: 1px solid ${cssManager.bdTheme('#e5e7eb', '#27272a')};
border-radius: 8px;
padding: 24px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.section-title {
font-size: 18px;
font-weight: 600;
margin-bottom: 16px;
color: ${cssManager.bdTheme('#09090b', '#fafafa')};
}
.two-column {
display: grid;
grid-template-columns: 200px 1fr;
gap: 24px;
align-items: start;
}
</style>
<div class="demo-container">
<div class="section">
<div class="section-title">Horizontal Tabs with Animated Indicator</div>
<dees-appui-tabs .tabs=${horizontalTabs}>
${demoContent('Select a tab to see the smooth sliding animation of the indicator. The indicator automatically adjusts its width to match the tab content with minimal padding.')}
</dees-appui-tabs>
</div>
<div class="section">
<div class="section-title">Vertical Tabs Layout</div>
<div class="two-column">
<dees-appui-tabs .tabStyle=${'vertical'} .tabs=${verticalTabs}></dees-appui-tabs>
${demoContent('Vertical tabs work great for settings pages and navigation menus. The animated indicator smoothly transitions between selections.')}
</div>
</div>
<div class="section">
<div class="section-title">Without Indicator</div>
<dees-appui-tabs .showTabIndicator=${false} .tabs=${noIndicatorTabs}>
${demoContent('Tabs can also be used without the animated indicator by setting showTabIndicator to false.')}
</dees-appui-tabs>
</div>
</div>
`;
};

View File

@@ -11,106 +11,21 @@ import {
} from '@design.estate/dees-element'; } from '@design.estate/dees-element';
import * as domtools from '@design.estate/dees-domtools'; import * as domtools from '@design.estate/dees-domtools';
import { demoFunc } from './dees-appui-tabs.demo.js';
import { themeDefaultStyles } from '../../00theme.js';
@customElement('dees-appui-tabs') @customElement('dees-appui-tabs')
export class DeesAppuiTabs extends DeesElement { export class DeesAppuiTabs extends DeesElement {
public static demo = () => { public static demo = demoFunc;
const horizontalTabs: interfaces.ITab[] = [
{ key: 'Home', iconName: 'lucide:home', action: () => console.log('Home clicked') },
{ key: 'Analytics Dashboard', iconName: 'lucide:lineChart', action: () => console.log('Analytics clicked') },
{ key: 'Reports', iconName: 'lucide:fileText', action: () => console.log('Reports clicked') },
{ key: 'User Settings', iconName: 'lucide:settings', action: () => console.log('Settings clicked') },
{ key: 'Help', iconName: 'lucide:helpCircle', action: () => console.log('Help clicked') },
];
const verticalTabs: interfaces.ITab[] = [
{ key: 'Profile', iconName: 'lucide:user', action: () => console.log('Profile clicked') },
{ key: 'Security', iconName: 'lucide:shield', action: () => console.log('Security clicked') },
{ key: 'Notifications', iconName: 'lucide:bell', action: () => console.log('Notifications clicked') },
{ key: 'Integrations', iconName: 'lucide:link', action: () => console.log('Integrations clicked') },
{ key: 'Advanced', iconName: 'lucide:code', action: () => console.log('Advanced clicked') },
];
const noIndicatorTabs: interfaces.ITab[] = [
{ key: 'All', action: () => console.log('All clicked') },
{ key: 'Active', action: () => console.log('Active clicked') },
{ key: 'Completed', action: () => console.log('Completed clicked') },
{ key: 'Archived', action: () => console.log('Archived clicked') },
];
const demoContent = (text: string) => html`
<div style="padding: 24px; color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};">
${text}
</div>
`;
return html`
<style>
.demo-container {
display: flex;
flex-direction: column;
gap: 32px;
padding: 48px;
background: ${cssManager.bdTheme('#f8f9fa', '#0a0a0a')};
min-height: 100vh;
}
.section {
background: ${cssManager.bdTheme('#ffffff', '#18181b')};
border: 1px solid ${cssManager.bdTheme('#e5e7eb', '#27272a')};
border-radius: 8px;
padding: 24px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.section-title {
font-size: 18px;
font-weight: 600;
margin-bottom: 16px;
color: ${cssManager.bdTheme('#09090b', '#fafafa')};
}
.two-column {
display: grid;
grid-template-columns: 200px 1fr;
gap: 24px;
align-items: start;
}
</style>
<div class="demo-container">
<div class="section">
<div class="section-title">Horizontal Tabs with Animated Indicator</div>
<dees-appui-tabs .tabs=${horizontalTabs}>
${demoContent('Select a tab to see the smooth sliding animation of the indicator. The indicator automatically adjusts its width to match the tab content with minimal padding.')}
</dees-appui-tabs>
</div>
<div class="section">
<div class="section-title">Vertical Tabs Layout</div>
<div class="two-column">
<dees-appui-tabs .tabStyle=${'vertical'} .tabs=${verticalTabs}></dees-appui-tabs>
${demoContent('Vertical tabs work great for settings pages and navigation menus. The animated indicator smoothly transitions between selections.')}
</div>
</div>
<div class="section">
<div class="section-title">Without Indicator</div>
<dees-appui-tabs .showTabIndicator=${false} .tabs=${noIndicatorTabs}>
${demoContent('Tabs can also be used without the animated indicator by setting showTabIndicator to false.')}
</dees-appui-tabs>
</div>
</div>
`;
};
// INSTANCE // INSTANCE
@property({ @property({
type: Array, type: Array,
}) })
accessor tabs: interfaces.ITab[] = []; accessor tabs: interfaces.IMenuItem[] = [];
@property({ type: Object }) @property({ type: Object })
accessor selectedTab: interfaces.ITab | null = null; accessor selectedTab: interfaces.IMenuItem | null = null;
@property({ type: Boolean }) @property({ type: Boolean })
accessor showTabIndicator: boolean = true; accessor showTabIndicator: boolean = true;
@@ -119,8 +34,10 @@ export class DeesAppuiTabs extends DeesElement {
accessor tabStyle: 'horizontal' | 'vertical' = 'horizontal'; accessor tabStyle: 'horizontal' | 'vertical' = 'horizontal';
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
display: block; display: block;
position: relative; position: relative;
@@ -312,7 +229,7 @@ export class DeesAppuiTabs extends DeesElement {
`; `;
} }
private renderTab(tab: interfaces.ITab, isHorizontal: boolean): TemplateResult { private renderTab(tab: interfaces.IMenuItem, isHorizontal: boolean): TemplateResult {
const isSelected = tab === this.selectedTab; const isSelected = tab === this.selectedTab;
const classes = `tab ${isSelected ? 'selectedTab' : ''}`; const classes = `tab ${isSelected ? 'selectedTab' : ''}`;
@@ -336,11 +253,11 @@ export class DeesAppuiTabs extends DeesElement {
`; `;
} }
private renderTabIcon(tab: interfaces.ITab): TemplateResult | '' { private renderTabIcon(tab: interfaces.IMenuItem): TemplateResult | '' {
return tab.iconName ? html`<dees-icon .icon=${tab.iconName}></dees-icon>` : ''; return tab.iconName ? html`<dees-icon .icon=${tab.iconName}></dees-icon>` : '';
} }
private selectTab(tabArg: interfaces.ITab) { private selectTab(tabArg: interfaces.IMenuItem) {
this.selectedTab = tabArg; this.selectedTab = tabArg;
tabArg.action(); tabArg.action();

View File

@@ -0,0 +1,30 @@
import { html } from '@design.estate/dees-element';
export const demoFunc = () => html`
<dees-appui-view
.viewConfig=${{
id: 'demo-view',
name: 'Demo View',
description: 'A demonstration view',
iconName: 'lucide:home',
tabs: [
{
key: 'overview',
iconName: 'lucide:lineChart',
action: () => console.log('Overview tab'),
content: html`<div style="padding: 20px;">Overview Content</div>`
},
{
key: 'details',
iconName: 'lucide:fileText',
action: () => console.log('Details tab'),
content: html`<div style="padding: 20px;">Details Content</div>`
}
],
menuItems: [
{ key: 'General', action: () => console.log('General') },
{ key: 'Advanced', action: () => console.log('Advanced') },
]
}}
></dees-appui-view>
`;

View File

@@ -13,9 +13,14 @@ import {
import '../dees-appui-tabs/dees-appui-tabs.js'; import '../dees-appui-tabs/dees-appui-tabs.js';
import type { DeesAppuiTabs } from '../dees-appui-tabs/dees-appui-tabs.js'; import type { DeesAppuiTabs } from '../dees-appui-tabs/dees-appui-tabs.js';
import { demoFunc } from './dees-appui-view.demo.js';
import { themeDefaultStyles } from '../../00theme.js';
export interface IAppViewTab extends interfaces.ITab { export interface IViewTab extends interfaces.IMenuItem {
content?: TemplateResult | (() => TemplateResult); content?: TemplateResult | (() => TemplateResult);
useSlotName?: boolean;
slotName?: string;
paddingPx?: number;
} }
export interface IAppView { export interface IAppView {
@@ -23,54 +28,32 @@ export interface IAppView {
name: string; name: string;
description?: string; description?: string;
iconName?: string; iconName?: string;
tabs: IAppViewTab[]; tabs: IViewTab[];
menuItems?: interfaces.ISelectionOption[]; menuItems?: interfaces.IMenuItem[];
} }
@customElement('dees-appui-view') @customElement('dees-appui-view')
export class DeesAppuiView extends DeesElement { export class DeesAppuiView extends DeesElement {
public static demo = () => html` public static demo = demoFunc;
<dees-appui-view
.viewConfig=${{
id: 'demo-view',
name: 'Demo View',
description: 'A demonstration view',
iconName: 'lucide:home',
tabs: [
{
key: 'overview',
iconName: 'lucide:lineChart',
action: () => console.log('Overview tab'),
content: html`<div style="padding: 20px;">Overview Content</div>`
},
{
key: 'details',
iconName: 'lucide:fileText',
action: () => console.log('Details tab'),
content: html`<div style="padding: 20px;">Details Content</div>`
}
],
menuItems: [
{ key: 'General', action: () => console.log('General') },
{ key: 'Advanced', action: () => console.log('Advanced') },
]
}}
></dees-appui-view>
`;
// INSTANCE // INSTANCE
@property({ type: Object }) @property({ type: Object })
accessor viewConfig: IAppView; accessor viewConfig: IAppView;
@state() @state()
accessor selectedTab: IAppViewTab | null = null; accessor selectedTab: IViewTab | null = null;
@state() @state()
accessor tabs: DeesAppuiTabs; accessor tabs: DeesAppuiTabs;
@property({ type: Number })
accessor paddingPx: number = 16;
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
display: block; display: block;
position: relative; position: relative;
@@ -138,9 +121,14 @@ export class DeesAppuiView extends DeesElement {
${this.viewConfig.tabs.map((tab) => { ${this.viewConfig.tabs.map((tab) => {
const isActive = tab === this.selectedTab; const isActive = tab === this.selectedTab;
const content = typeof tab.content === 'function' ? tab.content() : tab.content; const content = typeof tab.content === 'function' ? tab.content() : tab.content;
const padding = tab.paddingPx ?? this.paddingPx;
return html` return html`
<div class="tab-content ${isActive ? 'active' : ''}"> <div class="tab-content ${isActive ? 'active' : ''}" style="padding: ${padding}px;">
${content || html`<slot name="${tab.key}"></slot>`} ${content
? content
: tab.useSlotName
? html`<slot name="${tab.slotName || tab.key}"></slot>`
: ''}
</div> </div>
`; `;
})} })}
@@ -182,11 +170,11 @@ export class DeesAppuiView extends DeesElement {
} }
} }
public getMenuItems(): interfaces.ISelectionOption[] { public getMenuItems(): interfaces.IMenuItem[] {
return this.viewConfig?.menuItems || []; return this.viewConfig?.menuItems || [];
} }
public getTabs(): IAppViewTab[] { public getTabs(): IViewTab[] {
return this.viewConfig?.tabs || []; return this.viewConfig?.tabs || [];
} }
} }

View File

@@ -10,6 +10,7 @@ import {
import * as domtools from '@design.estate/dees-domtools'; import * as domtools from '@design.estate/dees-domtools';
import { demoFunc } from './dees-button-group.demo.js'; import { demoFunc } from './dees-button-group.demo.js';
import { themeDefaultStyles } from '../../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -33,8 +34,10 @@ export class DeesButtonGroup extends DeesElement {
} }
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
display: inline-block; display: inline-block;
} }

View File

@@ -12,6 +12,7 @@ import {
import * as domtools from '@design.estate/dees-domtools'; import * as domtools from '@design.estate/dees-domtools';
import { demoFunc } from './dees-button.demo.js'; import { demoFunc } from './dees-button.demo.js';
import { themeDefaultStyles } from '../../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -79,8 +80,10 @@ export class DeesButton extends DeesElement {
} }
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
display: inline-block; display: inline-block;
box-sizing: border-box; box-sizing: border-box;

View File

@@ -10,6 +10,7 @@ import {
import * as domtools from '@design.estate/dees-domtools'; import * as domtools from '@design.estate/dees-domtools';
import { demoFunc } from './dees-chart-log.demo.js'; import { demoFunc } from './dees-chart-log.demo.js';
import { themeDefaultStyles } from '../../00theme.js';
declare global { declare global {
@@ -50,8 +51,10 @@ export class DeesChartLog extends DeesElement {
} }
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
font-family: 'SF Mono', 'Monaco', 'Consolas', 'Liberation Mono', 'Courier New', monospace; font-family: 'SF Mono', 'Monaco', 'Consolas', 'Liberation Mono', 'Courier New', monospace;
color: ${cssManager.bdTheme('hsl(0 0% 3.9%)', 'hsl(0 0% 98%)')}; color: ${cssManager.bdTheme('hsl(0 0% 3.9%)', 'hsl(0 0% 98%)')};

View File

@@ -16,6 +16,7 @@ import {
import * as tsclass from '@tsclass/tsclass'; import * as tsclass from '@tsclass/tsclass';
import { DeesContextmenu } from '../../dees-contextmenu/dees-contextmenu.js'; import { DeesContextmenu } from '../../dees-contextmenu/dees-contextmenu.js';
import { themeDefaultStyles } from '../../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -30,8 +31,10 @@ export class DeesDataviewStatusobject extends DeesElement {
@property({ type: Object }) accessor statusObject: tsclass.code.IStatusObject; @property({ type: Object }) accessor statusObject: tsclass.code.IStatusObject;
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
} }

View File

@@ -8,6 +8,7 @@ import {
cssManager, cssManager,
domtools domtools
} from '@design.estate/dees-element'; } from '@design.estate/dees-element';
import { themeDefaultStyles } from '../../00theme.js';
const deferred = domtools.plugins.smartpromise.defer(); const deferred = domtools.plugins.smartpromise.defer();
@@ -22,8 +23,10 @@ export class DeesEditorMarkdown extends DeesElement {
public static demo = () => html`<dees-editormarkdown></dees-editormarkdown>`; public static demo = () => html`<dees-editormarkdown></dees-editormarkdown>`;
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
.gridcontainer { .gridcontainer {
position: absolute; position: absolute;
height: 100%; height: 100%;

View File

@@ -9,6 +9,7 @@ import {
} from '@design.estate/dees-element'; } from '@design.estate/dees-element';
import * as domtools from '@design.estate/dees-domtools'; import * as domtools from '@design.estate/dees-domtools';
import { MONACO_VERSION } from './version.js'; import { MONACO_VERSION } from './version.js';
import { themeDefaultStyles } from '../../00theme.js';
import type * as monaco from 'monaco-editor'; import type * as monaco from 'monaco-editor';
@@ -51,8 +52,10 @@ export class DeesEditor extends DeesElement {
} }
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
} }

View File

@@ -8,6 +8,7 @@ import {
property, property,
} from '@design.estate/dees-element'; } from '@design.estate/dees-element';
import type { DeesForm } from '../dees-form/dees-form.js'; import type { DeesForm } from '../dees-form/dees-form.js';
import { themeDefaultStyles } from '../../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -39,7 +40,9 @@ export class DeesFormSubmit extends DeesElement {
super(); super();
} }
public static styles = [cssManager.defaultStyles, css``]; public static styles = [themeDefaultStyles, cssManager.defaultStyles, css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
`];
public render() { public render() {
return html` return html`

View File

@@ -9,6 +9,7 @@ import {
import { DeesInputBase } from '../dees-input-base/dees-input-base.js'; import { DeesInputBase } from '../dees-input-base/dees-input-base.js';
import { demoFunc } from './dees-input-checkbox.demo.js'; import { demoFunc } from './dees-input-checkbox.demo.js';
import { cssGeistFontFamily } from '../../00fonts.js'; import { cssGeistFontFamily } from '../../00fonts.js';
import { themeDefaultStyles } from '../../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -38,9 +39,11 @@ export class DeesInputCheckbox extends DeesInputBase<DeesInputCheckbox> {
} }
public static styles = [ public static styles = [
themeDefaultStyles,
...DeesInputBase.baseStyles, ...DeesInputBase.baseStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
* { * {
box-sizing: border-box; box-sizing: border-box;
} }

View File

@@ -11,6 +11,7 @@ import * as domtools from '@design.estate/dees-domtools';
import { demoFunc } from './dees-input-dropdown.demo.js'; import { demoFunc } from './dees-input-dropdown.demo.js';
import { DeesInputBase } from '../dees-input-base/dees-input-base.js'; import { DeesInputBase } from '../dees-input-base/dees-input-base.js';
import { cssGeistFontFamily } from '../../00fonts.js'; import { cssGeistFontFamily } from '../../00fonts.js';
import { themeDefaultStyles } from '../../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -60,9 +61,11 @@ export class DeesInputDropdown extends DeesInputBase<DeesInputDropdown> {
accessor searchValue: string = ''; accessor searchValue: string = '';
public static styles = [ public static styles = [
themeDefaultStyles,
...DeesInputBase.baseStyles, ...DeesInputBase.baseStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
* { * {
box-sizing: border-box; box-sizing: border-box;
} }

View File

@@ -11,6 +11,7 @@ import * as domtools from '@design.estate/dees-domtools';
import { DeesInputBase } from '../dees-input-base/dees-input-base.js'; import { DeesInputBase } from '../dees-input-base/dees-input-base.js';
import * as ibantools from 'ibantools'; import * as ibantools from 'ibantools';
import { demoFunc } from './dees-input-iban.demo.js'; import { demoFunc } from './dees-input-iban.demo.js';
import { themeDefaultStyles } from '../../00theme.js';
@customElement('dees-input-iban') @customElement('dees-input-iban')
export class DeesInputIban extends DeesInputBase<DeesInputIban> { export class DeesInputIban extends DeesInputBase<DeesInputIban> {
@@ -30,9 +31,11 @@ export class DeesInputIban extends DeesInputBase<DeesInputIban> {
accessor value = ''; accessor value = '';
public static styles = [ public static styles = [
themeDefaultStyles,
...DeesInputBase.baseStyles, ...DeesInputBase.baseStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
/* IBAN input specific styles can go here */ /* IBAN input specific styles can go here */
`, `,
]; ];

View File

@@ -11,6 +11,7 @@ import { DeesInputBase } from '../dees-input-base/dees-input-base.js';
import '../../dees-icon/dees-icon.js'; import '../../dees-icon/dees-icon.js';
import '../../00group-button/dees-button/dees-button.js'; import '../../00group-button/dees-button/dees-button.js';
import { demoFunc } from './dees-input-list.demo.js'; import { demoFunc } from './dees-input-list.demo.js';
import { themeDefaultStyles } from '../../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -64,9 +65,11 @@ export class DeesInputList extends DeesInputBase<DeesInputList> {
accessor dragOverIndex: number = -1; accessor dragOverIndex: number = -1;
public static styles = [ public static styles = [
themeDefaultStyles,
...DeesInputBase.baseStyles, ...DeesInputBase.baseStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
display: block; display: block;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;

View File

@@ -11,6 +11,7 @@ import { DeesInputBase } from '../dees-input-base/dees-input-base.js';
import * as colors from '../../00colors.js' import * as colors from '../../00colors.js'
import { demoFunc } from './dees-input-multitoggle.demo.js'; import { demoFunc } from './dees-input-multitoggle.demo.js';
import { themeDefaultStyles } from '../../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -67,9 +68,11 @@ export class DeesInputMultitoggle extends DeesInputBase<DeesInputMultitoggle> {
} }
public static styles = [ public static styles = [
themeDefaultStyles,
...DeesInputBase.baseStyles, ...DeesInputBase.baseStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
color: ${cssManager.bdTheme('#09090b', '#fafafa')}; color: ${cssManager.bdTheme('#09090b', '#fafafa')};
user-select: none; user-select: none;

View File

@@ -10,6 +10,7 @@ import {
import * as domtools from '@design.estate/dees-domtools'; import * as domtools from '@design.estate/dees-domtools';
import { DeesInputBase } from '../dees-input-base/dees-input-base.js'; import { DeesInputBase } from '../dees-input-base/dees-input-base.js';
import { demoFunc } from './dees-input-phone.demo.js'; import { demoFunc } from './dees-input-phone.demo.js';
import { themeDefaultStyles } from '../../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -33,9 +34,11 @@ export class DeesInputPhone extends DeesInputBase<DeesInputPhone> {
accessor placeholder: string = '+1 (555) 123-4567'; accessor placeholder: string = '+1 (555) 123-4567';
public static styles = [ public static styles = [
themeDefaultStyles,
...DeesInputBase.baseStyles, ...DeesInputBase.baseStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
/* Phone input specific styles can go here */ /* Phone input specific styles can go here */
`, `,
]; ];

View File

@@ -2,6 +2,7 @@ import { customElement, property, html, type TemplateResult, css, cssManager } f
import * as domtools from '@design.estate/dees-domtools'; import * as domtools from '@design.estate/dees-domtools';
import { DeesInputBase } from '../dees-input-base/dees-input-base.js'; import { DeesInputBase } from '../dees-input-base/dees-input-base.js';
import { demoFunc } from './dees-input-quantityselector.demo.js'; import { demoFunc } from './dees-input-quantityselector.demo.js';
import { themeDefaultStyles } from '../../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -23,14 +24,16 @@ export class DeesInputQuantitySelector extends DeesInputBase<DeesInputQuantitySe
public static styles = [ public static styles = [
themeDefaultStyles,
...DeesInputBase.baseStyles, ...DeesInputBase.baseStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
width: auto; width: auto;
user-select: none; user-select: none;
} }
.quantity-container { .quantity-container {
transition: all 0.15s ease; transition: all 0.15s ease;
font-size: 14px; font-size: 14px;

View File

@@ -8,6 +8,7 @@ import {
} from '@design.estate/dees-element'; } from '@design.estate/dees-element';
import { DeesInputBase } from '../dees-input-base/dees-input-base.js'; import { DeesInputBase } from '../dees-input-base/dees-input-base.js';
import { demoFunc } from './dees-input-radiogroup.demo.js'; import { demoFunc } from './dees-input-radiogroup.demo.js';
import { themeDefaultStyles } from '../../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -59,9 +60,11 @@ export class DeesInputRadiogroup extends DeesInputBase<string | object> {
} }
public static styles = [ public static styles = [
themeDefaultStyles,
...DeesInputBase.baseStyles, ...DeesInputBase.baseStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
* { * {
box-sizing: border-box; box-sizing: border-box;
} }

View File

@@ -10,6 +10,7 @@ import {
import { DeesInputBase } from '../dees-input-base/dees-input-base.js'; import { DeesInputBase } from '../dees-input-base/dees-input-base.js';
import '../../dees-icon/dees-icon.js'; import '../../dees-icon/dees-icon.js';
import { demoFunc } from './dees-input-tags.demo.js'; import { demoFunc } from './dees-input-tags.demo.js';
import { themeDefaultStyles } from '../../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -48,9 +49,11 @@ export class DeesInputTags extends DeesInputBase<DeesInputTags> {
accessor validationText: string = ''; accessor validationText: string = '';
public static styles = [ public static styles = [
themeDefaultStyles,
...DeesInputBase.baseStyles, ...DeesInputBase.baseStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
display: block; display: block;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;

View File

@@ -11,6 +11,7 @@ import {
cssManager, cssManager,
css, css,
} from '@design.estate/dees-element'; } from '@design.estate/dees-element';
import { themeDefaultStyles } from '../../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -56,9 +57,11 @@ export class DeesInputText extends DeesInputBase {
accessor validationFunction: (value: string) => boolean; accessor validationFunction: (value: string) => boolean;
public static styles = [ public static styles = [
themeDefaultStyles,
...DeesInputBase.baseStyles, ...DeesInputBase.baseStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
* { * {
box-sizing: border-box; box-sizing: border-box;
} }

View File

@@ -11,6 +11,7 @@ import * as domtools from '@design.estate/dees-domtools';
import { DeesInputBase } from '../dees-input-base/dees-input-base.js'; import { DeesInputBase } from '../dees-input-base/dees-input-base.js';
import { demoFunc } from './dees-input-typelist.demo.js'; import { demoFunc } from './dees-input-typelist.demo.js';
import { themeDefaultStyles } from '../../00theme.js';
@customElement('dees-input-typelist') @customElement('dees-input-typelist')
export class DeesInputTypelist extends DeesInputBase<DeesInputTypelist> { export class DeesInputTypelist extends DeesInputBase<DeesInputTypelist> {
@@ -27,9 +28,11 @@ export class DeesInputTypelist extends DeesInputBase<DeesInputTypelist> {
public static styles = [ public static styles = [
themeDefaultStyles,
...DeesInputBase.baseStyles, ...DeesInputBase.baseStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
color: ${cssManager.bdTheme('#333', '#fff')}; color: ${cssManager.bdTheme('#333', '#fff')};
} }

View File

@@ -10,6 +10,7 @@ import {
import { zIndexRegistry } from '../../00zindex.js'; import { zIndexRegistry } from '../../00zindex.js';
import { WysiwygFormatting } from './wysiwyg.formatting.js'; import { WysiwygFormatting } from './wysiwyg.formatting.js';
import { themeDefaultStyles } from '../../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -41,8 +42,10 @@ export class DeesFormattingMenu extends DeesElement {
private callback: ((command: string) => void | Promise<void>) | null = null; private callback: ((command: string) => void | Promise<void>) | null = null;
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
position: fixed; position: fixed;
pointer-events: none; pointer-events: none;

View File

@@ -28,6 +28,7 @@ import {
DeesSlashMenu, DeesSlashMenu,
DeesFormattingMenu DeesFormattingMenu
} from './index.js'; } from './index.js';
import { themeDefaultStyles } from '../../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -86,6 +87,7 @@ export class DeesInputWysiwyg extends DeesInputBase<string> {
private history: WysiwygHistory; private history: WysiwygHistory;
public static styles = [ public static styles = [
themeDefaultStyles,
...DeesInputBase.baseStyles, ...DeesInputBase.baseStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
wysiwygStyles wysiwygStyles

View File

@@ -12,6 +12,7 @@ import '../../dees-icon/dees-icon.js';
import { type ISlashMenuItem } from './wysiwyg.types.js'; import { type ISlashMenuItem } from './wysiwyg.types.js';
import { WysiwygShortcuts } from './wysiwyg.shortcuts.js'; import { WysiwygShortcuts } from './wysiwyg.shortcuts.js';
import { themeDefaultStyles } from '../../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -49,8 +50,10 @@ export class DeesSlashMenu extends DeesElement {
private callback: ((type: string) => void) | null = null; private callback: ((type: string) => void) | null = null;
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
position: fixed; position: fixed;
pointer-events: none; pointer-events: none;

View File

@@ -15,6 +15,7 @@ import { BlockRegistry, type IBlockEventHandlers } from './blocks/index.js';
import './wysiwyg.blockregistration.js'; import './wysiwyg.blockregistration.js';
import { WysiwygShortcuts } from './wysiwyg.shortcuts.js'; import { WysiwygShortcuts } from './wysiwyg.shortcuts.js';
import '../../dees-contextmenu/dees-contextmenu.js'; import '../../dees-contextmenu/dees-contextmenu.js';
import { themeDefaultStyles } from '../../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -82,8 +83,10 @@ export class DeesWysiwygBlock extends DeesElement {
} }
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
display: block; display: block;
} }

View File

@@ -12,6 +12,7 @@ import '../../dees-icon/dees-icon.js';
import '../../dees-label/dees-label.js'; import '../../dees-label/dees-label.js';
import { ProfilePictureModal } from './profilepicture.modal.js'; import { ProfilePictureModal } from './profilepicture.modal.js';
import { demoFunc } from './dees-input-profilepicture.demo.js'; import { demoFunc } from './dees-input-profilepicture.demo.js';
import { themeDefaultStyles } from '../../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -67,9 +68,11 @@ export class DeesInputProfilePicture extends DeesInputBase<DeesInputProfilePictu
private modalInstance: ProfilePictureModal | null = null; private modalInstance: ProfilePictureModal | null = null;
public static styles = [ public static styles = [
themeDefaultStyles,
...DeesInputBase.baseStyles, ...DeesInputBase.baseStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
display: block; display: block;
position: relative; position: relative;

View File

@@ -17,6 +17,7 @@ import '../../dees-windowlayer/dees-windowlayer.js';
import { DeesWindowLayer } from '../../dees-windowlayer/dees-windowlayer.js'; import { DeesWindowLayer } from '../../dees-windowlayer/dees-windowlayer.js';
import { ImageCropper } from './profilepicture.cropper.js'; import { ImageCropper } from './profilepicture.cropper.js';
import type { ProfileShape } from './dees-input-profilepicture.js'; import type { ProfileShape } from './dees-input-profilepicture.js';
import { themeDefaultStyles } from '../../00theme.js';
@customElement('dees-profilepicture-modal') @customElement('dees-profilepicture-modal')
export class ProfilePictureModal extends DeesElement { export class ProfilePictureModal extends DeesElement {
@@ -46,8 +47,10 @@ export class ProfilePictureModal extends DeesElement {
private zIndex: number = 0; private zIndex: number = 0;
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
font-family: ${cssGeistFontFamily}; font-family: ${cssGeistFontFamily};
color: ${cssManager.bdTheme('#333', '#fff')}; color: ${cssManager.bdTheme('#333', '#fff')};

View File

@@ -15,6 +15,7 @@ import {
} from '@design.estate/dees-element'; } from '@design.estate/dees-element';
import '../../dees-icon/dees-icon.js'; import '../../dees-icon/dees-icon.js';
import type { DeesTerminal } from '../../dees-terminal/dees-terminal.js'; import type { DeesTerminal } from '../../dees-terminal/dees-terminal.js';
import { themeDefaultStyles } from '../../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -48,8 +49,10 @@ export class DeesSimpleAppDash extends DeesElement {
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
color: ${cssManager.bdTheme('hsl(0 0% 15%)', 'hsl(0 0% 90%)')}; color: ${cssManager.bdTheme('hsl(0 0% 15%)', 'hsl(0 0% 90%)')};
user-select: none; user-select: none;

View File

@@ -9,6 +9,7 @@ import {
cssManager, cssManager,
css, css,
} from '@design.estate/dees-element'; } from '@design.estate/dees-element';
import { themeDefaultStyles } from '../../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -26,8 +27,10 @@ export class DeesSimpleLogin extends DeesElement {
accessor name: string = 'Application'; accessor name: string = 'Application';
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
color: ${cssManager.bdTheme('hsl(0 0% 3.9%)', 'hsl(0 0% 98%)')}; color: ${cssManager.bdTheme('hsl(0 0% 3.9%)', 'hsl(0 0% 98%)')};
user-select: none; user-select: none;

218
ts_web/elements/00theme.ts Normal file
View File

@@ -0,0 +1,218 @@
import { css, type CSSResult } from '@design.estate/dees-element';
// ============================================
// Theme Token Type Definitions
// ============================================
export interface IThemeColors {
bgPrimary: string;
bgSecondary: string;
bgTertiary: string;
textPrimary: string;
textSecondary: string;
textMuted: string;
borderDefault: string;
borderSubtle: string;
borderStrong: string;
accentPrimary: string;
accentSuccess: string;
accentWarning: string;
accentError: string;
}
export interface IThemeSpacing {
xs: string;
sm: string;
md: string;
lg: string;
xl: string;
'2xl': string;
'3xl': string;
}
export interface IThemeRadius {
xs: string;
sm: string;
md: string;
lg: string;
xl: string;
full: string;
}
export interface IThemeShadows {
xs: string;
sm: string;
md: string;
lg: string;
}
export interface IThemeTransitions {
fast: string;
default: string;
slow: string;
slower: string;
}
export interface IThemeControlHeights {
sm: string;
md: string;
lg: string;
xl: string;
}
export interface ITheme {
colors: {
light: IThemeColors;
dark: IThemeColors;
};
spacing: IThemeSpacing;
radius: IThemeRadius;
shadows: IThemeShadows;
transitions: IThemeTransitions;
controlHeights: IThemeControlHeights;
}
// ============================================
// Default Theme Values (TypeScript Object)
// ============================================
export const themeDefaults: ITheme = {
colors: {
light: {
bgPrimary: '#ffffff',
bgSecondary: '#fafafa',
bgTertiary: '#f4f4f5',
textPrimary: '#09090b',
textSecondary: '#374151',
textMuted: '#71717a',
borderDefault: '#e5e7eb',
borderSubtle: '#f4f4f5',
borderStrong: '#d1d5db',
accentPrimary: '#3b82f6',
accentSuccess: '#22c55e',
accentWarning: '#f59e0b',
accentError: '#ef4444',
},
dark: {
bgPrimary: '#09090b',
bgSecondary: '#0a0a0a',
bgTertiary: '#18181b',
textPrimary: '#fafafa',
textSecondary: '#d4d4d8',
textMuted: '#a1a1aa',
borderDefault: '#27272a',
borderSubtle: '#1a1a1a',
borderStrong: '#3f3f46',
accentPrimary: '#3b82f6',
accentSuccess: '#22c55e',
accentWarning: '#f59e0b',
accentError: '#ef4444',
},
},
spacing: {
xs: '4px',
sm: '8px',
md: '12px',
lg: '16px',
xl: '24px',
'2xl': '32px',
'3xl': '48px',
},
radius: {
xs: '2px',
sm: '4px',
md: '6px',
lg: '8px',
xl: '12px',
full: '999px',
},
shadows: {
xs: '0 1px 2px 0 rgb(0 0 0 / 0.05)',
sm: '0 1px 3px rgba(0, 0, 0, 0.1)',
md: '0 2px 8px rgba(0, 0, 0, 0.15)',
lg: '0 4px 12px rgba(0, 0, 0, 0.15)',
},
transitions: {
fast: '0.1s',
default: '0.15s',
slow: '0.2s',
slower: '0.3s',
},
controlHeights: {
sm: '32px',
md: '36px',
lg: '40px',
xl: '48px',
},
};
// ============================================
// CSS Block for Component Import
// ============================================
/**
* Default theme styles to be imported into every component's static styles array.
* Provides CSS custom properties for spacing, radius, shadows, transitions, and control heights.
*
* Usage:
* ```typescript
* import { themeDefaultStyles } from '../00theme.js';
*
* @customElement('my-component')
* export class MyComponent extends DeesElement {
* public static styles = [
* themeDefaultStyles,
* cssManager.defaultStyles,
* css`...`
* ];
* }
* ```
*/
export const themeDefaultStyles: CSSResult = css`
:host {
/* ========================================
* Spacing Scale
* ======================================== */
--dees-spacing-xs: 4px;
--dees-spacing-sm: 8px;
--dees-spacing-md: 12px;
--dees-spacing-lg: 16px;
--dees-spacing-xl: 24px;
--dees-spacing-2xl: 32px;
--dees-spacing-3xl: 48px;
/* ========================================
* Border Radius Scale
* ======================================== */
--dees-radius-xs: 2px;
--dees-radius-sm: 4px;
--dees-radius-md: 6px;
--dees-radius-lg: 8px;
--dees-radius-xl: 12px;
--dees-radius-full: 999px;
/* ========================================
* Shadow Elevation Scale
* ======================================== */
--dees-shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--dees-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1);
--dees-shadow-md: 0 2px 8px rgba(0, 0, 0, 0.15);
--dees-shadow-lg: 0 4px 12px rgba(0, 0, 0, 0.15);
/* ========================================
* Transition Duration Scale
* ======================================== */
--dees-transition-fast: 0.1s;
--dees-transition-default: 0.15s;
--dees-transition-slow: 0.2s;
--dees-transition-slower: 0.3s;
/* ========================================
* Control Height Scale
* ======================================== */
--dees-control-height-sm: 32px;
--dees-control-height-md: 36px;
--dees-control-height-lg: 40px;
--dees-control-height-xl: 48px;
}
`;

View File

@@ -11,6 +11,7 @@ import {
import * as domtools from '@design.estate/dees-domtools'; import * as domtools from '@design.estate/dees-domtools';
import { demoFunc } from './dees-badge.demo.js'; import { demoFunc } from './dees-badge.demo.js';
import { themeDefaultStyles } from '../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -37,8 +38,10 @@ export class DeesBadge extends DeesElement {
} }
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
display: inline-block; display: inline-block;
} }

View File

@@ -12,6 +12,7 @@ import {
import * as domtools from '@design.estate/dees-domtools'; import * as domtools from '@design.estate/dees-domtools';
import { demoFunc } from './dees-chips.demo.js'; import { demoFunc } from './dees-chips.demo.js';
import { themeDefaultStyles } from '../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -51,8 +52,10 @@ export class DeesChips extends DeesElement {
} }
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
display: block; display: block;
box-sizing: border-box; box-sizing: border-box;

View File

@@ -16,6 +16,7 @@ import * as domtools from '@design.estate/dees-domtools';
import { DeesWindowLayer } from '../dees-windowlayer/dees-windowlayer.js'; import { DeesWindowLayer } from '../dees-windowlayer/dees-windowlayer.js';
import { zIndexLayers } from '../00zindex.js'; import { zIndexLayers } from '../00zindex.js';
import '../dees-icon/dees-icon.js'; import '../dees-icon/dees-icon.js';
import { themeDefaultStyles } from '../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -143,8 +144,10 @@ export class DeesContextmenu extends DeesElement {
* STATIC STYLES * STATIC STYLES
*/ */
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
display: block; display: block;
transition: opacity 0.2s, transform 0.2s; transition: opacity 0.2s, transform 0.2s;

View File

@@ -11,6 +11,7 @@ import {
import { demoFunc } from './dees-heading.demo.js'; import { demoFunc } from './dees-heading.demo.js';
import { cssCalSansFontFamily } from '../00fonts.js'; import { cssCalSansFontFamily } from '../00fonts.js';
import { themeDefaultStyles } from '../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -32,8 +33,10 @@ export class DeesHeading extends DeesElement {
// STATIC STYLES // STATIC STYLES
public static styles: CSSResult[] = [ public static styles: CSSResult[] = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
/* Heading styles */ /* Heading styles */
h1, h2, h3, h4, h5, h6 { h1, h2, h3, h4, h5, h6 {
margin: 16px 0 8px; margin: 16px 0 8px;

View File

@@ -11,6 +11,7 @@ import {
import * as domtools from '@design.estate/dees-domtools'; import * as domtools from '@design.estate/dees-domtools';
import { demoFunc } from './dees-hint.demo.js'; import { demoFunc } from './dees-hint.demo.js';
import { themeDefaultStyles } from '../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -30,7 +31,9 @@ export class DeesHint extends DeesElement {
domtools.elementBasic.setup(); domtools.elementBasic.setup();
} }
public static styles = [cssManager.defaultStyles, css``]; public static styles = [themeDefaultStyles, cssManager.defaultStyles, css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
`];
public render(): TemplateResult { public render(): TemplateResult {
return html` <div class="mainbox"></div> `; return html` <div class="mainbox"></div> `;

View File

@@ -9,6 +9,7 @@ import {
} from '@design.estate/dees-element'; } from '@design.estate/dees-element';
import * as domtools from '@design.estate/dees-domtools'; import * as domtools from '@design.estate/dees-domtools';
import { themeDefaultStyles } from '../00theme.js';
import { icon, type IconDefinition } from '@fortawesome/fontawesome-svg-core'; import { icon, type IconDefinition } from '@fortawesome/fontawesome-svg-core';
import { import {
@@ -325,8 +326,10 @@ export class DeesIcon extends DeesElement {
} }
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
@@ -334,7 +337,7 @@ export class DeesIcon extends DeesElement {
line-height: 1; line-height: 1;
vertical-align: middle; vertical-align: middle;
} }
/* Improve rendering performance */ /* Improve rendering performance */
#iconContainer svg { #iconContainer svg {
display: block; display: block;

View File

@@ -13,6 +13,7 @@ import {
} from '@design.estate/dees-element'; } from '@design.estate/dees-element';
import { demoFunc } from './dees-label.demo.js'; import { demoFunc } from './dees-label.demo.js';
import { themeDefaultStyles } from '../00theme.js';
@customElement('dees-label') @customElement('dees-label')
export class DeesLabel extends DeesElement { export class DeesLabel extends DeesElement {
@@ -39,8 +40,10 @@ export class DeesLabel extends DeesElement {
accessor required: boolean = false; accessor required: boolean = false;
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
} }

View File

@@ -14,6 +14,7 @@ import {
} from '@design.estate/dees-element'; } from '@design.estate/dees-element';
import { DeesWindowLayer } from '../dees-windowlayer/dees-windowlayer.js'; import { DeesWindowLayer } from '../dees-windowlayer/dees-windowlayer.js';
import '../dees-icon/dees-icon.js'; import '../dees-icon/dees-icon.js';
import { themeDefaultStyles } from '../00theme.js';
@customElement('dees-mobilenavigation') @customElement('dees-mobilenavigation')
export class DeesMobilenavigation extends DeesElement { export class DeesMobilenavigation extends DeesElement {
@@ -111,8 +112,10 @@ export class DeesMobilenavigation extends DeesElement {
} }
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
font-family: ${cssGeistFontFamily}; font-family: ${cssGeistFontFamily};
} }

View File

@@ -21,6 +21,7 @@ import {
import * as domtools from '@design.estate/dees-domtools'; import * as domtools from '@design.estate/dees-domtools';
import { DeesWindowLayer } from '../dees-windowlayer/dees-windowlayer.js'; import { DeesWindowLayer } from '../dees-windowlayer/dees-windowlayer.js';
import '../dees-icon/dees-icon.js'; import '../dees-icon/dees-icon.js';
import { themeDefaultStyles } from '../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -115,8 +116,10 @@ export class DeesModal extends DeesElement {
} }
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
font-family: ${cssGeistFontFamily}; font-family: ${cssGeistFontFamily};
color: ${cssManager.bdTheme('#333', '#fff')}; color: ${cssManager.bdTheme('#333', '#fff')};

View File

@@ -1,5 +1,6 @@
import { customElement, html, DeesElement, property, css, cssManager, type TemplateResult } from '@design.estate/dees-element'; import { customElement, html, DeesElement, property, css, cssManager, type TemplateResult } from '@design.estate/dees-element';
import { demoFunc } from './dees-pagination.demo.js'; import { demoFunc } from './dees-pagination.demo.js';
import { themeDefaultStyles } from '../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -23,8 +24,10 @@ export class DeesPagination extends DeesElement {
accessor total = 1; accessor total = 1;
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;

View File

@@ -9,6 +9,7 @@ import {
} from '@design.estate/dees-element'; } from '@design.estate/dees-element';
import { demoFunc } from './dees-panel.demo.js'; import { demoFunc } from './dees-panel.demo.js';
import { cssGeistFontFamily } from '../00fonts.js'; import { cssGeistFontFamily } from '../00fonts.js';
import { themeDefaultStyles } from '../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -36,8 +37,10 @@ export class DeesPanel extends DeesElement {
accessor runAfterRender: ((elementArg: HTMLElement) => void | Promise<void>) | undefined = undefined; accessor runAfterRender: ((elementArg: HTMLElement) => void | Promise<void>) | undefined = undefined;
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
display: block; display: block;
font-family: ${cssGeistFontFamily}; font-family: ${cssGeistFontFamily};

View File

@@ -16,6 +16,7 @@ import {
} from '@design.estate/dees-element'; } from '@design.estate/dees-element';
import * as domtools from '@design.estate/dees-domtools'; import * as domtools from '@design.estate/dees-domtools';
import { themeDefaultStyles } from '../00theme.js';
@customElement('dees-progressbar') @customElement('dees-progressbar')
export class DeesProgressbar extends DeesElement { export class DeesProgressbar extends DeesElement {
@@ -29,8 +30,10 @@ export class DeesProgressbar extends DeesElement {
accessor percentage = 0; accessor percentage = 0;
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
color: ${cssManager.bdTheme(colors.bright.text, colors.dark.text)}; color: ${cssManager.bdTheme(colors.bright.text, colors.dark.text)};
} }

View File

@@ -13,6 +13,7 @@ import {
import * as colors from '../00colors.js'; import * as colors from '../00colors.js';
import { demoFunc } from './dees-searchbar.demo.js'; import { demoFunc } from './dees-searchbar.demo.js';
import { themeDefaultStyles } from '../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -27,8 +28,10 @@ export class DeesSearchbar extends DeesElement {
// STATIC // STATIC
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
padding: 40px; padding: 40px;
font-family: Dees Sans; font-family: Dees Sans;

View File

@@ -8,6 +8,7 @@ import {
DeesElement, DeesElement,
} from '@design.estate/dees-element'; } from '@design.estate/dees-element';
import { demoFunc } from './dees-shopping-productcard.demo.js'; import { demoFunc } from './dees-shopping-productcard.demo.js';
import { themeDefaultStyles } from '../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -51,8 +52,10 @@ export class DeesShoppingProductcard extends DeesElement {
accessor selected: boolean = false; accessor selected: boolean = false;
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
display: block; display: block;
} }

View File

@@ -17,6 +17,7 @@ import {
unsafeHTML, unsafeHTML,
} from '@design.estate/dees-element'; } from '@design.estate/dees-element';
import { DeesWindowLayer } from '../dees-windowlayer/dees-windowlayer.js'; import { DeesWindowLayer } from '../dees-windowlayer/dees-windowlayer.js';
import { themeDefaultStyles } from '../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -78,8 +79,10 @@ export class DeesSpeechbubble extends DeesElement {
} }
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
box-sizing: border-box; box-sizing: border-box;
color: ${cssManager.bdTheme('#333', '#fff')}; color: ${cssManager.bdTheme('#333', '#fff')};

View File

@@ -11,6 +11,7 @@ import {
} from '@design.estate/dees-element'; } from '@design.estate/dees-element';
import * as domtools from '@design.estate/dees-domtools'; import * as domtools from '@design.estate/dees-domtools';
import { themeDefaultStyles } from '../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -46,8 +47,10 @@ export class DeesSpinner extends DeesElement {
} }
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
display: block; display: block;
} }

View File

@@ -16,6 +16,7 @@ import type { TemplateResult } from '@design.estate/dees-element';
import '../dees-icon/dees-icon.js'; import '../dees-icon/dees-icon.js';
import '../dees-contextmenu/dees-contextmenu.js'; import '../dees-contextmenu/dees-contextmenu.js';
import '../00group-button/dees-button/dees-button.js'; import '../00group-button/dees-button/dees-button.js';
import { themeDefaultStyles } from '../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -75,8 +76,10 @@ export class DeesStatsGrid extends DeesElement {
accessor contextMenuActions: plugins.tsclass.website.IMenuItem[] = []; accessor contextMenuActions: plugins.tsclass.website.IMenuItem[] = [];
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
display: block; display: block;
width: 100%; width: 100%;

View File

@@ -15,6 +15,7 @@ import {
import * as domtools from '@design.estate/dees-domtools'; import * as domtools from '@design.estate/dees-domtools';
import { stepperDemo } from './dees-stepper.demo.js'; import { stepperDemo } from './dees-stepper.demo.js';
import { themeDefaultStyles } from '../00theme.js';
export interface IStep { export interface IStep {
title: string; title: string;
@@ -50,8 +51,10 @@ export class DeesStepper extends DeesElement {
} }
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
position: absolute; position: absolute;
width: 100%; width: 100%;

View File

@@ -14,6 +14,7 @@ import {
getViewData as getViewDataFn, getViewData as getViewDataFn,
} from './data.js'; } from './data.js';
import { compileLucenePredicate } from './lucene.js'; import { compileLucenePredicate } from './lucene.js';
import { themeDefaultStyles } from '../00theme.js';
export type { Column, ITableAction, ITableActionDataArg, TDisplayFunction } from './types.js'; export type { Column, ITableAction, ITableActionDataArg, TDisplayFunction } from './types.js';

View File

@@ -1,9 +1,12 @@
import { cssManager, css, type CSSResult } from '@design.estate/dees-element'; import { cssManager, css, type CSSResult } from '@design.estate/dees-element';
import { cssGeistFontFamily } from '../00fonts.js'; import { cssGeistFontFamily } from '../00fonts.js';
import { themeDefaultStyles } from '../00theme.js';
export const tableStyles: CSSResult[] = [ export const tableStyles: CSSResult[] = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
display: block; display: block;
width: 100%; width: 100%;

View File

@@ -13,6 +13,7 @@ import * as webcontainer from '@webcontainer/api';
import { Terminal } from 'xterm'; import { Terminal } from 'xterm';
import { FitAddon } from 'xterm-addon-fit'; import { FitAddon } from 'xterm-addon-fit';
import { themeDefaultStyles } from '../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -57,8 +58,10 @@ export class DeesTerminal extends DeesElement {
} }
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
padding: 20px; padding: 20px;
background: var(--dees-terminal-background, #000000); background: var(--dees-terminal-background, #000000);

View File

@@ -0,0 +1,275 @@
import { html, css, cssManager } from '@design.estate/dees-element';
export const demoFunc = () => html`
<style>
.demo-container {
display: flex;
flex-direction: column;
gap: 32px;
padding: 48px;
background: ${cssManager.bdTheme('#f8f9fa', '#0a0a0a')};
min-height: 100vh;
}
.section {
background: ${cssManager.bdTheme('#ffffff', '#18181b')};
border: 1px solid ${cssManager.bdTheme('#e5e7eb', '#27272a')};
border-radius: 8px;
padding: 24px;
}
.section-title {
font-size: 18px;
font-weight: 600;
margin-bottom: 16px;
color: ${cssManager.bdTheme('#09090b', '#fafafa')};
}
.section-description {
font-size: 14px;
color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
margin-bottom: 24px;
}
.token-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 16px;
}
.token-item {
background: ${cssManager.bdTheme('#f4f4f5', '#27272a')};
border-radius: 6px;
padding: 16px;
}
.token-name {
font-family: 'Intel One Mono', monospace;
font-size: 12px;
color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
margin-bottom: 8px;
}
.token-value {
font-size: 14px;
font-weight: 500;
color: ${cssManager.bdTheme('#09090b', '#fafafa')};
}
.spacing-demo {
display: flex;
align-items: flex-end;
gap: 8px;
flex-wrap: wrap;
}
.spacing-box {
background: ${cssManager.bdTheme('#3b82f6', '#3b82f6')};
border-radius: 4px;
}
.radius-demo {
display: flex;
gap: 16px;
flex-wrap: wrap;
}
.radius-box {
width: 60px;
height: 60px;
background: ${cssManager.bdTheme('#3b82f6', '#3b82f6')};
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 11px;
font-weight: 500;
}
.shadow-demo {
display: flex;
gap: 24px;
flex-wrap: wrap;
}
.shadow-box {
width: 100px;
height: 100px;
background: ${cssManager.bdTheme('#ffffff', '#27272a')};
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
font-weight: 500;
color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
}
.height-demo {
display: flex;
gap: 16px;
align-items: flex-end;
flex-wrap: wrap;
}
.height-box {
background: ${cssManager.bdTheme('#3b82f6', '#3b82f6')};
width: 120px;
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 12px;
font-weight: 500;
}
</style>
<div class="demo-container">
<dees-theme>
<div class="section">
<div class="section-title">Spacing Scale</div>
<div class="section-description">
CSS variables: --dees-spacing-xs through --dees-spacing-3xl
</div>
<div class="spacing-demo">
<div>
<div class="spacing-box" style="width: var(--dees-spacing-xs); height: var(--dees-spacing-xs);"></div>
<div class="token-name">xs (4px)</div>
</div>
<div>
<div class="spacing-box" style="width: var(--dees-spacing-sm); height: var(--dees-spacing-sm);"></div>
<div class="token-name">sm (8px)</div>
</div>
<div>
<div class="spacing-box" style="width: var(--dees-spacing-md); height: var(--dees-spacing-md);"></div>
<div class="token-name">md (12px)</div>
</div>
<div>
<div class="spacing-box" style="width: var(--dees-spacing-lg); height: var(--dees-spacing-lg);"></div>
<div class="token-name">lg (16px)</div>
</div>
<div>
<div class="spacing-box" style="width: var(--dees-spacing-xl); height: var(--dees-spacing-xl);"></div>
<div class="token-name">xl (24px)</div>
</div>
<div>
<div class="spacing-box" style="width: var(--dees-spacing-2xl); height: var(--dees-spacing-2xl);"></div>
<div class="token-name">2xl (32px)</div>
</div>
<div>
<div class="spacing-box" style="width: var(--dees-spacing-3xl); height: var(--dees-spacing-3xl);"></div>
<div class="token-name">3xl (48px)</div>
</div>
</div>
</div>
<div class="section">
<div class="section-title">Border Radius Scale</div>
<div class="section-description">
CSS variables: --dees-radius-xs through --dees-radius-full
</div>
<div class="radius-demo">
<div>
<div class="radius-box" style="border-radius: var(--dees-radius-xs);">xs</div>
<div class="token-name">2px</div>
</div>
<div>
<div class="radius-box" style="border-radius: var(--dees-radius-sm);">sm</div>
<div class="token-name">4px</div>
</div>
<div>
<div class="radius-box" style="border-radius: var(--dees-radius-md);">md</div>
<div class="token-name">6px</div>
</div>
<div>
<div class="radius-box" style="border-radius: var(--dees-radius-lg);">lg</div>
<div class="token-name">8px</div>
</div>
<div>
<div class="radius-box" style="border-radius: var(--dees-radius-xl);">xl</div>
<div class="token-name">12px</div>
</div>
<div>
<div class="radius-box" style="border-radius: var(--dees-radius-full);">full</div>
<div class="token-name">999px</div>
</div>
</div>
</div>
<div class="section">
<div class="section-title">Shadow Elevation Scale</div>
<div class="section-description">
CSS variables: --dees-shadow-xs through --dees-shadow-lg
</div>
<div class="shadow-demo">
<div>
<div class="shadow-box" style="box-shadow: var(--dees-shadow-xs);">xs</div>
<div class="token-name">minimal</div>
</div>
<div>
<div class="shadow-box" style="box-shadow: var(--dees-shadow-sm);">sm</div>
<div class="token-name">subtle</div>
</div>
<div>
<div class="shadow-box" style="box-shadow: var(--dees-shadow-md);">md</div>
<div class="token-name">medium</div>
</div>
<div>
<div class="shadow-box" style="box-shadow: var(--dees-shadow-lg);">lg</div>
<div class="token-name">prominent</div>
</div>
</div>
</div>
<div class="section">
<div class="section-title">Control Height Scale</div>
<div class="section-description">
CSS variables: --dees-control-height-sm through --dees-control-height-xl
</div>
<div class="height-demo">
<div>
<div class="height-box" style="height: var(--dees-control-height-sm);">sm</div>
<div class="token-name">32px</div>
</div>
<div>
<div class="height-box" style="height: var(--dees-control-height-md);">md</div>
<div class="token-name">36px</div>
</div>
<div>
<div class="height-box" style="height: var(--dees-control-height-lg);">lg</div>
<div class="token-name">40px</div>
</div>
<div>
<div class="height-box" style="height: var(--dees-control-height-xl);">xl</div>
<div class="token-name">48px</div>
</div>
</div>
</div>
<div class="section">
<div class="section-title">Transition Durations</div>
<div class="section-description">
CSS variables: --dees-transition-fast through --dees-transition-slower
</div>
<div class="token-grid">
<div class="token-item">
<div class="token-name">--dees-transition-fast</div>
<div class="token-value">0.1s</div>
</div>
<div class="token-item">
<div class="token-name">--dees-transition-default</div>
<div class="token-value">0.15s</div>
</div>
<div class="token-item">
<div class="token-name">--dees-transition-slow</div>
<div class="token-value">0.2s</div>
</div>
<div class="token-item">
<div class="token-name">--dees-transition-slower</div>
<div class="token-value">0.3s</div>
</div>
</div>
</div>
</dees-theme>
</div>
`;

View File

@@ -0,0 +1,224 @@
import {
DeesElement,
type TemplateResult,
property,
customElement,
html,
css,
cssManager,
} from '@design.estate/dees-element';
import {
type ITheme,
type IThemeColors,
type IThemeSpacing,
type IThemeRadius,
type IThemeShadows,
type IThemeTransitions,
type IThemeControlHeights,
themeDefaults,
themeDefaultStyles,
} from '../00theme.js';
import { demoFunc } from './dees-theme.demo.js';
/**
* A theme provider component that wraps children and provides CSS custom properties.
* Can be used at the app root or around specific sections to customize theming.
*
* Usage:
* ```html
* <dees-theme>
* <my-app></my-app>
* </dees-theme>
* ```
*
* With custom overrides:
* ```html
* <dees-theme .customSpacing=${{ lg: '20px' }}>
* <my-section></my-section>
* </dees-theme>
* ```
*/
@customElement('dees-theme')
export class DeesTheme extends DeesElement {
public static demo = demoFunc;
// ============================================
// Properties for theme overrides
// ============================================
@property({ type: Object })
accessor customSpacing: Partial<IThemeSpacing> | null = null;
@property({ type: Object })
accessor customRadius: Partial<IThemeRadius> | null = null;
@property({ type: Object })
accessor customShadows: Partial<IThemeShadows> | null = null;
@property({ type: Object })
accessor customTransitions: Partial<IThemeTransitions> | null = null;
@property({ type: Object })
accessor customControlHeights: Partial<IThemeControlHeights> | null = null;
// ============================================
// Styles
// ============================================
public static styles = [
themeDefaultStyles,
cssManager.defaultStyles,
css`
:host {
display: contents;
}
`,
];
// ============================================
// Render
// ============================================
public render(): TemplateResult {
return html`
<style>
${this.generateCustomStyles()}
</style>
<slot></slot>
`;
}
// ============================================
// Private Methods
// ============================================
private generateCustomStyles(): string {
const styles: string[] = [':host {'];
// Custom spacing
if (this.customSpacing) {
for (const [key, value] of Object.entries(this.customSpacing)) {
if (value) {
styles.push(` --dees-spacing-${key}: ${value};`);
}
}
}
// Custom radius
if (this.customRadius) {
for (const [key, value] of Object.entries(this.customRadius)) {
if (value) {
styles.push(` --dees-radius-${key}: ${value};`);
}
}
}
// Custom shadows
if (this.customShadows) {
for (const [key, value] of Object.entries(this.customShadows)) {
if (value) {
styles.push(` --dees-shadow-${key}: ${value};`);
}
}
}
// Custom transitions
if (this.customTransitions) {
for (const [key, value] of Object.entries(this.customTransitions)) {
if (value) {
const cssKey = key === 'default' ? 'default' : key;
styles.push(` --dees-transition-${cssKey}: ${value};`);
}
}
}
// Custom control heights
if (this.customControlHeights) {
for (const [key, value] of Object.entries(this.customControlHeights)) {
if (value) {
styles.push(` --dees-control-height-${key}: ${value};`);
}
}
}
styles.push('}');
return styles.join('\n');
}
// ============================================
// Public API Methods
// ============================================
/**
* Set a spacing value dynamically
*/
public setSpacing(key: keyof IThemeSpacing, value: string): void {
this.customSpacing = { ...this.customSpacing, [key]: value };
}
/**
* Set a radius value dynamically
*/
public setRadius(key: keyof IThemeRadius, value: string): void {
this.customRadius = { ...this.customRadius, [key]: value };
}
/**
* Set a shadow value dynamically
*/
public setShadow(key: keyof IThemeShadows, value: string): void {
this.customShadows = { ...this.customShadows, [key]: value };
}
/**
* Set a transition value dynamically
*/
public setTransition(key: keyof IThemeTransitions, value: string): void {
this.customTransitions = { ...this.customTransitions, [key]: value };
}
/**
* Set a control height value dynamically
*/
public setControlHeight(key: keyof IThemeControlHeights, value: string): void {
this.customControlHeights = { ...this.customControlHeights, [key]: value };
}
/**
* Get the current theme configuration (defaults + overrides)
*/
public getTheme(): ITheme {
return {
colors: themeDefaults.colors,
spacing: { ...themeDefaults.spacing, ...this.customSpacing },
radius: { ...themeDefaults.radius, ...this.customRadius },
shadows: { ...themeDefaults.shadows, ...this.customShadows },
transitions: { ...themeDefaults.transitions, ...this.customTransitions },
controlHeights: { ...themeDefaults.controlHeights, ...this.customControlHeights },
};
}
/**
* Reset all custom overrides to defaults
*/
public resetToDefaults(): void {
this.customSpacing = null;
this.customRadius = null;
this.customShadows = null;
this.customTransitions = null;
this.customControlHeights = null;
}
/**
* Apply a complete theme object
*/
public applyTheme(theme: Partial<ITheme>): void {
if (theme.spacing) this.customSpacing = theme.spacing;
if (theme.radius) this.customRadius = theme.radius;
if (theme.shadows) this.customShadows = theme.shadows;
if (theme.transitions) this.customTransitions = theme.transitions;
if (theme.controlHeights) this.customControlHeights = theme.controlHeights;
}
}

View File

@@ -0,0 +1 @@
export * from './dees-theme.js';

View File

@@ -4,6 +4,7 @@ import * as domtools from '@design.estate/dees-domtools';
import { zIndexLayers } from '../00zindex.js'; import { zIndexLayers } from '../00zindex.js';
import { demoFunc } from './dees-toast.demo.js'; import { demoFunc } from './dees-toast.demo.js';
import { cssGeistFontFamily } from '../00fonts.js'; import { cssGeistFontFamily } from '../00fonts.js';
import { themeDefaultStyles } from '../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -148,8 +149,10 @@ export class DeesToast extends DeesElement {
} }
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
display: block; display: block;
pointer-events: auto; pointer-events: auto;

View File

@@ -11,6 +11,7 @@ import { demoFunc } from './dees-updater.demo.js';
import '../dees-windowlayer/dees-windowlayer.js'; import '../dees-windowlayer/dees-windowlayer.js';
import { css, cssManager } from '@design.estate/dees-element'; import { css, cssManager } from '@design.estate/dees-element';
import { themeDefaultStyles } from '../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -44,8 +45,10 @@ export class DeesUpdater extends DeesElement {
} }
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
.modalContainer { .modalContainer {
will-change: transform; will-change: transform;
position: relative; position: relative;

View File

@@ -10,6 +10,7 @@ import {
css, css,
cssManager, cssManager,
} from '@design.estate/dees-element'; } from '@design.estate/dees-element';
import { themeDefaultStyles } from '../00theme.js';
declare global { declare global {
interface HTMLElementTagNameMap { interface HTMLElementTagNameMap {
@@ -34,8 +35,10 @@ export class DeesWindowControls extends DeesElement {
accessor position: 'left' | 'right' = 'left'; accessor position: 'left' | 'right' = 'left';
public static styles = [ public static styles = [
themeDefaultStyles,
cssManager.defaultStyles, cssManager.defaultStyles,
css` css`
/* TODO: Migrate hardcoded values to --dees-* CSS variables */
:host { :host {
position: relative; position: relative;
display: block; display: block;

View File

@@ -1,4 +1,5 @@
export * from './00zindex.js'; export * from './00zindex.js';
export * from './00theme.js';
// Component Groups // Component Groups
export * from './00group-appui/index.js'; export * from './00group-appui/index.js';
@@ -37,3 +38,4 @@ export * from './dees-toast/index.js';
export * from './dees-updater/index.js'; export * from './dees-updater/index.js';
export * from './dees-windowcontrols/index.js'; export * from './dees-windowcontrols/index.js';
export * from './dees-windowlayer/index.js'; export * from './dees-windowlayer/index.js';
export * from './dees-theme/index.js';

View File

@@ -1,7 +1,6 @@
import type { TemplateResult } from '@design.estate/dees-element'; import type { TemplateResult } from '@design.estate/dees-element';
import type { IAppBarMenuItem } from './appbarmenuitem.js'; import type { IAppBarMenuItem } from './appbarmenuitem.js';
import type { ITab } from './tab.js'; import type { IMenuItem } from './tab.js';
import type { ISecondaryMenuGroup } from './secondarymenu.js';
import type { IMenuGroup } from './menugroup.js'; import type { IMenuGroup } from './menugroup.js';
// Forward declaration for circular reference // Forward declaration for circular reference
@@ -15,22 +14,22 @@ export type TDeesAppuiBase = HTMLElement & {
setWindowControlsVisible: (visible: boolean) => void; setWindowControlsVisible: (visible: boolean) => void;
setMainMenu: (config: IMainMenuConfig) => void; setMainMenu: (config: IMainMenuConfig) => void;
updateMainMenuGroup: (groupName: string, update: Partial<IMenuGroup>) => void; updateMainMenuGroup: (groupName: string, update: Partial<IMenuGroup>) => void;
addMainMenuItem: (groupName: string, tab: ITab) => void; addMainMenuItem: (groupName: string, tab: IMenuItem) => void;
removeMainMenuItem: (groupName: string, tabKey: string) => void; removeMainMenuItem: (groupName: string, tabKey: string) => void;
setMainMenuSelection: (tabKey: string) => void; setMainMenuSelection: (tabKey: string) => void;
setMainMenuCollapsed: (collapsed: boolean) => void; setMainMenuCollapsed: (collapsed: boolean) => void;
setMainMenuBadge: (tabKey: string, badge: string | number) => void; setMainMenuBadge: (tabKey: string, badge: string | number) => void;
clearMainMenuBadge: (tabKey: string) => void; clearMainMenuBadge: (tabKey: string) => void;
setSecondaryMenu: (config: { heading?: string; groups: ISecondaryMenuGroup[] }) => void; setSecondaryMenu: (config: { heading?: string; groups: IMenuGroup[] }) => void;
updateSecondaryMenuGroup: (groupName: string, update: Partial<ISecondaryMenuGroup>) => void; updateSecondaryMenuGroup: (groupName: string, update: Partial<IMenuGroup>) => void;
addSecondaryMenuItem: (groupName: string, item: ISecondaryMenuGroup['items'][0]) => void; addSecondaryMenuItem: (groupName: string, item: IMenuGroup['items'][0]) => void;
setSecondaryMenuSelection: (itemKey: string) => void; setSecondaryMenuSelection: (itemKey: string) => void;
clearSecondaryMenu: () => void; clearSecondaryMenu: () => void;
setContentTabs: (tabs: ITab[]) => void; setContentTabs: (tabs: IMenuItem[]) => void;
addContentTab: (tab: ITab) => void; addContentTab: (tab: IMenuItem) => void;
removeContentTab: (tabKey: string) => void; removeContentTab: (tabKey: string) => void;
selectContentTab: (tabKey: string) => void; selectContentTab: (tabKey: string) => void;
getSelectedContentTab: () => ITab | undefined; getSelectedContentTab: () => IMenuItem | undefined;
activityLog: IActivityLogAPI; activityLog: IActivityLogAPI;
navigateToView: (viewId: string, params?: Record<string, string>) => Promise<boolean>; navigateToView: (viewId: string, params?: Record<string, string>) => Promise<boolean>;
getCurrentView: () => IViewDefinition | undefined; getCurrentView: () => IViewDefinition | undefined;
@@ -132,9 +131,9 @@ export interface IViewDefinition {
| (() => TemplateResult) | (() => TemplateResult)
| (() => Promise<string | (new () => HTMLElement) | (() => TemplateResult)>); | (() => Promise<string | (new () => HTMLElement) | (() => TemplateResult)>);
/** Secondary menu items specific to this view */ /** Secondary menu items specific to this view */
secondaryMenu?: ISecondaryMenuGroup[]; secondaryMenu?: IMenuGroup[];
/** Content tabs specific to this view */ /** Content tabs specific to this view */
contentTabs?: ITab[]; contentTabs?: IMenuItem[];
/** Optional route path (defaults to id). Supports params like 'settings/:section' */ /** Optional route path (defaults to id). Supports params like 'settings/:section' */
route?: string; route?: string;
/** Badge to show on menu item */ /** Badge to show on menu item */
@@ -169,7 +168,7 @@ export interface IMainMenuConfig {
/** Bottom pinned items (view IDs or tabs) */ /** Bottom pinned items (view IDs or tabs) */
bottomItems?: string[]; bottomItems?: string[];
/** Bottom tabs */ /** Bottom tabs */
bottomTabs?: ITab[]; bottomTabs?: IMenuItem[];
} }
/** /**

View File

@@ -1,6 +1,4 @@
export * from './tab.js'; export * from './tab.js';
export * from './selectionoption.js';
export * from './appbarmenuitem.js'; export * from './appbarmenuitem.js';
export * from './menugroup.js'; export * from './menugroup.js';
export * from './secondarymenu.js';
export * from './appconfig.js'; export * from './appconfig.js';

View File

@@ -1,6 +1,8 @@
import type { ITab } from './tab.js'; import type { IMenuItem } from './tab.js';
export interface IMenuGroup { export interface IMenuGroup {
name?: string; name: string;
tabs: ITab[]; items: IMenuItem[];
collapsed?: boolean;
iconName?: string;
} }

View File

@@ -1,20 +0,0 @@
/**
* Interface for individual menu items in the secondary menu
*/
export interface ISecondaryMenuItem {
key: string;
iconName?: string;
action: () => void;
badge?: string | number;
badgeVariant?: 'default' | 'success' | 'warning' | 'error';
}
/**
* Interface for collapsible groups in the secondary menu
*/
export interface ISecondaryMenuGroup {
name: string;
items: ISecondaryMenuItem[];
collapsed?: boolean;
iconName?: string;
}

View File

@@ -1,5 +0,0 @@
export interface ISelectionOption {
key: string;
iconName?: string;
action: () => void;
}

View File

@@ -1,4 +1,4 @@
export interface ITab { export interface IMenuItem {
key: string; key: string;
iconName?: string; iconName?: string;
action: () => void; action: () => void;