169 lines
4.2 KiB
TypeScript
169 lines
4.2 KiB
TypeScript
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%)')};
|
|
}
|
|
|
|
`,
|
|
] 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="tile-badge-corner">
|
|
${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,
|
|
};
|
|
}
|
|
}
|