Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
9b0ff2d856 | |||
7e14645ed7 | |||
811737adcd | |||
7b6c135cd3 | |||
46065b2424 | |||
e76a6c3632 | |||
896bc2bbb1 | |||
296d254ba2 | |||
ecad05098f | |||
956964f5b9 | |||
ed73e16bbb |
32
changelog.md
32
changelog.md
@ -1,5 +1,37 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2025-06-27 - 1.10.8 - feat(ui-components)
|
||||||
|
Update multiple components with shadcn-aligned styling and improved animations
|
||||||
|
|
||||||
|
- Updated dees-modal with shadcn colors, borders, and subtle shadows
|
||||||
|
- Updated dees-chips with shadcn styling and fixed selection logic bug
|
||||||
|
- Updated dees-dataview-codebox with shadcn syntax highlighting colors and responsive label layout
|
||||||
|
- Updated dees-input-multitoggle with transparent blue indicator and smooth animations
|
||||||
|
- Updated dees-appui-tabs with animated sliding indicator for both horizontal and vertical layouts
|
||||||
|
- Fixed indicator positioning to be perfectly centered on tab content
|
||||||
|
- Indicator width is content width + 8px for minimal visual padding
|
||||||
|
- Fixed tab content centering by using consistent padding (12px → 16px on all sides)
|
||||||
|
- Fixed icon rendering by correcting property name from .iconName to .icon
|
||||||
|
- Added visual separators between tabs for better distinction
|
||||||
|
- Added subtle hover backgrounds for improved interactivity
|
||||||
|
- Refactored tabs component code for better maintainability and elegance
|
||||||
|
- Updated dees-appui-activitylog with shadcn-aligned styling:
|
||||||
|
- Updated background and text colors to match shadcn palette
|
||||||
|
- Enhanced topbar with better spacing and typography
|
||||||
|
- Improved activity entries with subtle hover states and better spacing
|
||||||
|
- Added activity type icons with color-coded backgrounds (login, logout, view, create, update)
|
||||||
|
- Added date separators ("Today", "Yesterday") for better temporal organization
|
||||||
|
- Enhanced streaming indicators with animated pulse effect
|
||||||
|
- Redesigned searchbox with modern input styling, search icon, and focus states
|
||||||
|
- Added custom scrollbar styling for consistency
|
||||||
|
- Updated timestamps to be more subtle with tabular number formatting
|
||||||
|
- Refined shadow effects for better visual hierarchy
|
||||||
|
- Added subtle box shadow to component for depth
|
||||||
|
- Added fade-in animation for new activity entries
|
||||||
|
- Improved user name highlighting with better typography
|
||||||
|
- Updated context menu with more relevant actions
|
||||||
|
- Improved overall spacing and visual consistency across components
|
||||||
|
|
||||||
## 2025-06-27 - 1.10.1 - fix(modal)
|
## 2025-06-27 - 1.10.1 - fix(modal)
|
||||||
Improve modal overscroll behavior by adding 'overscroll-behavior: contain' to content container
|
Improve modal overscroll behavior by adding 'overscroll-behavior: contain' to content container
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@design.estate/dees-catalog",
|
"name": "@design.estate/dees-catalog",
|
||||||
"version": "1.10.7",
|
"version": "1.10.9",
|
||||||
"private": false,
|
"private": false,
|
||||||
"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.",
|
||||||
"main": "dist_ts_web/index.js",
|
"main": "dist_ts_web/index.js",
|
||||||
@ -17,7 +17,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@design.estate/dees-domtools": "^2.3.3",
|
"@design.estate/dees-domtools": "^2.3.3",
|
||||||
"@design.estate/dees-element": "^2.0.45",
|
"@design.estate/dees-element": "^2.0.45",
|
||||||
"@design.estate/dees-wcctools": "^1.0.101",
|
"@design.estate/dees-wcctools": "^1.1.0",
|
||||||
"@fortawesome/fontawesome-svg-core": "^6.7.2",
|
"@fortawesome/fontawesome-svg-core": "^6.7.2",
|
||||||
"@fortawesome/free-brands-svg-icons": "^6.7.2",
|
"@fortawesome/free-brands-svg-icons": "^6.7.2",
|
||||||
"@fortawesome/free-regular-svg-icons": "^6.7.2",
|
"@fortawesome/free-regular-svg-icons": "^6.7.2",
|
||||||
@ -36,7 +36,7 @@
|
|||||||
"apexcharts": "^4.7.0",
|
"apexcharts": "^4.7.0",
|
||||||
"highlight.js": "11.11.1",
|
"highlight.js": "11.11.1",
|
||||||
"ibantools": "^4.5.1",
|
"ibantools": "^4.5.1",
|
||||||
"lucide": "^0.523.0",
|
"lucide": "^0.525.0",
|
||||||
"monaco-editor": "^0.52.2",
|
"monaco-editor": "^0.52.2",
|
||||||
"pdfjs-dist": "^4.10.38",
|
"pdfjs-dist": "^4.10.38",
|
||||||
"xterm": "^5.3.0",
|
"xterm": "^5.3.0",
|
||||||
|
22
pnpm-lock.yaml
generated
22
pnpm-lock.yaml
generated
@ -15,8 +15,8 @@ importers:
|
|||||||
specifier: ^2.0.45
|
specifier: ^2.0.45
|
||||||
version: 2.0.45
|
version: 2.0.45
|
||||||
'@design.estate/dees-wcctools':
|
'@design.estate/dees-wcctools':
|
||||||
specifier: ^1.0.101
|
specifier: ^1.1.0
|
||||||
version: 1.0.101
|
version: 1.1.0
|
||||||
'@fortawesome/fontawesome-svg-core':
|
'@fortawesome/fontawesome-svg-core':
|
||||||
specifier: ^6.7.2
|
specifier: ^6.7.2
|
||||||
version: 6.7.2
|
version: 6.7.2
|
||||||
@ -72,8 +72,8 @@ importers:
|
|||||||
specifier: ^4.5.1
|
specifier: ^4.5.1
|
||||||
version: 4.5.1
|
version: 4.5.1
|
||||||
lucide:
|
lucide:
|
||||||
specifier: ^0.523.0
|
specifier: ^0.525.0
|
||||||
version: 0.523.0
|
version: 0.525.0
|
||||||
monaco-editor:
|
monaco-editor:
|
||||||
specifier: ^0.52.2
|
specifier: ^0.52.2
|
||||||
version: 0.52.2
|
version: 0.52.2
|
||||||
@ -323,8 +323,8 @@ packages:
|
|||||||
'@design.estate/dees-element@2.0.45':
|
'@design.estate/dees-element@2.0.45':
|
||||||
resolution: {integrity: sha512-dj8nOOtfwvqEtQceTXQQ5IEy75HIFZ+iuDxPeIynLedYpxtHPsxFrHW8IQ7/ad9MNvVO0kTnlwUOmkjylul+DA==}
|
resolution: {integrity: sha512-dj8nOOtfwvqEtQceTXQQ5IEy75HIFZ+iuDxPeIynLedYpxtHPsxFrHW8IQ7/ad9MNvVO0kTnlwUOmkjylul+DA==}
|
||||||
|
|
||||||
'@design.estate/dees-wcctools@1.0.101':
|
'@design.estate/dees-wcctools@1.1.0':
|
||||||
resolution: {integrity: sha512-6j2kGORf7egRkHGwQUNuxSdTe2+6y7eX3+dVomBLeWczH30KhPi1jJKINSt/MqkpB5i7o3kQwvvWA6JYBOjXcg==}
|
resolution: {integrity: sha512-eniG2JsGgcVXQLkSE6M7azJ7av/UeTvvzhE6s3JbcIieHd589SCxQqF+BhlOyKqzJQ1n5jJ7KKdmhvQU5bbdtg==}
|
||||||
|
|
||||||
'@emnapi/core@1.4.3':
|
'@emnapi/core@1.4.3':
|
||||||
resolution: {integrity: sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==}
|
resolution: {integrity: sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==}
|
||||||
@ -3481,8 +3481,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==}
|
resolution: {integrity: sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==}
|
||||||
engines: {node: '>=16.14'}
|
engines: {node: '>=16.14'}
|
||||||
|
|
||||||
lucide@0.523.0:
|
lucide@0.525.0:
|
||||||
resolution: {integrity: sha512-tiIp5xEP4kpeulfT1J+a/NEaIZGT1k6RyMS3evQWfHRhJvR8uTat/+lN4wnX5qIexOwN02BhmcyMHBNwt+jkLA==}
|
resolution: {integrity: sha512-sfehWlaE/7NVkcEQ4T9JD3eID8RNMIGJBBUq9wF3UFiJIrcMKRbU3g1KGfDk4svcW7yw8BtDLXaXo02scDtUYQ==}
|
||||||
|
|
||||||
make-dir@3.1.0:
|
make-dir@3.1.0:
|
||||||
resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==}
|
resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==}
|
||||||
@ -5588,7 +5588,7 @@ snapshots:
|
|||||||
- supports-color
|
- supports-color
|
||||||
- vue
|
- vue
|
||||||
|
|
||||||
'@design.estate/dees-wcctools@1.0.101':
|
'@design.estate/dees-wcctools@1.1.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@design.estate/dees-domtools': 2.3.3
|
'@design.estate/dees-domtools': 2.3.3
|
||||||
'@design.estate/dees-element': 2.0.45
|
'@design.estate/dees-element': 2.0.45
|
||||||
@ -5905,10 +5905,8 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@nuxt/kit'
|
- '@nuxt/kit'
|
||||||
- '@swc/helpers'
|
- '@swc/helpers'
|
||||||
- bufferutil
|
|
||||||
- react
|
- react
|
||||||
- supports-color
|
- supports-color
|
||||||
- utf-8-validate
|
|
||||||
- vue
|
- vue
|
||||||
|
|
||||||
'@hapi/bourne@3.0.0': {}
|
'@hapi/bourne@3.0.0': {}
|
||||||
@ -9564,7 +9562,7 @@ snapshots:
|
|||||||
|
|
||||||
lru-cache@8.0.5: {}
|
lru-cache@8.0.5: {}
|
||||||
|
|
||||||
lucide@0.523.0: {}
|
lucide@0.525.0: {}
|
||||||
|
|
||||||
make-dir@3.1.0:
|
make-dir@3.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -529,9 +529,9 @@ Base container component for application layout structure with integrated appbar
|
|||||||
|
|
||||||
// Main menu configuration (left sidebar)
|
// Main menu configuration (left sidebar)
|
||||||
.mainmenuTabs=${[
|
.mainmenuTabs=${[
|
||||||
{ key: 'dashboard', iconName: 'home', action: () => {} },
|
{ key: 'dashboard', iconName: 'lucide:home', action: () => {} },
|
||||||
{ key: 'projects', iconName: 'folder', action: () => {} },
|
{ key: 'projects', iconName: 'lucide:folder', action: () => {} },
|
||||||
{ key: 'settings', iconName: 'cog', action: () => {} }
|
{ key: 'settings', iconName: 'lucide:settings', action: () => {} }
|
||||||
]}
|
]}
|
||||||
.mainmenuSelectedTab=${selectedTab}
|
.mainmenuSelectedTab=${selectedTab}
|
||||||
|
|
||||||
@ -545,7 +545,7 @@ Base container component for application layout structure with integrated appbar
|
|||||||
|
|
||||||
// Main content tabs
|
// Main content tabs
|
||||||
.maincontentTabs=${[
|
.maincontentTabs=${[
|
||||||
{ key: 'tab1', iconName: 'file', action: () => {} }
|
{ key: 'tab1', iconName: 'lucide:file', action: () => {} }
|
||||||
]}
|
]}
|
||||||
|
|
||||||
// Event handlers
|
// Event handlers
|
||||||
|
72
test-output.log
Normal file
72
test-output.log
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
|
||||||
|
> @design.estate/dees-catalog@1.10.8 test /mnt/data/lossless/design.estate/dees-catalog
|
||||||
|
> tstest test/ --web --verbose --timeout 30 --logfile test/test.tabs-indicator.browser.ts
|
||||||
|
|
||||||
|
[38;5;231m
|
||||||
|
🔍 Test Discovery[0m
|
||||||
|
[38;5;231m Mode: file[0m
|
||||||
|
[38;5;231m Pattern: test/test.tabs-indicator.browser.ts[0m
|
||||||
|
[38;5;113m Found: 1 test file(s)[0m
|
||||||
|
[38;5;33m
|
||||||
|
▶️ test/test.tabs-indicator.browser.ts (1/1)[0m
|
||||||
|
[38;5;231m Runtime: chromium[0m
|
||||||
|
running spawned compilation process
|
||||||
|
=======> ESBUILD
|
||||||
|
{
|
||||||
|
cwd: '/mnt/data/lossless/design.estate/dees-catalog',
|
||||||
|
from: 'test/test.tabs-indicator.browser.ts',
|
||||||
|
to: '/mnt/data/lossless/design.estate/dees-catalog/.nogit/tstest_cache/test__test.tabs-indicator.browser.ts.js',
|
||||||
|
mode: 'test',
|
||||||
|
argv: { bundler: 'esbuild' }
|
||||||
|
}
|
||||||
|
switched to /mnt/data/lossless/design.estate/dees-catalog
|
||||||
|
building for test:
|
||||||
|
Got no SSL certificates. Please ensure encryption using e.g. a reverse proxy
|
||||||
|
"/test" maps to 1 handlers
|
||||||
|
-> GET
|
||||||
|
"*" maps to 1 handlers
|
||||||
|
-> GET
|
||||||
|
now listening on 3007!
|
||||||
|
Launching puppeteer browser with arguments:
|
||||||
|
[]
|
||||||
|
Using executable: /usr/bin/google-chrome
|
||||||
|
added connection. now 1 sockets connected.
|
||||||
|
added connection. now 2 sockets connected.
|
||||||
|
connection ended
|
||||||
|
removed connection. 1 sockets remaining.
|
||||||
|
connection ended
|
||||||
|
removed connection. 0 sockets remaining.
|
||||||
|
added connection. now 1 sockets connected.
|
||||||
|
/favicon.ico
|
||||||
|
could not resolve /mnt/data/lossless/design.estate/dees-catalog/.nogit/tstest_cache/favicon.ico
|
||||||
|
/test__test.tabs-indicator.browser.ts.js
|
||||||
|
[38;5;231m [38;5;116mTest starting: tabs indicator positioning debug[0m[0m
|
||||||
|
[38;5;231m !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!![0m
|
||||||
|
[38;5;231m Using globalThis.tapPromise[0m
|
||||||
|
[38;5;231m !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!![0m
|
||||||
|
connection ended
|
||||||
|
removed connection. 0 sockets remaining.
|
||||||
|
[38;5;33m=> [0m Stopped [38;5;215mtest/test.tabs-indicator.browser.ts[0m chromium instance and server.
|
||||||
|
[38;5;196m
|
||||||
|
⚠️ Error[0m
|
||||||
|
[38;5;196m Only 0 out of 1 completed![0m
|
||||||
|
[38;5;196m
|
||||||
|
⚠️ Error[0m
|
||||||
|
[38;5;196m The amount of received tests and expectedTests is unequal! Therefore the testfile failed[0m
|
||||||
|
[38;5;196m Summary: -1 passed, 1 failed of 0 tests in 2.7s[0m
|
||||||
|
[38;5;231m
|
||||||
|
📊 Test Summary[0m
|
||||||
|
[38;5;231m┌────────────────────────────────┐[0m
|
||||||
|
[38;5;231m│ Total Files: 1 │[0m
|
||||||
|
[38;5;231m│ Total Tests: 0 │[0m
|
||||||
|
[38;5;113m│ Passed: 0 │[0m
|
||||||
|
[38;5;113m│ Failed: 0 │[0m
|
||||||
|
[38;5;231m│ Duration: 4.2s │[0m
|
||||||
|
[38;5;231m└────────────────────────────────┘[0m
|
||||||
|
[38;5;116m
|
||||||
|
⏱️ Performance Metrics:[0m
|
||||||
|
[38;5;231m Average per test: 0ms[0m
|
||||||
|
[38;5;113m
|
||||||
|
ALL TESTS PASSED! 🎉[0m
|
||||||
|
Exited NOT OK!
|
||||||
|
ELIFECYCLE Test failed. See above for more details.
|
146
test/test.tabs-indicator.browser.ts
Normal file
146
test/test.tabs-indicator.browser.ts
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
import { expect, tap } from '@git.zone/tstest/tapbundle';
|
||||||
|
import * as deesCatalog from '../ts_web/index.js';
|
||||||
|
|
||||||
|
tap.test('tabs indicator positioning - detailed measurements', async () => {
|
||||||
|
// Create tabs element with different length labels
|
||||||
|
const tabsElement = new deesCatalog.DeesAppuiTabs();
|
||||||
|
tabsElement.tabs = [
|
||||||
|
{ key: 'Home', iconName: 'lucide:home', action: () => {} },
|
||||||
|
{ key: 'Analytics Dashboard', iconName: 'lucide:lineChart', action: () => {} },
|
||||||
|
{ key: 'User Settings', iconName: 'lucide:settings', action: () => {} },
|
||||||
|
];
|
||||||
|
|
||||||
|
document.body.appendChild(tabsElement);
|
||||||
|
await tabsElement.updateComplete;
|
||||||
|
|
||||||
|
// Wait for fonts and indicator initialization
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 200));
|
||||||
|
|
||||||
|
// Get all elements
|
||||||
|
const shadowRoot = tabsElement.shadowRoot;
|
||||||
|
const wrapper = shadowRoot.querySelector('.tabs-wrapper') as HTMLElement;
|
||||||
|
const container = shadowRoot.querySelector('.tabsContainer') as HTMLElement;
|
||||||
|
const tabs = shadowRoot.querySelectorAll('.tab');
|
||||||
|
const firstTab = tabs[0] as HTMLElement;
|
||||||
|
const firstContent = firstTab.querySelector('.tab-content') as HTMLElement;
|
||||||
|
const indicator = shadowRoot.querySelector('.tabIndicator') as HTMLElement;
|
||||||
|
|
||||||
|
// Verify all elements exist
|
||||||
|
expect(wrapper).toBeInstanceOf(HTMLElement);
|
||||||
|
expect(container).toBeInstanceOf(HTMLElement);
|
||||||
|
expect(firstTab).toBeInstanceOf(HTMLElement);
|
||||||
|
expect(firstContent).toBeInstanceOf(HTMLElement);
|
||||||
|
expect(indicator).toBeInstanceOf(HTMLElement);
|
||||||
|
|
||||||
|
// Get all measurements
|
||||||
|
const wrapperRect = wrapper.getBoundingClientRect();
|
||||||
|
const containerRect = container.getBoundingClientRect();
|
||||||
|
const tabRect = firstTab.getBoundingClientRect();
|
||||||
|
const contentRect = firstContent.getBoundingClientRect();
|
||||||
|
const indicatorRect = indicator.getBoundingClientRect();
|
||||||
|
|
||||||
|
console.log('\n=== DETAILED MEASUREMENTS ===');
|
||||||
|
console.log('Document body left:', document.body.getBoundingClientRect().left);
|
||||||
|
console.log('Wrapper left:', wrapperRect.left);
|
||||||
|
console.log('Container left:', containerRect.left);
|
||||||
|
console.log('Tab left:', tabRect.left);
|
||||||
|
console.log('Content left:', contentRect.left);
|
||||||
|
console.log('Indicator left (actual):', indicatorRect.left);
|
||||||
|
|
||||||
|
console.log('\n=== RELATIVE POSITIONS ===');
|
||||||
|
console.log('Container padding (container - wrapper):', containerRect.left - wrapperRect.left);
|
||||||
|
console.log('Tab position in container:', tabRect.left - containerRect.left);
|
||||||
|
console.log('Content position in tab:', contentRect.left - tabRect.left);
|
||||||
|
console.log('Content relative to wrapper:', contentRect.left - wrapperRect.left);
|
||||||
|
console.log('Indicator relative to wrapper (actual):', indicatorRect.left - wrapperRect.left);
|
||||||
|
|
||||||
|
console.log('\n=== WIDTHS ===');
|
||||||
|
console.log('Tab width:', tabRect.width);
|
||||||
|
console.log('Content width:', contentRect.width);
|
||||||
|
console.log('Indicator width:', indicatorRect.width);
|
||||||
|
|
||||||
|
console.log('\n=== STYLES (what we set) ===');
|
||||||
|
console.log('Indicator style.left:', indicator.style.left);
|
||||||
|
console.log('Indicator style.width:', indicator.style.width);
|
||||||
|
|
||||||
|
console.log('\n=== CALCULATIONS ===');
|
||||||
|
const expectedIndicatorLeft = contentRect.left - wrapperRect.left - 4; // We subtract 4 to center
|
||||||
|
const expectedIndicatorWidth = contentRect.width + 8; // We add 8 in the code
|
||||||
|
console.log('Expected indicator left:', expectedIndicatorLeft);
|
||||||
|
console.log('Expected indicator width:', expectedIndicatorWidth);
|
||||||
|
console.log('Actual indicator left (from style):', parseFloat(indicator.style.left));
|
||||||
|
console.log('Actual indicator width (from style):', parseFloat(indicator.style.width));
|
||||||
|
|
||||||
|
console.log('\n=== VISUAL ALIGNMENT CHECK ===');
|
||||||
|
const tabCenter = tabRect.left + (tabRect.width / 2);
|
||||||
|
const contentCenter = contentRect.left + (contentRect.width / 2);
|
||||||
|
const indicatorCenter = indicatorRect.left + (indicatorRect.width / 2);
|
||||||
|
|
||||||
|
console.log('Tab center:', tabCenter);
|
||||||
|
console.log('Content center:', contentCenter);
|
||||||
|
console.log('Indicator center:', indicatorCenter);
|
||||||
|
console.log('Content offset from tab center:', contentCenter - tabCenter);
|
||||||
|
console.log('Indicator offset from content center:', indicatorCenter - contentCenter);
|
||||||
|
console.log('Indicator offset from tab center:', indicatorCenter - tabCenter);
|
||||||
|
console.log('---');
|
||||||
|
console.log('Indicator extends left of content by:', contentRect.left - indicatorRect.left);
|
||||||
|
console.log('Indicator extends right of content by:', (indicatorRect.left + indicatorRect.width) - (contentRect.left + contentRect.width));
|
||||||
|
|
||||||
|
// Check if icons are rendering
|
||||||
|
const icon = firstContent.querySelector('dees-icon');
|
||||||
|
console.log('\n=== ICON CHECK ===');
|
||||||
|
console.log('Icon element found:', icon ? 'YES' : 'NO');
|
||||||
|
if (icon) {
|
||||||
|
const iconRect = icon.getBoundingClientRect();
|
||||||
|
console.log('Icon width:', iconRect.width);
|
||||||
|
console.log('Icon height:', iconRect.height);
|
||||||
|
console.log('Icon visible:', iconRect.width > 0 && iconRect.height > 0 ? 'YES' : 'NO');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify indicator is visible
|
||||||
|
expect(indicator.style.opacity).toEqual('1');
|
||||||
|
|
||||||
|
// Verify positioning calculations
|
||||||
|
expect(parseFloat(indicator.style.left)).toBeCloseTo(expectedIndicatorLeft, 1);
|
||||||
|
expect(parseFloat(indicator.style.width)).toBeCloseTo(expectedIndicatorWidth, 1);
|
||||||
|
|
||||||
|
// Verify visual centering on content (should be perfectly centered)
|
||||||
|
expect(Math.abs(indicatorCenter - contentCenter)).toBeLessThan(1);
|
||||||
|
|
||||||
|
document.body.removeChild(tabsElement);
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('tabs indicator should move when tab is clicked', async () => {
|
||||||
|
// Create tabs element
|
||||||
|
const tabsElement = new deesCatalog.DeesAppuiTabs();
|
||||||
|
tabsElement.tabs = [
|
||||||
|
{ key: 'Home', iconName: 'lucide:home', action: () => {} },
|
||||||
|
{ key: 'Analytics', iconName: 'lucide:barChart', action: () => {} },
|
||||||
|
{ key: 'Settings', iconName: 'lucide:settings', action: () => {} },
|
||||||
|
];
|
||||||
|
|
||||||
|
document.body.appendChild(tabsElement);
|
||||||
|
await tabsElement.updateComplete;
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 100));
|
||||||
|
|
||||||
|
const shadowRoot = tabsElement.shadowRoot;
|
||||||
|
const tabs = shadowRoot.querySelectorAll('.tab');
|
||||||
|
const indicator = shadowRoot.querySelector('.tabIndicator') as HTMLElement;
|
||||||
|
|
||||||
|
// Get initial position
|
||||||
|
const initialLeft = parseFloat(indicator.style.left);
|
||||||
|
|
||||||
|
// Click second tab
|
||||||
|
(tabs[1] as HTMLElement).click();
|
||||||
|
await tabsElement.updateComplete;
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 100));
|
||||||
|
|
||||||
|
// Position should have changed
|
||||||
|
const newLeft = parseFloat(indicator.style.left);
|
||||||
|
expect(newLeft).not.toEqual(initialLeft);
|
||||||
|
expect(newLeft).toBeGreaterThan(initialLeft);
|
||||||
|
|
||||||
|
document.body.removeChild(tabsElement);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default tap.start();
|
@ -11,27 +11,46 @@ import {
|
|||||||
|
|
||||||
import * as domtools from '@design.estate/dees-domtools';
|
import * as domtools from '@design.estate/dees-domtools';
|
||||||
import { DeesContextmenu } from './dees-contextmenu.js';
|
import { DeesContextmenu } from './dees-contextmenu.js';
|
||||||
|
import './dees-icon.js';
|
||||||
|
|
||||||
@customElement('dees-appui-activitylog')
|
@customElement('dees-appui-activitylog')
|
||||||
export class DeesAppuiActivitylog extends DeesElement {
|
export class DeesAppuiActivitylog extends DeesElement {
|
||||||
// STATIC
|
// STATIC
|
||||||
public static demo = () => html`<dees-appui-activitylog></dees-appui-activitylog>`;
|
public static demo = () => html`
|
||||||
|
<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">
|
||||||
|
<dees-appui-activitylog></dees-appui-activitylog>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
// INSTANCE
|
// INSTANCE
|
||||||
public static styles = [
|
public static styles = [
|
||||||
cssManager.defaultStyles,
|
cssManager.defaultStyles,
|
||||||
css`
|
css`
|
||||||
:host {
|
:host {
|
||||||
color: ${cssManager.bdTheme('#333', '#fff')};
|
color: ${cssManager.bdTheme('#09090b', '#fafafa')};
|
||||||
position: relative;
|
position: relative;
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 300px;
|
max-width: 320px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: ${cssManager.bdTheme('#f8f8f8', '#111c28')};
|
background: ${cssManager.bdTheme('#fafafa', '#0a0a0a')};
|
||||||
font-family: 'Intel One Mono', sans-serif;
|
font-family: 'Geist Mono', monospace;
|
||||||
border-left: 1px solid ${cssManager.bdTheme('#e0e0e0', '#202020')};
|
border-left: 1px solid ${cssManager.bdTheme('#e5e7eb', '#27272a')};
|
||||||
cursor: default;
|
cursor: default;
|
||||||
|
box-shadow: ${cssManager.bdTheme(
|
||||||
|
'-4px 0 12px rgba(0, 0, 0, 0.02)',
|
||||||
|
'-4px 0 12px rgba(0, 0, 0, 0.2)'
|
||||||
|
)};
|
||||||
}
|
}
|
||||||
.maincontainer {
|
.maincontainer {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -44,108 +63,265 @@ export class DeesAppuiActivitylog extends DeesElement {
|
|||||||
.topbar {
|
.topbar {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
height: 32px;
|
height: 40px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0px 12px 0px 12px;
|
padding: 0px 16px;
|
||||||
background: ${cssManager.bdTheme('#ffffff', '#0e151f')};
|
background: ${cssManager.bdTheme('#ffffff', '#09090b')};
|
||||||
border-bottom: 1px solid ${cssManager.bdTheme('#e0e0e0', '#202020')};
|
border-bottom: 1px solid ${cssManager.bdTheme('#e5e7eb', '#27272a')};
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.topbar .heading {
|
.topbar .heading {
|
||||||
text-align: left;
|
font-weight: 600;
|
||||||
line-height: 24px;
|
|
||||||
padding-top: 8px;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-family: 'Geist Sans', sans-serif;
|
font-family: 'Geist Sans', sans-serif;
|
||||||
color: ${cssManager.bdTheme('#666', '#ccc')};
|
color: ${cssManager.bdTheme('#09090b', '#fafafa')};
|
||||||
}
|
}
|
||||||
|
|
||||||
.activityContainer {
|
.activityContainer {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 32px;
|
top: 40px;
|
||||||
bottom: 40px;
|
bottom: 48px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 8px 0px;
|
padding: 12px 0px;
|
||||||
overflow-y: scroll;
|
overflow-y: auto;
|
||||||
|
scrollbar-width: thin;
|
||||||
|
scrollbar-color: ${cssManager.bdTheme('#e5e7eb', '#27272a')} transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activityContainer::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activityContainer::-webkit-scrollbar-track {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activityContainer::-webkit-scrollbar-thumb {
|
||||||
|
background: ${cssManager.bdTheme('#e5e7eb', '#27272a')};
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activityContainer::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: ${cssManager.bdTheme('#d4d4d8', '#3f3f46')};
|
||||||
}
|
}
|
||||||
|
|
||||||
.streamingIndicator {
|
.streamingIndicator {
|
||||||
font-size: 12px;
|
font-size: 11px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding-top: 16px;
|
padding: 16px;
|
||||||
color: ${cssManager.bdTheme('#666', '#888')}
|
color: ${cssManager.bdTheme('#71717a', '#71717a')};
|
||||||
|
font-family: 'Geist Sans', sans-serif;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
font-weight: 500;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.streamingIndicator::before {
|
||||||
|
content: '';
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
background: ${cssManager.bdTheme('#3b82f6', '#3b82f6')};
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: pulse 2s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0%, 100% { opacity: 0.4; transform: scale(0.8); }
|
||||||
|
50% { opacity: 1; transform: scale(1.2); }
|
||||||
}
|
}
|
||||||
|
|
||||||
.streamingIndicator.bottom {
|
.streamingIndicator.bottom {
|
||||||
padding-top: 0px;
|
padding-top: 8px;
|
||||||
padding-bottom: 16px;
|
padding-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.activityentry {
|
.activityentry {
|
||||||
min-height: 30px;
|
min-height: 36px;
|
||||||
font-size: 12px;
|
font-size: 13px;
|
||||||
padding: 8px 16px;
|
padding: 10px 16px;
|
||||||
border-bottom: 1px dotted ${cssManager.bdTheme('#00000020', '#ffffff20')};
|
border-bottom: 1px solid ${cssManager.bdTheme('#f4f4f5', '#18181b')};
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
line-height: 1.4;
|
||||||
|
animation: fadeIn 0.3s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-4px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.activityentry:last-of-type {
|
.activityentry:last-of-type {
|
||||||
border-bottom: 1px solid transparent;
|
border-bottom: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.activityentry:hover {
|
.activityentry:hover {
|
||||||
background: ${cssManager.bdTheme('#00000005', '#00000080')};
|
background: ${cssManager.bdTheme('#f4f4f5', '#18181b')};
|
||||||
}
|
}
|
||||||
|
|
||||||
.timestamp {
|
.timestamp {
|
||||||
color: ${cssManager.bdTheme('#e57373', '#ff8787')};
|
color: ${cssManager.bdTheme('#71717a', '#71717a')};
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 12px;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
flex-shrink: 0;
|
||||||
|
min-width: 45px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-icon {
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: ${cssManager.bdTheme('#f4f4f5', '#18181b')};
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-icon.login {
|
||||||
|
background: ${cssManager.bdTheme('rgba(34, 197, 94, 0.1)', 'rgba(34, 197, 94, 0.1)')};
|
||||||
|
color: ${cssManager.bdTheme('#16a34a', '#22c55e')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-icon.logout {
|
||||||
|
background: ${cssManager.bdTheme('rgba(239, 68, 68, 0.1)', 'rgba(239, 68, 68, 0.1)')};
|
||||||
|
color: ${cssManager.bdTheme('#dc2626', '#ef4444')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-icon.view {
|
||||||
|
background: ${cssManager.bdTheme('rgba(59, 130, 246, 0.1)', 'rgba(59, 130, 246, 0.1)')};
|
||||||
|
color: ${cssManager.bdTheme('#2563eb', '#3b82f6')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-icon.create {
|
||||||
|
background: ${cssManager.bdTheme('rgba(168, 85, 247, 0.1)', 'rgba(168, 85, 247, 0.1)')};
|
||||||
|
color: ${cssManager.bdTheme('#9333ea', '#a855f7')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-icon.update {
|
||||||
|
background: ${cssManager.bdTheme('rgba(251, 146, 60, 0.1)', 'rgba(251, 146, 60, 0.1)')};
|
||||||
|
color: ${cssManager.bdTheme('#ea580c', '#fb923c')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-text {
|
||||||
|
flex: 1;
|
||||||
|
color: ${cssManager.bdTheme('#18181b', '#e4e4e7')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-user {
|
||||||
|
font-weight: 600;
|
||||||
|
color: ${cssManager.bdTheme('#09090b', '#fafafa')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-separator {
|
||||||
|
padding: 12px 16px 8px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
color: ${cssManager.bdTheme('#71717a', '#71717a')};
|
||||||
|
background: ${cssManager.bdTheme('#f9fafb', '#09090b')};
|
||||||
|
border-bottom: 1px solid ${cssManager.bdTheme('#f4f4f5', '#18181b')};
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.searchbox {
|
.searchbox {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0px;
|
bottom: 0px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 40px;
|
height: 48px;
|
||||||
background: ${cssManager.bdTheme('#ffffff', '#0e151f')};
|
background: ${cssManager.bdTheme('#ffffff', '#09090b')};
|
||||||
border-top: 1px solid ${cssManager.bdTheme('#e0e0e0', '#202020')};
|
border-top: 1px solid ${cssManager.bdTheme('#e5e7eb', '#27272a')};
|
||||||
|
padding: 8px;
|
||||||
}
|
}
|
||||||
.searchbox input {
|
|
||||||
color: ${cssManager.bdTheme('#333', '#fff')};
|
.search-wrapper {
|
||||||
background: none;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 40px;
|
height: 32px;
|
||||||
line-height: 32px;
|
}
|
||||||
border: none;
|
|
||||||
padding: 4px 12px;
|
.search-icon {
|
||||||
font-family: 'Intel One Mono', sans-serif;
|
position: absolute;
|
||||||
|
left: 10px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
color: ${cssManager.bdTheme('#71717a', '#71717a')};
|
||||||
|
font-size: 14px;
|
||||||
|
pointer-events: none;
|
||||||
|
transition: color 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchbox input {
|
||||||
|
color: ${cssManager.bdTheme('#09090b', '#fafafa')};
|
||||||
|
background: ${cssManager.bdTheme('#f4f4f5', '#18181b')};
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border: 1px solid ${cssManager.bdTheme('#e5e7eb', '#27272a')};
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 0 12px 0 36px;
|
||||||
|
font-family: 'Geist Sans', sans-serif;
|
||||||
|
font-size: 13px;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchbox input::placeholder {
|
||||||
|
color: ${cssManager.bdTheme('#71717a', '#71717a')};
|
||||||
}
|
}
|
||||||
|
|
||||||
.searchbox input:focus {
|
.searchbox input:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
|
border-color: ${cssManager.bdTheme('#3b82f6', '#3b82f6')};
|
||||||
|
box-shadow: 0 0 0 3px ${cssManager.bdTheme('rgba(59, 130, 246, 0.1)', 'rgba(59, 130, 246, 0.1)')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchbox input:focus ~ .search-icon,
|
||||||
|
.search-wrapper:has(input:focus) .search-icon {
|
||||||
|
color: ${cssManager.bdTheme('#3b82f6', '#3b82f6')};
|
||||||
}
|
}
|
||||||
|
|
||||||
.bottomShadow {
|
.bottomShadow {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 32px;
|
height: 24px;
|
||||||
bottom: 40px;
|
bottom: 48px;
|
||||||
background: ${cssManager.bdTheme(
|
background: ${cssManager.bdTheme(
|
||||||
'linear-gradient(180deg, #f8f8f800 0%, #ffffff 100%)',
|
'linear-gradient(180deg, transparent 0%, #fafafa 100%)',
|
||||||
'linear-gradient(180deg, #111c2800 0%, #0e151f 100%)'
|
'linear-gradient(180deg, transparent 0%, #0a0a0a 100%)'
|
||||||
)};
|
)};
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.topShadow {
|
.topShadow {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 32px;
|
height: 24px;
|
||||||
top: 32px;
|
top: 40px;
|
||||||
background: ${cssManager.bdTheme(
|
background: ${cssManager.bdTheme(
|
||||||
'linear-gradient(0deg, #f8f8f800 0%, #ffffff 100%)',
|
'linear-gradient(0deg, transparent 0%, #fafafa 100%)',
|
||||||
'linear-gradient(0deg, #111c2800 0%, #0e151f 100%)'
|
'linear-gradient(0deg, transparent 0%, #0a0a0a 100%)'
|
||||||
)};
|
)};
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
@ -159,86 +335,174 @@ export class DeesAppuiActivitylog extends DeesElement {
|
|||||||
<div class="heading">Activity Log</div>
|
<div class="heading">Activity Log</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="activityContainer">
|
<div class="activityContainer">
|
||||||
<div class="streamingIndicator">streaming...</div>
|
<div class="streamingIndicator">Live Updates</div>
|
||||||
|
|
||||||
|
<div class="date-separator">Today</div>
|
||||||
|
|
||||||
<div class="activityentry" @contextmenu=${async eventArg => {
|
<div class="activityentry" @contextmenu=${async eventArg => {
|
||||||
DeesContextmenu.openContextMenuWithOptions(eventArg, [
|
DeesContextmenu.openContextMenuWithOptions(eventArg, [
|
||||||
{
|
{
|
||||||
name: 'app settings',
|
name: 'Copy activity',
|
||||||
action: async () => {},
|
action: async () => {},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'account settings',
|
name: 'View details',
|
||||||
action: async () => {},
|
action: async () => {},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'logout',
|
name: 'Filter by user',
|
||||||
action: async () => {},
|
action: async () => {},
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
}}>
|
}}>
|
||||||
<span class="timestamp">22:01:</span> Max Mustermann logged in
|
<span class="timestamp">22:20</span>
|
||||||
|
<div class="activity-icon logout">
|
||||||
|
<dees-icon .icon=${'lucide:logOut'}></dees-icon>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="activity-text">
|
||||||
|
<span class="activity-user">Max Mustermann</span> logged out
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="activityentry">
|
<div class="activityentry">
|
||||||
<span class="timestamp">22:02:</span> Max Mustermann viewed an invoice
|
<span class="timestamp">22:19</span>
|
||||||
|
<div class="activity-icon update">
|
||||||
|
<dees-icon .icon=${'lucide:checkCircle'}></dees-icon>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="activity-text">
|
||||||
|
<span class="activity-user">Max Mustermann</span> approved a payment
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="activityentry">
|
<div class="activityentry">
|
||||||
<span class="timestamp">22:03:</span> Max Mustermann added a new contact
|
<span class="timestamp">22:18</span>
|
||||||
|
<div class="activity-icon view">
|
||||||
|
<dees-icon .icon=${'lucide:archive'}></dees-icon>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="activity-text">
|
||||||
|
<span class="activity-user">Max Mustermann</span> archived an invoice
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="activityentry">
|
<div class="activityentry">
|
||||||
<span class="timestamp">22:04:</span> Max Mustermann updated account settings
|
<span class="timestamp">22:17</span>
|
||||||
|
<div class="activity-icon login">
|
||||||
|
<dees-icon .icon=${'lucide:logIn'}></dees-icon>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="activity-text">
|
||||||
|
<span class="activity-user">Max Mustermann</span> logged in
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="activityentry">
|
<div class="activityentry">
|
||||||
<span class="timestamp">22:05:</span> Max Mustermann logged out
|
<span class="timestamp">22:16</span>
|
||||||
|
<div class="activity-icon logout">
|
||||||
|
<dees-icon .icon=${'lucide:logOut'}></dees-icon>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="activity-text">
|
||||||
|
<span class="activity-user">Max Mustermann</span> logged out
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="activityentry">
|
<div class="activityentry">
|
||||||
<span class="timestamp">22:06:</span> Max Mustermann logged in
|
<span class="timestamp">22:15</span>
|
||||||
|
<div class="activity-icon update">
|
||||||
|
<dees-icon .icon=${'lucide:key'}></dees-icon>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="activity-text">
|
||||||
|
<span class="activity-user">Max Mustermann</span> changed password
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="activityentry">
|
<div class="activityentry">
|
||||||
<span class="timestamp">22:07:</span> Max Mustermann created a new invoice
|
<span class="timestamp">22:14</span>
|
||||||
|
<div class="activity-icon create">
|
||||||
|
<dees-icon .icon=${'lucide:userPlus'}></dees-icon>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="activity-text">
|
||||||
|
<span class="activity-user">Max Mustermann</span> added a new user
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="activityentry">
|
<div class="activityentry">
|
||||||
<span class="timestamp">22:08:</span> Max Mustermann sent an invoice
|
<span class="timestamp">22:13</span>
|
||||||
|
<div class="activity-icon view">
|
||||||
|
<dees-icon .icon=${'lucide:messageCircle'}></dees-icon>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="activity-text">
|
||||||
|
<span class="activity-user">Max Mustermann</span> contacted support
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="date-separator">Yesterday</div>
|
||||||
|
|
||||||
<div class="activityentry">
|
<div class="activityentry">
|
||||||
<span class="timestamp">22:09:</span> Max Mustermann viewed reports
|
<span class="timestamp">18:45</span>
|
||||||
|
<div class="activity-icon update">
|
||||||
|
<dees-icon .icon=${'lucide:trash2'}></dees-icon>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="activity-text">
|
||||||
|
<span class="activity-user">Max Mustermann</span> deleted an invoice
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="activityentry">
|
<div class="activityentry">
|
||||||
<span class="timestamp">22:10:</span> Max Mustermann logged out
|
<span class="timestamp">17:30</span>
|
||||||
|
<div class="activity-icon login">
|
||||||
|
<dees-icon .icon=${'lucide:logIn'}></dees-icon>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="activity-text">
|
||||||
|
<span class="activity-user">Max Mustermann</span> logged in
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="activityentry">
|
<div class="activityentry">
|
||||||
<span class="timestamp">22:11:</span> Max Mustermann logged in
|
<span class="timestamp">16:15</span>
|
||||||
|
<div class="activity-icon logout">
|
||||||
|
<dees-icon .icon=${'lucide:logOut'}></dees-icon>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="activity-text">
|
||||||
|
<span class="activity-user">Max Mustermann</span> logged out
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="activityentry">
|
<div class="activityentry">
|
||||||
<span class="timestamp">22:12:</span> Max Mustermann deleted an invoice
|
<span class="timestamp">14:20</span>
|
||||||
|
<div class="activity-icon view">
|
||||||
|
<dees-icon .icon=${'lucide:barChart'}></dees-icon>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="activity-text">
|
||||||
|
<span class="activity-user">Max Mustermann</span> viewed reports
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="activityentry">
|
<div class="activityentry">
|
||||||
<span class="timestamp">22:13:</span> Max Mustermann contacted support
|
<span class="timestamp">13:45</span>
|
||||||
|
<div class="activity-icon create">
|
||||||
|
<dees-icon .icon=${'lucide:send'}></dees-icon>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="activity-text">
|
||||||
|
<span class="activity-user">Max Mustermann</span> sent an invoice
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="activityentry">
|
<div class="activityentry">
|
||||||
<span class="timestamp">22:14:</span> Max Mustermann added a new user
|
<span class="timestamp">13:30</span>
|
||||||
|
<div class="activity-icon create">
|
||||||
|
<dees-icon .icon=${'lucide:filePlus'}></dees-icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="activityentry">
|
<div class="activity-text">
|
||||||
<span class="timestamp">22:15:</span> Max Mustermann changed password
|
<span class="activity-user">Max Mustermann</span> created a new invoice
|
||||||
</div>
|
</div>
|
||||||
<div class="activityentry">
|
|
||||||
<span class="timestamp">22:16:</span> Max Mustermann logged out
|
|
||||||
</div>
|
</div>
|
||||||
<div class="activityentry">
|
|
||||||
<span class="timestamp">22:17:</span> Max Mustermann logged in
|
<div class="streamingIndicator bottom">Loading History</div>
|
||||||
</div>
|
|
||||||
<div class="activityentry">
|
|
||||||
<span class="timestamp">22:18:</span> Max Mustermann archived an invoice
|
|
||||||
</div>
|
|
||||||
<div class="activityentry">
|
|
||||||
<span class="timestamp">22:19:</span> Max Mustermann approved a payment
|
|
||||||
</div>
|
|
||||||
<div class="activityentry">
|
|
||||||
<span class="timestamp">22:20:</span> Max Mustermann logged out
|
|
||||||
</div>
|
|
||||||
<div class="streamingIndicator bottom">loading more...</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="searchbox">
|
<div class="searchbox">
|
||||||
<input type="text" placeholder="Search" />
|
<div class="search-wrapper">
|
||||||
|
<dees-icon class="search-icon" .icon=${'lucide:search'}></dees-icon>
|
||||||
|
<input type="text" placeholder="Search activities, users..." />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="topShadow"></div>
|
<div class="topShadow"></div>
|
||||||
<div class="bottomShadow"></div>
|
<div class="bottomShadow"></div>
|
||||||
|
@ -65,10 +65,10 @@ export const demoFunc = () => {
|
|||||||
|
|
||||||
// Main menu tabs (left sidebar)
|
// Main menu tabs (left sidebar)
|
||||||
const mainMenuTabs: ITab[] = [
|
const mainMenuTabs: ITab[] = [
|
||||||
{ key: 'dashboard', iconName: 'home', action: () => console.log('Dashboard selected') },
|
{ key: 'dashboard', iconName: 'lucide:home', action: () => console.log('Dashboard selected') },
|
||||||
{ key: 'projects', iconName: 'folder', action: () => console.log('Projects selected') },
|
{ key: 'projects', iconName: 'lucide:folder', action: () => console.log('Projects selected') },
|
||||||
{ key: 'analytics', iconName: 'lineChart', action: () => console.log('Analytics selected') },
|
{ key: 'analytics', iconName: 'lucide:lineChart', action: () => console.log('Analytics selected') },
|
||||||
{ key: 'settings', iconName: 'settings', action: () => console.log('Settings selected') },
|
{ key: 'settings', iconName: 'lucide:settings', action: () => console.log('Settings selected') },
|
||||||
];
|
];
|
||||||
|
|
||||||
// Selector options (second sidebar)
|
// Selector options (second sidebar)
|
||||||
@ -83,9 +83,9 @@ export const demoFunc = () => {
|
|||||||
|
|
||||||
// Main content tabs
|
// Main content tabs
|
||||||
const mainContentTabs: ITab[] = [
|
const mainContentTabs: ITab[] = [
|
||||||
{ key: 'Details', iconName: 'file', action: () => console.log('Details tab') },
|
{ key: 'Details', iconName: 'lucide:file', action: () => console.log('Details tab') },
|
||||||
{ key: 'Logs', iconName: 'list', action: () => console.log('Logs tab') },
|
{ key: 'Logs', iconName: 'lucide:list', action: () => console.log('Logs tab') },
|
||||||
{ key: 'Metrics', iconName: 'lineChart', action: () => console.log('Metrics tab') },
|
{ key: 'Metrics', iconName: 'lucide:lineChart', action: () => console.log('Metrics tab') },
|
||||||
];
|
];
|
||||||
|
|
||||||
// Profile menu items
|
// Profile menu items
|
||||||
|
@ -19,9 +19,9 @@ export class DeesAppuiMaincontent extends DeesElement {
|
|||||||
public static demo = () => html`
|
public static demo = () => html`
|
||||||
<dees-appui-maincontent
|
<dees-appui-maincontent
|
||||||
.tabs=${[
|
.tabs=${[
|
||||||
{ key: 'Overview', iconName: 'home', action: () => console.log('Overview') },
|
{ key: 'Overview', iconName: 'lucide:home', action: () => console.log('Overview') },
|
||||||
{ key: 'Details', iconName: 'file', action: () => console.log('Details') },
|
{ key: 'Details', iconName: 'lucide:file', action: () => console.log('Details') },
|
||||||
{ key: 'Settings', iconName: 'cog', action: () => console.log('Settings') },
|
{ key: 'Settings', iconName: 'lucide:settings', action: () => console.log('Settings') },
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<div slot="content" style="padding: 40px; color: #ccc;">
|
<div slot="content" style="padding: 40px; color: #ccc;">
|
||||||
|
@ -22,10 +22,10 @@ export class DeesAppuiMainmenu extends DeesElement {
|
|||||||
public static demo = () => html`
|
public static demo = () => html`
|
||||||
<dees-appui-mainmenu
|
<dees-appui-mainmenu
|
||||||
.tabs=${[
|
.tabs=${[
|
||||||
{ key: 'Dashboard', iconName: 'home', action: () => console.log('Dashboard') },
|
{ key: 'Dashboard', iconName: 'lucide:home', action: () => console.log('Dashboard') },
|
||||||
{ key: 'Projects', iconName: 'folder', action: () => console.log('Projects') },
|
{ key: 'Projects', iconName: 'lucide:folder', action: () => console.log('Projects') },
|
||||||
{ key: 'Analytics', iconName: 'lineChart', action: () => console.log('Analytics') },
|
{ key: 'Analytics', iconName: 'lucide:lineChart', action: () => console.log('Analytics') },
|
||||||
{ key: 'Settings', iconName: 'settings', action: () => console.log('Settings') },
|
{ key: 'Settings', iconName: 'lucide:settings', action: () => console.log('Settings') },
|
||||||
]}
|
]}
|
||||||
></dees-appui-mainmenu>
|
></dees-appui-mainmenu>
|
||||||
`;
|
`;
|
||||||
@ -35,7 +35,7 @@ export class DeesAppuiMainmenu extends DeesElement {
|
|||||||
// INSTANCE
|
// INSTANCE
|
||||||
@property({ type: Array })
|
@property({ type: Array })
|
||||||
public tabs: interfaces.ITab[] = [
|
public tabs: interfaces.ITab[] = [
|
||||||
{ key: '⚠️ Please set tabs', iconName: 'alertTriangle', action: () => console.warn('No tabs configured for mainmenu') },
|
{ key: '⚠️ Please set tabs', iconName: 'lucide:alertTriangle', action: () => console.warn('No tabs configured for mainmenu') },
|
||||||
];
|
];
|
||||||
|
|
||||||
@property()
|
@property()
|
||||||
@ -112,7 +112,7 @@ export class DeesAppuiMainmenu extends DeesElement {
|
|||||||
this.updateTab(tabArg);
|
this.updateTab(tabArg);
|
||||||
}}"
|
}}"
|
||||||
>
|
>
|
||||||
<dees-icon .icon="${tabArg.iconName ? `lucide:${tabArg.iconName}` : ''}"></dees-icon>
|
<dees-icon .icon="${tabArg.iconName || ''}"></dees-icon>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
})}
|
})}
|
||||||
|
@ -14,16 +14,95 @@ import * as domtools from '@design.estate/dees-domtools';
|
|||||||
|
|
||||||
@customElement('dees-appui-tabs')
|
@customElement('dees-appui-tabs')
|
||||||
export class DeesAppuiTabs extends DeesElement {
|
export class DeesAppuiTabs extends DeesElement {
|
||||||
public static demo = () => html`
|
public static demo = () => {
|
||||||
<dees-appui-tabs
|
const horizontalTabs: interfaces.ITab[] = [
|
||||||
.tabs=${[
|
{ key: 'Home', iconName: 'lucide:home', action: () => console.log('Home clicked') },
|
||||||
{ key: 'Tab 1', action: () => console.log('Tab 1 clicked') },
|
{ key: 'Analytics Dashboard', iconName: 'lucide:lineChart', action: () => console.log('Analytics clicked') },
|
||||||
{ key: 'Tab 2', action: () => console.log('Tab 2 clicked') },
|
{ key: 'Reports', iconName: 'lucide:fileText', action: () => console.log('Reports clicked') },
|
||||||
{ key: 'Tab 3', action: () => console.log('Tab 3 clicked') },
|
{ key: 'User Settings', iconName: 'lucide:settings', action: () => console.log('Settings clicked') },
|
||||||
]}
|
{ key: 'Help', iconName: 'lucide:helpCircle', action: () => console.log('Help clicked') },
|
||||||
></dees-appui-tabs>
|
];
|
||||||
|
|
||||||
|
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,
|
||||||
@ -50,148 +129,217 @@ export class DeesAppuiTabs extends DeesElement {
|
|||||||
|
|
||||||
.tabs-wrapper {
|
.tabs-wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
background: ${cssManager.bdTheme('#f5f5f5', '#000000')};
|
}
|
||||||
height: 52px;
|
|
||||||
|
.tabs-wrapper.horizontal-wrapper {
|
||||||
|
border-bottom: 1px solid ${cssManager.bdTheme('#e5e7eb', '#27272a')};
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabsContainer {
|
.tabsContainer {
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabsContainer.horizontal {
|
.tabsContainer.horizontal {
|
||||||
display: grid;
|
display: flex;
|
||||||
padding-top: 20px;
|
align-items: center;
|
||||||
padding-bottom: 0px;
|
|
||||||
margin-left: 24px;
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
overflow-x: auto;
|
||||||
|
scrollbar-width: none;
|
||||||
|
height: 48px;
|
||||||
|
padding: 0 16px;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabsContainer.horizontal::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabsContainer.vertical {
|
.tabsContainer.vertical {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
padding: 20px;
|
padding: 8px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
gap: 2px;
|
||||||
|
position: relative;
|
||||||
|
background: ${cssManager.bdTheme('#f9fafb', '#18181b')};
|
||||||
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab {
|
.tab {
|
||||||
color: ${cssManager.bdTheme('#666', '#a0a0a0')};
|
color: ${cssManager.bdTheme('#71717a', '#71717a')};
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
cursor: default;
|
cursor: pointer;
|
||||||
transition: color 0.1s;
|
transition: color 0.15s ease;
|
||||||
|
font-weight: 500;
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.horizontal .tab {
|
.horizontal .tab {
|
||||||
margin-right: 30px;
|
padding: 0 16px;
|
||||||
padding-top: 4px;
|
height: 100%;
|
||||||
padding-bottom: 12px;
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
position: relative;
|
||||||
|
border-radius: 6px 6px 0 0;
|
||||||
|
transition: background-color 0.15s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vertical .tab {
|
.horizontal .tab:not(:last-child)::after {
|
||||||
padding: 12px 16px;
|
content: '';
|
||||||
margin-bottom: 4px;
|
position: absolute;
|
||||||
border-radius: 4px;
|
right: -2px;
|
||||||
width: 100%;
|
top: 50%;
|
||||||
display: flex;
|
transform: translateY(-50%);
|
||||||
|
height: 20px;
|
||||||
|
width: 1px;
|
||||||
|
background: ${cssManager.bdTheme('#e5e7eb', '#27272a')};
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.horizontal .tab .tab-content {
|
||||||
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vertical .tab {
|
||||||
|
padding: 10px 16px;
|
||||||
|
border-radius: 6px;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
.tab:hover {
|
.tab:hover {
|
||||||
color: ${cssManager.bdTheme('#000', '#ffffff')};
|
color: ${cssManager.bdTheme('#09090b', '#fafafa')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.horizontal .tab:hover {
|
||||||
|
background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.03)', 'rgba(255, 255, 255, 0.03)')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.horizontal .tab:hover::after,
|
||||||
|
.horizontal .tab:hover + .tab::after {
|
||||||
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vertical .tab:hover {
|
.vertical .tab:hover {
|
||||||
background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.05)', 'rgba(255, 255, 255, 0.05)')};
|
background: ${cssManager.bdTheme('rgba(244, 244, 245, 0.5)', 'rgba(39, 39, 42, 0.5)')};
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab.selectedTab {
|
.horizontal .tab.selectedTab {
|
||||||
color: ${cssManager.bdTheme('#333', '#e0e0e0')};
|
color: ${cssManager.bdTheme('#09090b', '#fafafa')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.horizontal .tab.selectedTab::after,
|
||||||
|
.horizontal .tab.selectedTab + .tab::after {
|
||||||
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vertical .tab.selectedTab {
|
.vertical .tab.selectedTab {
|
||||||
background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.1)', 'rgba(255, 255, 255, 0.1)')};
|
color: ${cssManager.bdTheme('#09090b', '#fafafa')};
|
||||||
color: ${cssManager.bdTheme('#000', '#ffffff')};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab dees-icon {
|
.tab dees-icon {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabs-wrapper .tabIndicator {
|
.tabIndicator {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 0;
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
left: 40px;
|
opacity: 0;
|
||||||
bottom: 0px;
|
|
||||||
height: 40px;
|
|
||||||
width: 40px;
|
|
||||||
background: ${cssManager.bdTheme('#ffffff', '#161616')};
|
|
||||||
transition: all 0.1s;
|
|
||||||
border-top-left-radius: 8px;
|
|
||||||
border-top-right-radius: 8px;
|
|
||||||
border-top: 1px solid ${cssManager.bdTheme('#e0e0e0', '#444444')};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.vertical .tabIndicator {
|
.tabIndicator.no-transition {
|
||||||
display: none;
|
transition: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs-wrapper .tabIndicator {
|
||||||
|
height: 3px;
|
||||||
|
bottom: 0;
|
||||||
|
background: ${cssManager.bdTheme('#3b82f6', '#3b82f6')};
|
||||||
|
border-radius: 3px 3px 0 0;
|
||||||
|
z-index: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-wrapper {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-wrapper .tabIndicator {
|
||||||
|
left: 8px;
|
||||||
|
right: 8px;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: ${cssManager.bdTheme('#ffffff', '#27272a')};
|
||||||
|
z-index: 1;
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
margin-top: 20px;
|
padding: 32px 24px;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
|
|
||||||
public render(): TemplateResult {
|
public render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
${this.tabStyle === 'horizontal' ? html`
|
${this.renderTabsWrapper()}
|
||||||
<style>
|
|
||||||
.tabsContainer.horizontal {
|
|
||||||
grid-template-columns: repeat(${this.tabs.length}, min-content);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<div class="tabs-wrapper">
|
|
||||||
<div class="tabsContainer horizontal">
|
|
||||||
${this.tabs.map((tabArg) => {
|
|
||||||
return html`
|
|
||||||
<div
|
|
||||||
class="tab ${tabArg === this.selectedTab ? 'selectedTab' : ''}"
|
|
||||||
@click="${() => this.selectTab(tabArg)}"
|
|
||||||
>
|
|
||||||
${tabArg.key}
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
${this.showTabIndicator ? html`
|
|
||||||
<div class="tabIndicator"></div>
|
|
||||||
` : ''}
|
|
||||||
</div>
|
|
||||||
` : html`
|
|
||||||
<div class="tabsContainer vertical">
|
|
||||||
${this.tabs.map((tabArg) => {
|
|
||||||
return html`
|
|
||||||
<div
|
|
||||||
class="tab ${tabArg === this.selectedTab ? 'selectedTab' : ''}"
|
|
||||||
@click="${() => this.selectTab(tabArg)}"
|
|
||||||
>
|
|
||||||
${tabArg.iconName ? html`<dees-icon .iconName=${tabArg.iconName}></dees-icon>` : ''}
|
|
||||||
${tabArg.key}
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
`}
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private renderTabsWrapper(): TemplateResult {
|
||||||
|
const isHorizontal = this.tabStyle === 'horizontal';
|
||||||
|
const wrapperClass = isHorizontal ? 'tabs-wrapper horizontal-wrapper' : 'vertical-wrapper';
|
||||||
|
const containerClass = `tabsContainer ${this.tabStyle}`;
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<div class="${wrapperClass}">
|
||||||
|
<div class="${containerClass}">
|
||||||
|
${this.tabs.map(tab => this.renderTab(tab, isHorizontal))}
|
||||||
|
</div>
|
||||||
|
${this.showTabIndicator ? html`<div class="tabIndicator"></div>` : ''}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderTab(tab: interfaces.ITab, isHorizontal: boolean): TemplateResult {
|
||||||
|
const isSelected = tab === this.selectedTab;
|
||||||
|
const classes = `tab ${isSelected ? 'selectedTab' : ''}`;
|
||||||
|
|
||||||
|
const content = isHorizontal ? html`
|
||||||
|
<span class="tab-content">
|
||||||
|
${this.renderTabIcon(tab)}
|
||||||
|
${tab.key}
|
||||||
|
</span>
|
||||||
|
` : html`
|
||||||
|
${this.renderTabIcon(tab)}
|
||||||
|
${tab.key}
|
||||||
|
`;
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<div
|
||||||
|
class="${classes}"
|
||||||
|
@click="${() => this.selectTab(tab)}"
|
||||||
|
>
|
||||||
|
${content}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderTabIcon(tab: interfaces.ITab): TemplateResult | '' {
|
||||||
|
return tab.iconName ? html`<dees-icon .icon=${tab.iconName}></dees-icon>` : '';
|
||||||
|
}
|
||||||
|
|
||||||
private selectTab(tabArg: interfaces.ITab) {
|
private selectTab(tabArg: interfaces.ITab) {
|
||||||
this.selectedTab = tabArg;
|
this.selectedTab = tabArg;
|
||||||
this.updateTabIndicator();
|
|
||||||
tabArg.action();
|
tabArg.action();
|
||||||
|
|
||||||
// Emit tab-select event
|
// Emit tab-select event
|
||||||
@ -202,31 +350,6 @@ export class DeesAppuiTabs extends DeesElement {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* updates the indicator position
|
|
||||||
*/
|
|
||||||
private updateTabIndicator() {
|
|
||||||
if (!this.showTabIndicator || this.tabStyle !== 'horizontal' || !this.selectedTab) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const tabIndex = this.tabs.indexOf(this.selectedTab);
|
|
||||||
const selectedTabElement: HTMLElement = this.shadowRoot.querySelector(
|
|
||||||
`.tabs-wrapper .tabsContainer .tab:nth-child(${tabIndex + 1})`
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!selectedTabElement) return;
|
|
||||||
|
|
||||||
const tabsContainer: HTMLElement = this.shadowRoot.querySelector('.tabs-wrapper .tabsContainer');
|
|
||||||
const marginLeft = parseInt(window.getComputedStyle(tabsContainer).getPropertyValue("margin-left"));
|
|
||||||
const tabIndicator: HTMLElement = this.shadowRoot.querySelector('.tabs-wrapper .tabIndicator');
|
|
||||||
|
|
||||||
if (tabIndicator) {
|
|
||||||
tabIndicator.style.width = selectedTabElement.clientWidth + 24 + 'px';
|
|
||||||
tabIndicator.style.left = selectedTabElement.offsetLeft + marginLeft - 12 + 'px';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
if (this.tabs && this.tabs.length > 0) {
|
if (this.tabs && this.tabs.length > 0) {
|
||||||
this.selectTab(this.tabs[0]);
|
this.selectTab(this.tabs[0]);
|
||||||
@ -241,7 +364,88 @@ export class DeesAppuiTabs extends DeesElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (changedProperties.has('selectedTab') || changedProperties.has('tabs')) {
|
if (changedProperties.has('selectedTab') || changedProperties.has('tabs')) {
|
||||||
this.updateTabIndicator();
|
await this.updateComplete;
|
||||||
|
// Wait for fonts to load on first update
|
||||||
|
if (!this.indicatorInitialized && document.fonts) {
|
||||||
|
await document.fonts.ready;
|
||||||
}
|
}
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
this.updateTabIndicator();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private indicatorInitialized = false;
|
||||||
|
|
||||||
|
private updateTabIndicator() {
|
||||||
|
if (!this.shouldShowIndicator()) return;
|
||||||
|
|
||||||
|
const selectedTabElement = this.getSelectedTabElement();
|
||||||
|
if (!selectedTabElement) return;
|
||||||
|
|
||||||
|
const indicator = this.getIndicatorElement();
|
||||||
|
if (!indicator) return;
|
||||||
|
|
||||||
|
this.handleInitialTransition(indicator);
|
||||||
|
|
||||||
|
if (this.tabStyle === 'horizontal') {
|
||||||
|
this.updateHorizontalIndicator(indicator, selectedTabElement);
|
||||||
|
} else {
|
||||||
|
this.updateVerticalIndicator(indicator, selectedTabElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
indicator.style.opacity = '1';
|
||||||
|
}
|
||||||
|
|
||||||
|
private shouldShowIndicator(): boolean {
|
||||||
|
return this.selectedTab && this.showTabIndicator && this.tabs.includes(this.selectedTab);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getSelectedTabElement(): HTMLElement | null {
|
||||||
|
const selectedIndex = this.tabs.indexOf(this.selectedTab);
|
||||||
|
const isHorizontal = this.tabStyle === 'horizontal';
|
||||||
|
const selector = isHorizontal
|
||||||
|
? `.tabs-wrapper .tabsContainer .tab:nth-child(${selectedIndex + 1})`
|
||||||
|
: `.vertical-wrapper .tabsContainer .tab:nth-child(${selectedIndex + 1})`;
|
||||||
|
|
||||||
|
return this.shadowRoot.querySelector(selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getIndicatorElement(): HTMLElement | null {
|
||||||
|
return this.shadowRoot.querySelector('.tabIndicator');
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleInitialTransition(indicator: HTMLElement): void {
|
||||||
|
if (!this.indicatorInitialized) {
|
||||||
|
indicator.classList.add('no-transition');
|
||||||
|
this.indicatorInitialized = true;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
indicator.classList.remove('no-transition');
|
||||||
|
}, 50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateHorizontalIndicator(indicator: HTMLElement, tabElement: HTMLElement): void {
|
||||||
|
const tabContent = tabElement.querySelector('.tab-content') as HTMLElement;
|
||||||
|
if (!tabContent) return;
|
||||||
|
|
||||||
|
const wrapperRect = indicator.parentElement.getBoundingClientRect();
|
||||||
|
const contentRect = tabContent.getBoundingClientRect();
|
||||||
|
|
||||||
|
const contentLeft = contentRect.left - wrapperRect.left;
|
||||||
|
const indicatorWidth = contentRect.width + 8;
|
||||||
|
const indicatorLeft = contentLeft - 4;
|
||||||
|
|
||||||
|
indicator.style.width = `${indicatorWidth}px`;
|
||||||
|
indicator.style.left = `${indicatorLeft}px`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateVerticalIndicator(indicator: HTMLElement, tabElement: HTMLElement): void {
|
||||||
|
const tabsContainer = this.shadowRoot.querySelector('.vertical-wrapper .tabsContainer') as HTMLElement;
|
||||||
|
if (!tabsContainer) return;
|
||||||
|
|
||||||
|
indicator.style.top = `${tabElement.offsetTop + tabsContainer.offsetTop}px`;
|
||||||
|
indicator.style.height = `${tabElement.clientHeight}px`;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -35,17 +35,17 @@ export class DeesAppuiView extends DeesElement {
|
|||||||
id: 'demo-view',
|
id: 'demo-view',
|
||||||
name: 'Demo View',
|
name: 'Demo View',
|
||||||
description: 'A demonstration view',
|
description: 'A demonstration view',
|
||||||
iconName: 'home',
|
iconName: 'lucide:home',
|
||||||
tabs: [
|
tabs: [
|
||||||
{
|
{
|
||||||
key: 'overview',
|
key: 'overview',
|
||||||
iconName: 'chart-line',
|
iconName: 'lucide:lineChart',
|
||||||
action: () => console.log('Overview tab'),
|
action: () => console.log('Overview tab'),
|
||||||
content: html`<div style="padding: 20px;">Overview Content</div>`
|
content: html`<div style="padding: 20px;">Overview Content</div>`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'details',
|
key: 'details',
|
||||||
iconName: 'file-alt',
|
iconName: 'lucide:fileText',
|
||||||
action: () => console.log('Details tab'),
|
action: () => console.log('Details tab'),
|
||||||
content: html`<div style="padding: 20px;">Details Content</div>`
|
content: html`<div style="padding: 20px;">Details Content</div>`
|
||||||
}
|
}
|
||||||
|
@ -1,41 +1,112 @@
|
|||||||
import { html } from '@design.estate/dees-element';
|
import { html, cssManager } from '@design.estate/dees-element';
|
||||||
|
|
||||||
export const demoFunc = () => html`
|
export const demoFunc = () => html`
|
||||||
<style>
|
<style>
|
||||||
.demoContainer {
|
.demoContainer {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
gap: 32px;
|
||||||
justify-content: center;
|
padding: 48px;
|
||||||
height: 100%;
|
background: ${cssManager.bdTheme('#f8f9fa', '#0a0a0a')};
|
||||||
background: #222;
|
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')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-description {
|
||||||
|
font-size: 14px;
|
||||||
|
color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
|
||||||
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div class="demoContainer">
|
<div class="demoContainer">
|
||||||
|
<div class="section">
|
||||||
|
<div class="section-title">Non-Selectable Chips</div>
|
||||||
|
<div class="section-description">Basic chips without selection capability. Use for display-only tags.</div>
|
||||||
<dees-chips
|
<dees-chips
|
||||||
selectionMode="none"
|
selectionMode="none"
|
||||||
.selectableChips=${[
|
.selectableChips=${[
|
||||||
{ key: 'account1', value: 'Payment Account 1' },
|
{ key: 'status', value: 'Active' },
|
||||||
{ key: 'account2', value: 'PaymentAccount2' },
|
{ key: 'tier', value: 'Premium' },
|
||||||
{ key: 'account3', value: 'Payment Account 3' },
|
{ key: 'region', value: 'EU-West' },
|
||||||
|
{ key: 'type', value: 'Enterprise' },
|
||||||
]}
|
]}
|
||||||
></dees-chips>
|
></dees-chips>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="section-title">Single Selection Chips</div>
|
||||||
|
<div class="section-description">Click to select one chip at a time. Useful for filters and options.</div>
|
||||||
|
<dees-chips
|
||||||
|
selectionMode="single"
|
||||||
|
.selectableChips=${[
|
||||||
|
{ key: 'all', value: 'All Projects' },
|
||||||
|
{ key: 'active', value: 'Active' },
|
||||||
|
{ key: 'archived', value: 'Archived' },
|
||||||
|
{ key: 'drafts', value: 'Drafts' },
|
||||||
|
]}
|
||||||
|
></dees-chips>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="section-title">Multiple Selection Chips</div>
|
||||||
|
<div class="section-description">Select multiple chips simultaneously. Great for tag selection.</div>
|
||||||
|
<dees-chips
|
||||||
|
selectionMode="multiple"
|
||||||
|
.selectableChips=${[
|
||||||
|
{ key: 'js', value: 'JavaScript' },
|
||||||
|
{ key: 'ts', value: 'TypeScript' },
|
||||||
|
{ key: 'react', value: 'React' },
|
||||||
|
{ key: 'vue', value: 'Vue' },
|
||||||
|
{ key: 'angular', value: 'Angular' },
|
||||||
|
{ key: 'node', value: 'Node.js' },
|
||||||
|
]}
|
||||||
|
></dees-chips>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="section-title">Removable Chips with Keys</div>
|
||||||
|
<div class="section-description">Chips with remove buttons and key-value pairs. Perfect for dynamic lists.</div>
|
||||||
<dees-chips
|
<dees-chips
|
||||||
selectionMode="single"
|
selectionMode="single"
|
||||||
chipsAreRemovable
|
chipsAreRemovable
|
||||||
.selectableChips=${[
|
.selectableChips=${[
|
||||||
{ key: 'account1', value: 'Payment Account 1' },
|
{ key: 'env', value: 'Production' },
|
||||||
{ key: 'account2', value: 'PaymentAccount2' },
|
{ key: 'version', value: '2.4.1' },
|
||||||
{ key: 'account3', value: 'Payment Account 3' },
|
{ key: 'branch', value: 'main' },
|
||||||
]}
|
{ key: 'author', value: 'John Doe' },
|
||||||
></dees-chips>
|
|
||||||
<dees-chips
|
|
||||||
selectionMode="multiple"
|
|
||||||
.selectableChips=${[
|
|
||||||
{ key: 'account1', value: 'Payment Account 1' },
|
|
||||||
{ key: 'account2', value: 'PaymentAccount2' },
|
|
||||||
{ key: 'account3', value: 'Payment Account 3' },
|
|
||||||
]}
|
]}
|
||||||
></dees-chips>
|
></dees-chips>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="section-title">Mixed Content Example</div>
|
||||||
|
<div class="section-description">Combining different chip types for complex UIs.</div>
|
||||||
|
<dees-chips
|
||||||
|
selectionMode="multiple"
|
||||||
|
chipsAreRemovable
|
||||||
|
.selectableChips=${[
|
||||||
|
{ key: 'priority', value: 'High' },
|
||||||
|
{ key: 'status', value: 'In Progress' },
|
||||||
|
{ key: 'bug', value: 'Bug' },
|
||||||
|
{ key: 'feature', value: 'Feature' },
|
||||||
|
{ key: 'sprint', value: 'Sprint 23' },
|
||||||
|
{ key: 'assignee', value: 'Alice' },
|
||||||
|
]}
|
||||||
|
></dees-chips>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
`;
|
`;
|
||||||
|
@ -60,52 +60,93 @@ export class DeesChips extends DeesElement {
|
|||||||
|
|
||||||
.mainbox {
|
.mainbox {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chip {
|
.chip {
|
||||||
border-top: ${cssManager.bdTheme('1px solid #CCC', '1px solid #444')};
|
background: ${cssManager.bdTheme('#f4f4f5', '#27272a')};
|
||||||
background: #333333;
|
border: 1px solid ${cssManager.bdTheme('#e5e7eb', '#3f3f46')};
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
height: 20px;
|
align-items: center;
|
||||||
line-height: 20px;
|
height: 32px;
|
||||||
padding: 0px 8px;
|
padding: 0px 12px;
|
||||||
font-size: 12px;
|
font-size: 14px;
|
||||||
color: #fff;
|
font-weight: 500;
|
||||||
border-radius: 40px;
|
color: ${cssManager.bdTheme('#09090b', '#fafafa')};
|
||||||
margin-right: 4px;
|
border-radius: 6px;
|
||||||
margin-bottom: 4px;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
cursor: pointer;
|
||||||
box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.3);
|
transition: all 0.15s ease;
|
||||||
|
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
.chip:hover {
|
.chip:hover {
|
||||||
background: #666666;
|
background: ${cssManager.bdTheme('#e5e7eb', '#3f3f46')};
|
||||||
|
border-color: ${cssManager.bdTheme('#d1d5db', '#52525b')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.chip:active {
|
||||||
|
transform: scale(0.98);
|
||||||
}
|
}
|
||||||
|
|
||||||
.chip.selected {
|
.chip.selected {
|
||||||
background: #00a3ff;
|
background: ${cssManager.bdTheme('#3b82f6', '#3b82f6')};
|
||||||
|
border-color: ${cssManager.bdTheme('#3b82f6', '#3b82f6')};
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chip.selected:hover {
|
||||||
|
background: ${cssManager.bdTheme('#2563eb', '#2563eb')};
|
||||||
|
border-color: ${cssManager.bdTheme('#2563eb', '#2563eb')};
|
||||||
}
|
}
|
||||||
|
|
||||||
.chipKey {
|
.chipKey {
|
||||||
background: rgba(0, 0, 0, 0.3);
|
background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.06)', 'rgba(255, 255, 255, 0.1)')};
|
||||||
height: 100%;
|
height: 20px;
|
||||||
display: inline-block;
|
line-height: 20px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
margin-left: -8px;
|
margin-left: -8px;
|
||||||
padding-left: 8px;
|
padding: 0px 8px;
|
||||||
padding-right: 8px;
|
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.chip.selected .chipKey {
|
||||||
|
background: rgba(255, 255, 255, 0.2);
|
||||||
|
color: rgba(255, 255, 255, 0.9);
|
||||||
}
|
}
|
||||||
|
|
||||||
dees-icon {
|
dees-icon {
|
||||||
padding: 0px 6px 0px 4px;
|
display: flex;
|
||||||
margin-left: 4px;
|
align-items: center;
|
||||||
margin-right: -8px;
|
justify-content: center;
|
||||||
background: rgba(0, 0, 0, 0.3);
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
margin-left: 8px;
|
||||||
|
margin-right: -6px;
|
||||||
|
border-radius: 3px;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.chip.selected dees-icon {
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
dees-icon:hover {
|
dees-icon:hover {
|
||||||
background: #e4002b;
|
background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.1)', 'rgba(255, 255, 255, 0.1)')};
|
||||||
|
color: ${cssManager.bdTheme('#ef4444', '#ef4444')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.chip.selected dees-icon:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.2);
|
||||||
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
@ -139,20 +180,26 @@ export class DeesChips extends DeesElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async firstUpdated() {
|
public async firstUpdated() {
|
||||||
if (!this.textContent) {
|
// Component initialized
|
||||||
this.textContent = 'Button';
|
|
||||||
this.performUpdate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private isSelected(chip: Tag): boolean {
|
private isSelected(chip: Tag): boolean {
|
||||||
if (this.selectionMode === 'single') {
|
if (this.selectionMode === 'single') {
|
||||||
return this.selectedChip?.key === chip.key;
|
return this.selectedChip ? this.isSameChip(this.selectedChip, chip) : false;
|
||||||
} else {
|
} else {
|
||||||
return this.selectedChips.some((selected) => selected.key === chip.key);
|
return this.selectedChips.some((selected) => this.isSameChip(selected, chip));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private isSameChip(chip1: Tag, chip2: Tag): boolean {
|
||||||
|
// If both have keys, compare by key
|
||||||
|
if (chip1.key && chip2.key) {
|
||||||
|
return chip1.key === chip2.key;
|
||||||
|
}
|
||||||
|
// Otherwise compare by value (and key if present)
|
||||||
|
return chip1.value === chip2.value && chip1.key === chip2.key;
|
||||||
|
}
|
||||||
|
|
||||||
public async selectChip(chip: Tag) {
|
public async selectChip(chip: Tag) {
|
||||||
if (this.selectionMode === 'none') {
|
if (this.selectionMode === 'none') {
|
||||||
return;
|
return;
|
||||||
@ -168,7 +215,7 @@ export class DeesChips extends DeesElement {
|
|||||||
}
|
}
|
||||||
} else if (this.selectionMode === 'multiple') {
|
} else if (this.selectionMode === 'multiple') {
|
||||||
if (this.isSelected(chip)) {
|
if (this.isSelected(chip)) {
|
||||||
this.selectedChips = this.selectedChips.filter((selected) => selected.key !== chip.key);
|
this.selectedChips = this.selectedChips.filter((selected) => !this.isSameChip(selected, chip));
|
||||||
} else {
|
} else {
|
||||||
this.selectedChips = [...this.selectedChips, chip];
|
this.selectedChips = [...this.selectedChips, chip];
|
||||||
}
|
}
|
||||||
@ -179,13 +226,13 @@ export class DeesChips extends DeesElement {
|
|||||||
|
|
||||||
public removeChip(chipToRemove: Tag): void {
|
public removeChip(chipToRemove: Tag): void {
|
||||||
// Remove the chip from selectableChips
|
// Remove the chip from selectableChips
|
||||||
this.selectableChips = this.selectableChips.filter((chip) => chip.key !== chipToRemove.key);
|
this.selectableChips = this.selectableChips.filter((chip) => !this.isSameChip(chip, chipToRemove));
|
||||||
|
|
||||||
// Remove the chip from selectedChips if present
|
// Remove the chip from selectedChips if present
|
||||||
this.selectedChips = this.selectedChips.filter((chip) => chip.key !== chipToRemove.key);
|
this.selectedChips = this.selectedChips.filter((chip) => !this.isSameChip(chip, chipToRemove));
|
||||||
|
|
||||||
// If the removed chip was the selectedChip, set selectedChip to null
|
// If the removed chip was the selectedChip, set selectedChip to null
|
||||||
if (this.selectedChip && this.selectedChip.key === chipToRemove.key) {
|
if (this.selectedChip && this.isSameChip(this.selectedChip, chipToRemove)) {
|
||||||
this.selectedChip = null;
|
this.selectedChip = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,18 +1,199 @@
|
|||||||
import { html } from '@design.estate/dees-element';
|
import { html, cssManager } from '@design.estate/dees-element';
|
||||||
|
|
||||||
export const demoFunc = () => html` <style>
|
export const demoFunc = () => html`
|
||||||
.demoWrapper {
|
<style>
|
||||||
|
.demoWrapper {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
position: absolute;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
min-height: 100vh;
|
||||||
padding: 20px;
|
padding: 48px;
|
||||||
background: none;
|
background: ${cssManager.bdTheme('#f8f9fa', '#0a0a0a')};
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section {
|
||||||
|
max-width: 900px;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="demoWrapper">
|
||||||
|
<div class="section">
|
||||||
|
<div class="section-title">TypeScript Code Example</div>
|
||||||
|
<div class="section-description">A comprehensive TypeScript code example with various syntax highlighting.</div>
|
||||||
|
<dees-dataview-codebox proglang="typescript">
|
||||||
|
interface User {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
email: string;
|
||||||
|
isActive: boolean;
|
||||||
}
|
}
|
||||||
</style>
|
|
||||||
<div class="demoWrapper">
|
class UserService {
|
||||||
<dees-dataview-codebox proglang="typescript">
|
private users: User[] = [];
|
||||||
import * as text from './hello'; const hiThere = 'nice'; const myFunction = async () => {
|
|
||||||
console.log('nice one'); }
|
constructor(private apiUrl: string) {
|
||||||
</dees-dataview-codebox>
|
console.log('UserService initialized');
|
||||||
</div>`
|
}
|
||||||
|
|
||||||
|
async getUsers(): Promise<User[]> {
|
||||||
|
try {
|
||||||
|
const response = await fetch(this.apiUrl);
|
||||||
|
const data = await response.json();
|
||||||
|
return data.users;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to fetch users:', error);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addUser(user: User): void {
|
||||||
|
this.users.push(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Usage example
|
||||||
|
const service = new UserService('https://api.example.com/users');
|
||||||
|
const users = await service.getUsers();
|
||||||
|
console.log('Found users:', users.length);
|
||||||
|
</dees-dataview-codebox>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="section-title">JavaScript Example</div>
|
||||||
|
<div class="section-description">Modern JavaScript with ES6+ features.</div>
|
||||||
|
<dees-dataview-codebox proglang="javascript">
|
||||||
|
// Array manipulation examples
|
||||||
|
const numbers = [1, 2, 3, 4, 5];
|
||||||
|
const doubled = numbers.map(n => n * 2);
|
||||||
|
const filtered = numbers.filter(n => n > 3);
|
||||||
|
|
||||||
|
// Object destructuring
|
||||||
|
const user = { name: 'John', age: 30, city: 'New York' };
|
||||||
|
const { name, age } = user;
|
||||||
|
|
||||||
|
// Promise handling
|
||||||
|
const fetchData = async (url) => {
|
||||||
|
const response = await fetch(url);
|
||||||
|
return response.json();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Modern syntax
|
||||||
|
const greet = (name = 'World') => \`Hello, \${name}!\`;
|
||||||
|
console.log(greet('ShadCN'));
|
||||||
|
</dees-dataview-codebox>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="section-title">Python Example</div>
|
||||||
|
<div class="section-description">Python code with classes and type hints.</div>
|
||||||
|
<dees-dataview-codebox proglang="python">
|
||||||
|
from typing import List, Optional
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
class DataProcessor:
|
||||||
|
"""A simple data processor class"""
|
||||||
|
|
||||||
|
def __init__(self, name: str):
|
||||||
|
self.name = name
|
||||||
|
self.data: List[dict] = []
|
||||||
|
|
||||||
|
async def process_data(self, items: List[dict]) -> List[dict]:
|
||||||
|
"""Process data items asynchronously"""
|
||||||
|
results = []
|
||||||
|
for item in items:
|
||||||
|
# Simulate async processing
|
||||||
|
await asyncio.sleep(0.1)
|
||||||
|
results.append({
|
||||||
|
'id': item.get('id'),
|
||||||
|
'processed': True,
|
||||||
|
'processor': self.name
|
||||||
|
})
|
||||||
|
return results
|
||||||
|
|
||||||
|
def get_summary(self) -> dict:
|
||||||
|
return {
|
||||||
|
'processor': self.name,
|
||||||
|
'items_processed': len(self.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
processor = DataProcessor("Main")
|
||||||
|
data = await processor.process_data([{'id': 1}, {'id': 2}])
|
||||||
|
</dees-dataview-codebox>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="section-title">CSS Example</div>
|
||||||
|
<div class="section-description">Modern CSS with custom properties and animations. Note the shorter language label.</div>
|
||||||
|
<dees-dataview-codebox proglang="css">
|
||||||
|
/* Modern CSS with custom properties */
|
||||||
|
:root {
|
||||||
|
--primary-color: #3b82f6;
|
||||||
|
--secondary-color: #10b981;
|
||||||
|
--background: #ffffff;
|
||||||
|
--text-color: #09090b;
|
||||||
|
--border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
background: var(--background);
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
padding: 24px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from { opacity: 0; transform: translateY(10px); }
|
||||||
|
to { opacity: 1; transform: translateY(0); }
|
||||||
|
}
|
||||||
|
</dees-dataview-codebox>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="section-title">JSON Example</div>
|
||||||
|
<div class="section-description">JSON configuration with proper formatting.</div>
|
||||||
|
<dees-dataview-codebox proglang="json">
|
||||||
|
{
|
||||||
|
"name": "@design.estate/dees-catalog",
|
||||||
|
"version": "1.10.7",
|
||||||
|
"description": "A comprehensive catalog of web components",
|
||||||
|
"main": "dist_ts_web/index.js",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsbuild tsfolders --allowimplicitany && tsbundle element --production",
|
||||||
|
"watch": "tswatch element",
|
||||||
|
"test": "tstest test/ --web --verbose"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@design.estate/dees-element": "^2.0.45",
|
||||||
|
"highlight.js": "^11.9.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</dees-dataview-codebox>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
@ -53,23 +53,23 @@ export class DeesDataviewCodebox extends DeesElement {
|
|||||||
}
|
}
|
||||||
.mainbox {
|
.mainbox {
|
||||||
position: relative;
|
position: relative;
|
||||||
color: ${this.goBright ? '#333333' : '#ffffff'};
|
color: ${cssManager.bdTheme('#09090b', '#fafafa')};
|
||||||
border-top: 1px solid ${this.goBright ? '#ffffff' : '#333333'};
|
border: 1px solid ${cssManager.bdTheme('#e5e7eb', '#27272a')};
|
||||||
box-shadow: 0px 0px 5px ${this.goBright ? 'rgba(0,0,0,0.1)' : 'rgba(0,0,0,0.5)'};
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06);
|
||||||
background: ${this.goBright ? '#ffffff' : '#191919'};
|
background: ${cssManager.bdTheme('#ffffff', '#09090b')};
|
||||||
border-radius: 16px;
|
border-radius: 6px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.appbar {
|
.appbar {
|
||||||
position: relative;
|
position: relative;
|
||||||
color: ${cssManager.bdTheme('#333', '#ccc')};
|
color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
|
||||||
background: ${cssManager.bdTheme('#ffffff', '#161616')};
|
background: ${cssManager.bdTheme('#f9fafb', '#18181b')};
|
||||||
border-bottom: 1px solid ${cssManager.bdTheme('#eeeeeb', '#222222')};
|
border-bottom: 1px solid ${cssManager.bdTheme('#e5e7eb', '#27272a')};
|
||||||
height: 24px;
|
height: 32px;
|
||||||
display: flex;
|
display: flex;
|
||||||
font-size: 12px;
|
font-size: 13px;
|
||||||
line-height: 24px;
|
line-height: 32px;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
@ -82,31 +82,38 @@ export class DeesDataviewCodebox extends DeesElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.bottomBar {
|
.bottomBar {
|
||||||
color: ${cssManager.bdTheme('#333', '#ccc')};
|
position: relative;
|
||||||
background: ${cssManager.bdTheme('#ffffff', '#161616')};
|
color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
|
||||||
border-top: 1px solid ${cssManager.bdTheme('#eeeeeb', '#222222')};
|
background: ${cssManager.bdTheme('#f9fafb', '#18181b')};
|
||||||
height: 24px;
|
border-top: 1px solid ${cssManager.bdTheme('#e5e7eb', '#27272a')};
|
||||||
|
height: 28px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 24px;
|
line-height: 28px;
|
||||||
text-align: right;
|
display: flex;
|
||||||
padding-right: 100px;
|
justify-content: flex-end;
|
||||||
|
align-items: stretch;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spacesLabel {
|
||||||
|
padding: 0 16px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.languageLabel {
|
.languageLabel {
|
||||||
color: ${cssManager.bdTheme('#333', '#ccc')};
|
color: ${cssManager.bdTheme('#3b82f6', '#3b82f6')};
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 24px;
|
line-height: 28px;
|
||||||
z-index: 10;
|
background: ${cssManager.bdTheme('rgba(59, 130, 246, 0.1)', 'rgba(59, 130, 246, 0.1)')};
|
||||||
background: #6596ff20;
|
padding: 0px 16px;
|
||||||
display: inline-block;
|
font-weight: 500;
|
||||||
position: absolute;
|
display: flex;
|
||||||
bottom: 0px;
|
align-items: center;
|
||||||
right: 0px;
|
|
||||||
padding: 0px 16px 0px 8px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.hljs-keyword {
|
.hljs-keyword {
|
||||||
color: #ff65ec;
|
color: ${cssManager.bdTheme('#dc2626', '#f87171')};
|
||||||
}
|
}
|
||||||
|
|
||||||
.codegrid {
|
.codegrid {
|
||||||
@ -116,10 +123,10 @@ export class DeesDataviewCodebox extends DeesElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.lineNumbers {
|
.lineNumbers {
|
||||||
color: ${this.goBright ? '#acacac' : '#666666'};
|
color: ${cssManager.bdTheme('#71717a', '#52525b')};
|
||||||
padding: 30px 16px 0px 0px;
|
padding: 24px 16px 0px 0px;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
border-right: 1px solid ${this.goBright ? '#eaeaea' : '#222222'};
|
border-right: 1px solid ${cssManager.bdTheme('#e5e7eb', '#27272a')};
|
||||||
}
|
}
|
||||||
|
|
||||||
.lineCounter:last-child {
|
.lineCounter:last-child {
|
||||||
@ -129,11 +136,11 @@ export class DeesDataviewCodebox extends DeesElement {
|
|||||||
pre {
|
pre {
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
padding: 30px 40px;
|
padding: 24px 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
code {
|
code {
|
||||||
font-weight: ${this.goBright ? '400' : '300'};
|
font-weight: 400;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
}
|
}
|
||||||
@ -147,23 +154,39 @@ export class DeesDataviewCodebox extends DeesElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.hljs-string {
|
.hljs-string {
|
||||||
color: #ffa465;
|
color: ${cssManager.bdTheme('#059669', '#10b981')};
|
||||||
}
|
}
|
||||||
|
|
||||||
.hljs-built_in {
|
.hljs-built_in {
|
||||||
color: #65ff6a;
|
color: ${cssManager.bdTheme('#8b5cf6', '#a78bfa')};
|
||||||
}
|
}
|
||||||
|
|
||||||
.hljs-function {
|
.hljs-function {
|
||||||
color: ${this.goBright ? '#2765DF' : '#6596ff'};
|
color: ${cssManager.bdTheme('#3b82f6', '#60a5fa')};
|
||||||
}
|
}
|
||||||
|
|
||||||
.hljs-params {
|
.hljs-params {
|
||||||
color: ${this.goBright ? '#3DB420' : '#65d5ff'};
|
color: ${cssManager.bdTheme('#0891b2', '#06b6d4')};
|
||||||
}
|
}
|
||||||
|
|
||||||
.hljs-comment {
|
.hljs-comment {
|
||||||
color: ${this.goBright ? '#EF9300' : '#ffd765'};
|
color: ${cssManager.bdTheme('#71717a', '#71717a')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-number {
|
||||||
|
color: ${cssManager.bdTheme('#ea580c', '#fb923c')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-literal {
|
||||||
|
color: ${cssManager.bdTheme('#dc2626', '#f87171')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-attr {
|
||||||
|
color: ${cssManager.bdTheme('#8b5cf6', '#a78bfa')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.hljs-variable {
|
||||||
|
color: ${cssManager.bdTheme('#09090b', '#fafafa')};
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div
|
<div
|
||||||
@ -198,7 +221,7 @@ export class DeesDataviewCodebox extends DeesElement {
|
|||||||
<pre><code></code></pre>
|
<pre><code></code></pre>
|
||||||
</div>
|
</div>
|
||||||
<div class="bottomBar">
|
<div class="bottomBar">
|
||||||
Spaces: 2
|
<div class="spacesLabel">Spaces: 2</div>
|
||||||
<div class="languageLabel">${this.progLang}</div>
|
<div class="languageLabel">${this.progLang}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { html, css } from '@design.estate/dees-element';
|
import { html, css, cssManager } from '@design.estate/dees-element';
|
||||||
|
|
||||||
export const demoFunc = () => html`
|
export const demoFunc = () => html`
|
||||||
<dees-demowrapper>
|
<dees-demowrapper>
|
||||||
@ -7,10 +7,31 @@ export const demoFunc = () => html`
|
|||||||
.demo-container {
|
.demo-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 24px;
|
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;
|
padding: 24px;
|
||||||
max-width: 1200px;
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
margin: 0 auto;
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
color: ${cssManager.bdTheme('#09090b', '#fafafa')};
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-description {
|
||||||
|
font-size: 14px;
|
||||||
|
color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
|
||||||
|
margin-bottom: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings-grid {
|
.settings-grid {
|
||||||
@ -28,7 +49,10 @@ export const demoFunc = () => html`
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div class="demo-container">
|
<div class="demo-container">
|
||||||
<dees-panel .title=${'Multi-Option Toggle'} .subtitle=${'Select from multiple options with a sliding indicator'}>
|
<div class="section">
|
||||||
|
<div class="section-title">Multi-Option Toggle</div>
|
||||||
|
<div class="section-description">Select from multiple options with a smooth sliding indicator animation.</div>
|
||||||
|
|
||||||
<dees-input-multitoggle
|
<dees-input-multitoggle
|
||||||
.label=${'Display Mode'}
|
.label=${'Display Mode'}
|
||||||
.description=${'Choose how content is displayed'}
|
.description=${'Choose how content is displayed'}
|
||||||
@ -36,15 +60,20 @@ export const demoFunc = () => html`
|
|||||||
.selectedOption=${'Grid View'}
|
.selectedOption=${'Grid View'}
|
||||||
></dees-input-multitoggle>
|
></dees-input-multitoggle>
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
|
||||||
<dees-input-multitoggle
|
<dees-input-multitoggle
|
||||||
.label=${'T-Shirt Size'}
|
.label=${'T-Shirt Size'}
|
||||||
.description=${'Select your preferred size'}
|
.description=${'Select your preferred size'}
|
||||||
.options=${['XS', 'S', 'M', 'L', 'XL', 'XXL']}
|
.options=${['XS', 'S', 'M', 'L', 'XL', 'XXL']}
|
||||||
.selectedOption=${'M'}
|
.selectedOption=${'M'}
|
||||||
></dees-input-multitoggle>
|
></dees-input-multitoggle>
|
||||||
</dees-panel>
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="section-title">Boolean Toggle</div>
|
||||||
|
<div class="section-description">Simple on/off switches with customizable labels for clearer context.</div>
|
||||||
|
|
||||||
<dees-panel .title=${'Boolean Toggle'} .subtitle=${'Simple on/off switches with custom labels'}>
|
|
||||||
<dees-input-multitoggle
|
<dees-input-multitoggle
|
||||||
.label=${'Notifications'}
|
.label=${'Notifications'}
|
||||||
.description=${'Enable or disable push notifications'}
|
.description=${'Enable or disable push notifications'}
|
||||||
@ -52,6 +81,8 @@ export const demoFunc = () => html`
|
|||||||
.selectedOption=${'true'}
|
.selectedOption=${'true'}
|
||||||
></dees-input-multitoggle>
|
></dees-input-multitoggle>
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
|
||||||
<dees-input-multitoggle
|
<dees-input-multitoggle
|
||||||
.label=${'Theme Mode'}
|
.label=${'Theme Mode'}
|
||||||
.description=${'Switch between light and dark theme'}
|
.description=${'Switch between light and dark theme'}
|
||||||
@ -60,13 +91,15 @@ export const demoFunc = () => html`
|
|||||||
.booleanFalseName=${'Light'}
|
.booleanFalseName=${'Light'}
|
||||||
.selectedOption=${'Dark'}
|
.selectedOption=${'Dark'}
|
||||||
></dees-input-multitoggle>
|
></dees-input-multitoggle>
|
||||||
</dees-panel>
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="section-title">Settings Grid</div>
|
||||||
|
<div class="section-description">Configuration options arranged in a responsive grid layout.</div>
|
||||||
|
|
||||||
<dees-panel .title=${'Settings Panel'} .subtitle=${'Configuration options in a horizontal layout'}>
|
|
||||||
<div class="settings-grid">
|
<div class="settings-grid">
|
||||||
<dees-input-multitoggle
|
<dees-input-multitoggle
|
||||||
.label=${'Auto-Save'}
|
.label=${'Auto-Save'}
|
||||||
.layoutMode=${'horizontal'}
|
|
||||||
.type=${'boolean'}
|
.type=${'boolean'}
|
||||||
.booleanTrueName=${'Enabled'}
|
.booleanTrueName=${'Enabled'}
|
||||||
.booleanFalseName=${'Disabled'}
|
.booleanFalseName=${'Disabled'}
|
||||||
@ -75,30 +108,30 @@ export const demoFunc = () => html`
|
|||||||
|
|
||||||
<dees-input-multitoggle
|
<dees-input-multitoggle
|
||||||
.label=${'Language'}
|
.label=${'Language'}
|
||||||
.layoutMode=${'horizontal'}
|
|
||||||
.options=${['English', 'German', 'French', 'Spanish']}
|
.options=${['English', 'German', 'French', 'Spanish']}
|
||||||
.selectedOption=${'English'}
|
.selectedOption=${'English'}
|
||||||
></dees-input-multitoggle>
|
></dees-input-multitoggle>
|
||||||
|
|
||||||
<dees-input-multitoggle
|
<dees-input-multitoggle
|
||||||
.label=${'Quality'}
|
.label=${'Quality'}
|
||||||
.layoutMode=${'horizontal'}
|
|
||||||
.options=${['Low', 'Medium', 'High', 'Ultra']}
|
.options=${['Low', 'Medium', 'High', 'Ultra']}
|
||||||
.selectedOption=${'High'}
|
.selectedOption=${'High'}
|
||||||
></dees-input-multitoggle>
|
></dees-input-multitoggle>
|
||||||
|
|
||||||
<dees-input-multitoggle
|
<dees-input-multitoggle
|
||||||
.label=${'Privacy'}
|
.label=${'Privacy'}
|
||||||
.layoutMode=${'horizontal'}
|
|
||||||
.type=${'boolean'}
|
.type=${'boolean'}
|
||||||
.booleanTrueName=${'Private'}
|
.booleanTrueName=${'Private'}
|
||||||
.booleanFalseName=${'Public'}
|
.booleanFalseName=${'Public'}
|
||||||
.selectedOption=${'Private'}
|
.selectedOption=${'Private'}
|
||||||
></dees-input-multitoggle>
|
></dees-input-multitoggle>
|
||||||
</div>
|
</div>
|
||||||
</dees-panel>
|
</div>
|
||||||
|
|
||||||
|
<div class="section">
|
||||||
|
<div class="section-title">States & Form Integration</div>
|
||||||
|
<div class="section-description">Examples of disabled states and integration within forms.</div>
|
||||||
|
|
||||||
<dees-panel .title=${'States & Form Integration'} .subtitle=${'Disabled states and form usage'}>
|
|
||||||
<dees-input-multitoggle
|
<dees-input-multitoggle
|
||||||
.label=${'Account Type'}
|
.label=${'Account Type'}
|
||||||
.description=${'This setting is locked'}
|
.description=${'This setting is locked'}
|
||||||
@ -107,6 +140,8 @@ export const demoFunc = () => html`
|
|||||||
.disabled=${true}
|
.disabled=${true}
|
||||||
></dees-input-multitoggle>
|
></dees-input-multitoggle>
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
|
||||||
<dees-form>
|
<dees-form>
|
||||||
<dees-input-text .label=${'Project Name'} .required=${true}></dees-input-text>
|
<dees-input-text .label=${'Project Name'} .required=${true}></dees-input-text>
|
||||||
<dees-input-multitoggle
|
<dees-input-multitoggle
|
||||||
@ -122,7 +157,7 @@ export const demoFunc = () => html`
|
|||||||
.selectedOption=${'MIT'}
|
.selectedOption=${'MIT'}
|
||||||
></dees-input-multitoggle>
|
></dees-input-multitoggle>
|
||||||
</dees-form>
|
</dees-form>
|
||||||
</dees-panel>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</dees-demowrapper>
|
</dees-demowrapper>
|
||||||
`;
|
`;
|
@ -57,9 +57,12 @@ export class DeesInputMultitoggle extends DeesInputBase<DeesInputMultitoggle> {
|
|||||||
} else {
|
} else {
|
||||||
this.selectedOption = val as string;
|
this.selectedOption = val as string;
|
||||||
}
|
}
|
||||||
|
this.requestUpdate();
|
||||||
// Defer indicator update to next frame if component not yet updated
|
// Defer indicator update to next frame if component not yet updated
|
||||||
if (this.hasUpdated) {
|
if (this.hasUpdated) {
|
||||||
|
requestAnimationFrame(() => {
|
||||||
this.setIndicator();
|
this.setIndicator();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,59 +71,71 @@ export class DeesInputMultitoggle extends DeesInputBase<DeesInputMultitoggle> {
|
|||||||
cssManager.defaultStyles,
|
cssManager.defaultStyles,
|
||||||
css`
|
css`
|
||||||
:host {
|
:host {
|
||||||
color: ${cssManager.bdTheme('#333', '#ccc')};
|
color: ${cssManager.bdTheme('#09090b', '#fafafa')};
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.selections {
|
.selections {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: inline-flex;
|
||||||
flex-direction: row;
|
align-items: center;
|
||||||
flex-wrap: nowrap;
|
background: ${cssManager.bdTheme('#ffffff', '#18181b')};
|
||||||
background: ${cssManager.bdTheme('#fff', '#222')};
|
border: 1px solid ${cssManager.bdTheme('#e5e7eb', '#27272a')};
|
||||||
width: min-content;
|
padding: 4px;
|
||||||
border-radius: 20px;
|
border-radius: 8px;
|
||||||
height: 32px;
|
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
||||||
border-top: 1px solid ${cssManager.bdTheme('rgba(0,0,0,0.1)', 'rgba(255,255,255,0.1)')};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.option {
|
.option {
|
||||||
color: ${cssManager.bdTheme('#666', '#999')};
|
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 0px 16px;
|
padding: 8px 20px;
|
||||||
line-height: 32px;
|
border-radius: 6px;
|
||||||
cursor: default;
|
cursor: pointer;
|
||||||
width: min-content; /* Make the width as per the content */
|
white-space: nowrap;
|
||||||
white-space: nowrap; /* Prevent text wrapping */
|
transition: color 0.2s ease;
|
||||||
transition: all 0.1s;
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
transform: translateY(-1px);
|
font-weight: 500;
|
||||||
|
color: ${cssManager.bdTheme('#71717a', '#71717a')};
|
||||||
|
line-height: 1;
|
||||||
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.option:hover {
|
.option:hover {
|
||||||
color: ${cssManager.bdTheme('#333', '#fff')};
|
color: ${cssManager.bdTheme('#18181b', '#e4e4e7')};
|
||||||
}
|
}
|
||||||
|
|
||||||
.option.selected {
|
.option.selected {
|
||||||
color: ${cssManager.bdTheme('#fff', '#fff')};
|
color: ${cssManager.bdTheme('#3b82f6', '#60a5fa')};
|
||||||
}
|
}
|
||||||
|
|
||||||
.indicator {
|
.indicator {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
height: 24px;
|
height: calc(100% - 8px);
|
||||||
left: 4px;
|
top: 4px;
|
||||||
top: 3px;
|
border-radius: 6px;
|
||||||
border-radius: 16px;
|
background: ${cssManager.bdTheme('rgba(59, 130, 246, 0.15)', 'rgba(59, 130, 246, 0.15)')};
|
||||||
background: ${cssManager.bdTheme(colors.bright.blueActive, colors.dark.blueActive)};
|
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
min-width: 24px;
|
z-index: 1;
|
||||||
transition: all 0.1s ease-in-out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.indicator.no-transition {
|
.indicator.no-transition {
|
||||||
transition: none;
|
transition: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:host([disabled]) .selections {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([disabled]) .option {
|
||||||
|
cursor: not-allowed;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([disabled]) .indicator {
|
||||||
|
background: ${cssManager.bdTheme('rgba(113, 113, 122, 0.15)', 'rgba(113, 113, 122, 0.15)')};
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -148,6 +163,14 @@ export class DeesInputMultitoggle extends DeesInputBase<DeesInputMultitoggle> {
|
|||||||
// Initialize boolean options early
|
// Initialize boolean options early
|
||||||
if (this.type === 'boolean' && this.options.length === 0) {
|
if (this.type === 'boolean' && this.options.length === 0) {
|
||||||
this.options = [this.booleanTrueName || 'true', this.booleanFalseName || 'false'];
|
this.options = [this.booleanTrueName || 'true', this.booleanFalseName || 'false'];
|
||||||
|
// Set default selection for boolean if not set
|
||||||
|
if (!this.selectedOption) {
|
||||||
|
this.selectedOption = this.booleanFalseName || 'false';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Set default selection to first option if not set
|
||||||
|
if (!this.selectedOption && this.options.length > 0) {
|
||||||
|
this.selectedOption = this.options[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,13 +182,25 @@ export class DeesInputMultitoggle extends DeesInputBase<DeesInputMultitoggle> {
|
|||||||
}
|
}
|
||||||
// Wait for the next frame to ensure DOM is fully rendered
|
// Wait for the next frame to ensure DOM is fully rendered
|
||||||
await this.updateComplete;
|
await this.updateComplete;
|
||||||
requestAnimationFrame(() => {
|
|
||||||
|
// Wait for fonts to load
|
||||||
|
if (document.fonts) {
|
||||||
|
await document.fonts.ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait one more frame after fonts are loaded
|
||||||
|
await new Promise(resolve => requestAnimationFrame(resolve));
|
||||||
|
|
||||||
|
// Now set the indicator
|
||||||
this.setIndicator();
|
this.setIndicator();
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async handleSelection(optionArg: string) {
|
public async handleSelection(optionArg: string) {
|
||||||
|
if (this.disabled) return;
|
||||||
this.selectedOption = optionArg;
|
this.selectedOption = optionArg;
|
||||||
|
this.requestUpdate();
|
||||||
|
this.changeSubject.next(this);
|
||||||
|
await this.updateComplete;
|
||||||
this.setIndicator();
|
this.setIndicator();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,8 +234,8 @@ export class DeesInputMultitoggle extends DeesInputBase<DeesInputMultitoggle> {
|
|||||||
}, 50);
|
}, 50);
|
||||||
}
|
}
|
||||||
|
|
||||||
indicator.style.width = `${option.clientWidth - 8}px`;
|
indicator.style.width = `${option.clientWidth}px`;
|
||||||
indicator.style.left = `${option.offsetLeft + 4}px`;
|
indicator.style.left = `${option.offsetLeft}px`;
|
||||||
indicator.style.opacity = '1';
|
indicator.style.opacity = '1';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -218,8 +253,11 @@ export class DeesInputMultitoggle extends DeesInputBase<DeesInputMultitoggle> {
|
|||||||
} else {
|
} else {
|
||||||
this.selectedOption = value as string;
|
this.selectedOption = value as string;
|
||||||
}
|
}
|
||||||
|
this.requestUpdate();
|
||||||
if (this.hasUpdated) {
|
if (this.hasUpdated) {
|
||||||
|
requestAnimationFrame(() => {
|
||||||
this.setIndicator();
|
this.setIndicator();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,12 +139,12 @@ export class DeesModal extends DeesElement {
|
|||||||
opacity: 0;
|
opacity: 0;
|
||||||
min-height: 120px;
|
min-height: 120px;
|
||||||
max-height: calc(100vh - 40px);
|
max-height: calc(100vh - 40px);
|
||||||
background: ${cssManager.bdTheme('#ffffff', '#111')};
|
background: ${cssManager.bdTheme('#ffffff', '#09090b')};
|
||||||
border-radius: 8px;
|
border-radius: 6px;
|
||||||
border: 1px solid ${cssManager.bdTheme('#e0e0e0', '#333')};
|
border: 1px solid ${cssManager.bdTheme('#e5e7eb', '#27272a')};
|
||||||
transition: all 0.2s;
|
transition: all 0.2s ease;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
box-shadow: ${cssManager.bdTheme('0px 2px 10px rgba(0, 0, 0, 0.1)', '0px 2px 5px rgba(0, 0, 0, 0.5)')};
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06);
|
||||||
margin: 20px;
|
margin: 20px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -193,6 +193,7 @@ export class DeesModal extends DeesElement {
|
|||||||
max-height: 100vh !important;
|
max-height: 100vh !important;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
|
border: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,7 +215,7 @@ export class DeesModal extends DeesElement {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
padding: 0 12px;
|
padding: 0 12px;
|
||||||
border-bottom: 1px solid ${cssManager.bdTheme('#e0e0e0', '#333')};
|
border-bottom: 1px solid ${cssManager.bdTheme('#e5e7eb', '#27272a')};
|
||||||
position: relative;
|
position: relative;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
@ -232,23 +233,23 @@ export class DeesModal extends DeesElement {
|
|||||||
.modal .heading .header-button {
|
.modal .heading .header-button {
|
||||||
width: 28px;
|
width: 28px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
border-radius: 6px;
|
border-radius: 4px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.2s;
|
transition: all 0.15s ease;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: ${cssManager.bdTheme('#666', '#999')};
|
color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal .heading .header-button:hover {
|
.modal .heading .header-button:hover {
|
||||||
background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.08)', 'rgba(255, 255, 255, 0.08)')};
|
background: ${cssManager.bdTheme('#f4f4f5', '#27272a')};
|
||||||
color: ${cssManager.bdTheme('#333', '#fff')};
|
color: ${cssManager.bdTheme('#09090b', '#fafafa')};
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal .heading .header-button:active {
|
.modal .heading .header-button:active {
|
||||||
background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.12)', 'rgba(255, 255, 255, 0.12)')};
|
background: ${cssManager.bdTheme('#e5e7eb', '#3f3f46')};
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal .heading .header-button dees-icon {
|
.modal .heading .header-button dees-icon {
|
||||||
@ -264,6 +265,7 @@ export class DeesModal extends DeesElement {
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 40px;
|
line-height: 40px;
|
||||||
padding: 0 40px;
|
padding: 0 40px;
|
||||||
|
color: ${cssManager.bdTheme('#09090b', '#fafafa')};
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal .content {
|
.modal .content {
|
||||||
@ -276,7 +278,7 @@ export class DeesModal extends DeesElement {
|
|||||||
.modal .bottomButtons {
|
.modal .bottomButtons {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
border-top: 1px solid ${cssManager.bdTheme('#e0e0e0', '#333')};
|
border-top: 1px solid ${cssManager.bdTheme('#e5e7eb', '#27272a')};
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
@ -285,39 +287,43 @@ export class DeesModal extends DeesElement {
|
|||||||
|
|
||||||
.modal .bottomButtons .bottomButton {
|
.modal .bottomButtons .bottomButton {
|
||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
border-radius: 6px;
|
border-radius: 4px;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
transition: all 0.2s;
|
transition: all 0.15s ease;
|
||||||
background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.05)', 'rgba(255, 255, 255, 0.05)')};
|
background: ${cssManager.bdTheme('#ffffff', '#27272a')};
|
||||||
|
border: 1px solid ${cssManager.bdTheme('#e5e7eb', '#3f3f46')};
|
||||||
|
color: ${cssManager.bdTheme('#09090b', '#fafafa')};
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal .bottomButtons .bottomButton:hover {
|
.modal .bottomButtons .bottomButton:hover {
|
||||||
background: ${cssManager.bdTheme(colors.bright.blue, colors.dark.blue)};
|
background: ${cssManager.bdTheme('#f4f4f5', '#3f3f46')};
|
||||||
color: #ffffff;
|
border-color: ${cssManager.bdTheme('#d1d5db', '#52525b')};
|
||||||
}
|
}
|
||||||
.modal .bottomButtons .bottomButton:active {
|
.modal .bottomButtons .bottomButton:active {
|
||||||
background: ${cssManager.bdTheme(colors.bright.blueActive, colors.dark.blueActive)};
|
background: ${cssManager.bdTheme('#e5e7eb', '#52525b')};
|
||||||
color: #ffffff;
|
|
||||||
}
|
}
|
||||||
.modal .bottomButtons .bottomButton:last-child {
|
.modal .bottomButtons .bottomButton:last-child {
|
||||||
border-right: none;
|
border-right: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal .bottomButtons .bottomButton.primary {
|
.modal .bottomButtons .bottomButton.primary {
|
||||||
background: ${cssManager.bdTheme(colors.bright.blue, colors.dark.blue)};
|
background: ${cssManager.bdTheme('#3b82f6', '#3b82f6')};
|
||||||
|
border-color: ${cssManager.bdTheme('#3b82f6', '#3b82f6')};
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
.modal .bottomButtons .bottomButton.primary:hover {
|
.modal .bottomButtons .bottomButton.primary:hover {
|
||||||
background: ${cssManager.bdTheme(colors.bright.blueActive, colors.dark.blueActive)};
|
background: ${cssManager.bdTheme('#2563eb', '#2563eb')};
|
||||||
|
border-color: ${cssManager.bdTheme('#2563eb', '#2563eb')};
|
||||||
}
|
}
|
||||||
.modal .bottomButtons .bottomButton.primary:active {
|
.modal .bottomButtons .bottomButton.primary:active {
|
||||||
background: ${cssManager.bdTheme(colors.bright.blueMuted, colors.dark.blueMuted)};
|
background: ${cssManager.bdTheme('#1d4ed8', '#1d4ed8')};
|
||||||
|
border-color: ${cssManager.bdTheme('#1d4ed8', '#1d4ed8')};
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
|
Reference in New Issue
Block a user