307 lines
10 KiB
TypeScript
307 lines
10 KiB
TypeScript
import { html, cssManager, css, DeesElement, customElement, state } from '@design.estate/dees-element';
|
|
import * as interfaces from '../../interfaces/index.js';
|
|
import type { DeesAppuiTabs } from './dees-appui-tabs.js';
|
|
|
|
// Interactive demo component for closeable tabs
|
|
@customElement('demo-closeable-tabs')
|
|
class DemoCloseableTabs extends DeesElement {
|
|
@state()
|
|
accessor tabs: interfaces.IMenuItem[] = [
|
|
{ key: 'Main', iconName: 'lucide:home', action: () => console.log('Main clicked') },
|
|
];
|
|
|
|
@state()
|
|
accessor tabCounter: number = 0;
|
|
|
|
static styles = [
|
|
css`
|
|
:host {
|
|
display: block;
|
|
}
|
|
.controls {
|
|
display: flex;
|
|
gap: 8px;
|
|
margin-top: 16px;
|
|
}
|
|
button {
|
|
background: ${cssManager.bdTheme('rgba(59, 130, 246, 0.1)', 'rgba(59, 130, 246, 0.1)')};
|
|
border: 1px solid ${cssManager.bdTheme('rgba(59, 130, 246, 0.3)', 'rgba(59, 130, 246, 0.3)')};
|
|
color: ${cssManager.bdTheme('#3b82f6', '#60a5fa')};
|
|
padding: 8px 16px;
|
|
border-radius: 6px;
|
|
cursor: pointer;
|
|
font-size: 13px;
|
|
transition: all 0.15s ease;
|
|
}
|
|
button:hover {
|
|
background: ${cssManager.bdTheme('rgba(59, 130, 246, 0.2)', 'rgba(59, 130, 246, 0.2)')};
|
|
}
|
|
.info {
|
|
margin-top: 16px;
|
|
padding: 12px 16px;
|
|
background: ${cssManager.bdTheme('rgba(0,0,0,0.02)', 'rgba(255,255,255,0.02)')};
|
|
border-radius: 6px;
|
|
font-size: 13px;
|
|
color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
|
|
}
|
|
`
|
|
];
|
|
|
|
private addTab() {
|
|
this.tabCounter++;
|
|
const tabKey = `Document ${this.tabCounter}`;
|
|
this.tabs = [
|
|
...this.tabs,
|
|
{
|
|
key: tabKey,
|
|
iconName: 'lucide:file',
|
|
action: () => console.log(`${tabKey} clicked`),
|
|
closeable: true,
|
|
onClose: () => this.removeTab(tabKey)
|
|
}
|
|
];
|
|
}
|
|
|
|
private removeTab(tabKey: string) {
|
|
this.tabs = this.tabs.filter(t => t.key !== tabKey);
|
|
}
|
|
|
|
render() {
|
|
return html`
|
|
<dees-appui-tabs
|
|
.tabs=${this.tabs}
|
|
@tab-close=${(e: CustomEvent) => this.removeTab(e.detail.tab.key)}
|
|
></dees-appui-tabs>
|
|
<div class="controls">
|
|
<button @click=${() => this.addTab()}>+ Add New Tab</button>
|
|
</div>
|
|
<div class="info">
|
|
Click the X button on tabs to close them. The "Main" tab is not closeable.
|
|
<br>Current tabs: ${this.tabs.length}
|
|
</div>
|
|
`;
|
|
}
|
|
}
|
|
|
|
// Interactive demo for auto-hide feature
|
|
@customElement('demo-autohide-tabs')
|
|
class DemoAutoHideTabs extends DeesElement {
|
|
@state()
|
|
accessor tabs: interfaces.IMenuItem[] = [
|
|
{ key: 'Tab 1', iconName: 'lucide:file', action: () => console.log('Tab 1') },
|
|
{ key: 'Tab 2', iconName: 'lucide:file', action: () => console.log('Tab 2') },
|
|
];
|
|
|
|
@state()
|
|
accessor autoHide: boolean = true;
|
|
|
|
@state()
|
|
accessor threshold: number = 1;
|
|
|
|
static styles = [
|
|
css`
|
|
:host {
|
|
display: block;
|
|
}
|
|
.tabs-container {
|
|
min-height: 60px;
|
|
border: 1px dashed ${cssManager.bdTheme('#e5e7eb', '#27272a')};
|
|
border-radius: 6px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
.tabs-container dees-appui-tabs {
|
|
width: 100%;
|
|
}
|
|
.placeholder {
|
|
color: ${cssManager.bdTheme('#a1a1aa', '#71717a')};
|
|
font-size: 13px;
|
|
font-style: italic;
|
|
}
|
|
.controls {
|
|
display: flex;
|
|
gap: 8px;
|
|
margin-top: 16px;
|
|
flex-wrap: wrap;
|
|
}
|
|
button {
|
|
background: ${cssManager.bdTheme('rgba(59, 130, 246, 0.1)', 'rgba(59, 130, 246, 0.1)')};
|
|
border: 1px solid ${cssManager.bdTheme('rgba(59, 130, 246, 0.3)', 'rgba(59, 130, 246, 0.3)')};
|
|
color: ${cssManager.bdTheme('#3b82f6', '#60a5fa')};
|
|
padding: 8px 16px;
|
|
border-radius: 6px;
|
|
cursor: pointer;
|
|
font-size: 13px;
|
|
transition: all 0.15s ease;
|
|
}
|
|
button:hover {
|
|
background: ${cssManager.bdTheme('rgba(59, 130, 246, 0.2)', 'rgba(59, 130, 246, 0.2)')};
|
|
}
|
|
button.danger {
|
|
background: ${cssManager.bdTheme('rgba(239, 68, 68, 0.1)', 'rgba(239, 68, 68, 0.1)')};
|
|
border-color: ${cssManager.bdTheme('rgba(239, 68, 68, 0.3)', 'rgba(239, 68, 68, 0.3)')};
|
|
color: ${cssManager.bdTheme('#ef4444', '#f87171')};
|
|
}
|
|
button.danger:hover {
|
|
background: ${cssManager.bdTheme('rgba(239, 68, 68, 0.2)', 'rgba(239, 68, 68, 0.2)')};
|
|
}
|
|
.info {
|
|
margin-top: 16px;
|
|
padding: 12px 16px;
|
|
background: ${cssManager.bdTheme('rgba(0,0,0,0.02)', 'rgba(255,255,255,0.02)')};
|
|
border-radius: 6px;
|
|
font-size: 13px;
|
|
color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
|
|
}
|
|
`
|
|
];
|
|
|
|
private tabCounter = 2;
|
|
|
|
private addTab() {
|
|
this.tabCounter++;
|
|
this.tabs = [...this.tabs, {
|
|
key: `Tab ${this.tabCounter}`,
|
|
iconName: 'lucide:file',
|
|
action: () => console.log(`Tab ${this.tabCounter}`)
|
|
}];
|
|
}
|
|
|
|
private removeLastTab() {
|
|
if (this.tabs.length > 0) {
|
|
this.tabs = this.tabs.slice(0, -1);
|
|
}
|
|
}
|
|
|
|
private clearTabs() {
|
|
this.tabs = [];
|
|
}
|
|
|
|
render() {
|
|
const shouldHide = this.autoHide && this.tabs.length <= this.threshold;
|
|
|
|
return html`
|
|
<div class="tabs-container">
|
|
${shouldHide
|
|
? html`<span class="placeholder">Tabs hidden (${this.tabs.length} tabs ≤ threshold ${this.threshold})</span>`
|
|
: html`<dees-appui-tabs
|
|
.tabs=${this.tabs}
|
|
.autoHide=${this.autoHide}
|
|
.autoHideThreshold=${this.threshold}
|
|
></dees-appui-tabs>`
|
|
}
|
|
</div>
|
|
<div class="controls">
|
|
<button @click=${() => this.addTab()}>+ Add Tab</button>
|
|
<button class="danger" @click=${() => this.removeLastTab()}>- Remove Tab</button>
|
|
<button class="danger" @click=${() => this.clearTabs()}>Clear All</button>
|
|
<button @click=${() => { this.threshold = 0; }}>Threshold: 0</button>
|
|
<button @click=${() => { this.threshold = 1; }}>Threshold: 1</button>
|
|
<button @click=${() => { this.threshold = 2; }}>Threshold: 2</button>
|
|
</div>
|
|
<div class="info">
|
|
Auto-hide: ${this.autoHide ? 'ON' : 'OFF'} | Threshold: ${this.threshold} | Tabs: ${this.tabs.length}
|
|
<br>Tabs will hide when count ≤ threshold.
|
|
</div>
|
|
`;
|
|
}
|
|
}
|
|
|
|
export const demoFunc = () => {
|
|
const horizontalTabs: interfaces.IMenuItem[] = [
|
|
{ key: 'Home', iconName: 'lucide:home', action: () => console.log('Home clicked') },
|
|
{ key: 'Analytics Dashboard', iconName: 'lucide:lineChart', action: () => console.log('Analytics clicked') },
|
|
{ key: 'Reports', iconName: 'lucide:fileText', action: () => console.log('Reports clicked') },
|
|
{ key: 'User Settings', iconName: 'lucide:settings', action: () => console.log('Settings clicked') },
|
|
{ key: 'Help', iconName: 'lucide:helpCircle', action: () => console.log('Help clicked') },
|
|
];
|
|
|
|
const verticalTabs: interfaces.IMenuItem[] = [
|
|
{ key: 'Profile', iconName: 'lucide:user', action: () => console.log('Profile clicked') },
|
|
{ key: 'Security', iconName: 'lucide:shield', action: () => console.log('Security clicked') },
|
|
{ key: 'Notifications', iconName: 'lucide:bell', action: () => console.log('Notifications clicked') },
|
|
{ key: 'Integrations', iconName: 'lucide:link', action: () => console.log('Integrations clicked') },
|
|
{ key: 'Advanced', iconName: 'lucide:code', action: () => console.log('Advanced clicked') },
|
|
];
|
|
|
|
const noIndicatorTabs: interfaces.IMenuItem[] = [
|
|
{ key: 'All', action: () => console.log('All clicked') },
|
|
{ key: 'Active', action: () => console.log('Active clicked') },
|
|
{ key: 'Completed', action: () => console.log('Completed clicked') },
|
|
{ key: 'Archived', action: () => console.log('Archived clicked') },
|
|
];
|
|
|
|
const demoContent = (text: string) => html`
|
|
<div style="padding: 24px; color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};">
|
|
${text}
|
|
</div>
|
|
`;
|
|
|
|
return html`
|
|
<style>
|
|
.demo-container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 32px;
|
|
padding: 48px;
|
|
background: ${cssManager.bdTheme('#f8f9fa', '#0a0a0a')};
|
|
min-height: 100vh;
|
|
}
|
|
|
|
.section {
|
|
background: ${cssManager.bdTheme('#ffffff', '#18181b')};
|
|
border: 1px solid ${cssManager.bdTheme('#e5e7eb', '#27272a')};
|
|
border-radius: 8px;
|
|
padding: 24px;
|
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.section-title {
|
|
font-size: 18px;
|
|
font-weight: 600;
|
|
margin-bottom: 16px;
|
|
color: ${cssManager.bdTheme('#09090b', '#fafafa')};
|
|
}
|
|
|
|
.two-column {
|
|
display: grid;
|
|
grid-template-columns: 200px 1fr;
|
|
gap: 24px;
|
|
align-items: start;
|
|
}
|
|
</style>
|
|
<div class="demo-container">
|
|
<div class="section">
|
|
<div class="section-title">Horizontal Tabs with Animated Indicator</div>
|
|
<dees-appui-tabs .tabs=${horizontalTabs}></dees-appui-tabs>
|
|
${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.')}
|
|
</div>
|
|
|
|
<div class="section">
|
|
<div class="section-title">Closeable Tabs (Browser-style)</div>
|
|
<demo-closeable-tabs></demo-closeable-tabs>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<div class="section-title">Auto-hide Tabs</div>
|
|
<demo-autohide-tabs></demo-autohide-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}></dees-appui-tabs>
|
|
${demoContent('Tabs can also be used without the animated indicator by setting showTabIndicator to false.')}
|
|
</div>
|
|
</div>
|
|
`;
|
|
};
|