feat(components): add large set of new UI components and demos, reorganize groups, and bump a few dependencies

This commit is contained in:
2026-01-27 10:57:42 +00:00
parent 8158b791c7
commit 162688cdb5
218 changed files with 5223 additions and 458 deletions

View File

@@ -0,0 +1,181 @@
import {
property,
html,
customElement,
css,
cssManager,
type TemplateResult,
type CSSResult,
} from '@design.estate/dees-element';
import { DeesTileBase } from '../dees-tile-shared/DeesTileBase.js';
import { tileBaseStyles } from '../dees-tile-shared/styles.js';
import { demo } from './demo.js';
export interface ITileFolderItem {
type: 'pdf' | 'image' | 'audio' | 'video' | 'note' | 'folder' | 'unknown';
thumbnailSrc?: string;
name: string;
}
const TYPE_ICON_MAP: Record<string, string> = {
pdf: 'lucide:FileText',
image: 'lucide:Image',
audio: 'lucide:Music',
video: 'lucide:Video',
note: 'lucide:FileCode',
folder: 'lucide:Folder',
unknown: 'lucide:File',
};
declare global {
interface HTMLElementTagNameMap {
'dees-tile-folder': DeesTileFolder;
}
}
@customElement('dees-tile-folder')
export class DeesTileFolder extends DeesTileBase {
public static demo = demo;
public static demoGroups = ['Media'];
public static styles = [
...tileBaseStyles,
css`
.folder-content {
position: relative;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
background: ${cssManager.bdTheme('hsl(40 30% 97%)', 'hsl(215 20% 14%)')};
overflow: hidden;
}
.folder-header {
display: flex;
align-items: center;
gap: 8px;
padding: 12px 14px 8px;
flex-shrink: 0;
}
.folder-icon {
font-size: 18px;
color: ${cssManager.bdTheme('hsl(40 80% 50%)', 'hsl(40 70% 60%)')};
}
.folder-name {
font-size: 12px;
font-weight: 700;
color: ${cssManager.bdTheme('hsl(215 20% 20%)', 'hsl(215 16% 80%)')};
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex: 1;
}
.preview-grid {
flex: 1;
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
gap: 4px;
padding: 0 14px 14px;
min-height: 0;
}
.grid-cell {
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
overflow: hidden;
background: ${cssManager.bdTheme('hsl(215 20% 94%)', 'hsl(215 20% 18%)')};
position: relative;
}
.grid-cell img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.grid-cell dees-icon {
font-size: 20px;
color: ${cssManager.bdTheme('hsl(215 16% 60%)', 'hsl(215 16% 55%)')};
}
.grid-cell-empty {
background: ${cssManager.bdTheme('hsl(215 15% 96%)', 'hsl(215 20% 16%)')};
}
.item-count-badge {
position: absolute;
bottom: 8px;
right: 8px;
padding: 3px 8px;
background: ${cssManager.bdTheme('hsl(0 0% 0% / 0.6)', 'hsl(0 0% 100% / 0.85)')};
color: ${cssManager.bdTheme('white', 'hsl(215 20% 12%)')};
border-radius: 4px;
font-size: 10px;
font-weight: 600;
backdrop-filter: blur(8px);
z-index: 10;
}
`,
] as any;
@property({ type: String })
accessor name: string = '';
@property({ attribute: false })
accessor items: ITileFolderItem[] = [];
protected renderTileContent(): TemplateResult {
const previewItems = this.items.slice(0, 4);
const emptyCells = 4 - previewItems.length;
return html`
<div class="folder-content">
<div class="folder-header">
<dees-icon class="folder-icon" icon="lucide:Folder"></dees-icon>
<div class="folder-name">${this.name || 'Untitled Folder'}</div>
</div>
<div class="preview-grid">
${previewItems.map((item) => html`
<div class="grid-cell">
${item.thumbnailSrc ? html`
<img src="${item.thumbnailSrc}" alt="${item.name}" />
` : html`
<dees-icon icon="${TYPE_ICON_MAP[item.type] || TYPE_ICON_MAP.unknown}"></dees-icon>
`}
</div>
`)}
${Array.from({ length: emptyCells }).map(() => html`
<div class="grid-cell grid-cell-empty"></div>
`)}
</div>
</div>
<div class="item-count-badge">
${this.items.length} item${this.items.length !== 1 ? 's' : ''}
</div>
${this.clickable ? html`
<div class="tile-overlay">
<dees-icon icon="lucide:FolderOpen"></dees-icon>
<span>Open Folder</span>
</div>
` : ''}
`;
}
protected getTileClickDetail(): Record<string, unknown> {
return {
name: this.name,
itemCount: this.items.length,
items: this.items,
};
}
}