148 lines
5.4 KiB
JavaScript
148 lines
5.4 KiB
JavaScript
|
|
import { api } from '../api.js';
|
||
|
|
|
||
|
|
export class StarredItems extends HTMLElement {
|
||
|
|
constructor() {
|
||
|
|
super();
|
||
|
|
this.starredFiles = [];
|
||
|
|
this.starredFolders = [];
|
||
|
|
}
|
||
|
|
|
||
|
|
async connectedCallback() {
|
||
|
|
await this.loadStarredItems();
|
||
|
|
}
|
||
|
|
|
||
|
|
async loadStarredItems() {
|
||
|
|
try {
|
||
|
|
this.starredFiles = await api.listStarredFiles();
|
||
|
|
this.starredFolders = await api.listStarredFolders();
|
||
|
|
this.render();
|
||
|
|
} catch (error) {
|
||
|
|
console.error('Failed to load starred items:', error);
|
||
|
|
document.dispatchEvent(new CustomEvent('show-toast', {
|
||
|
|
detail: { message: 'Failed to load starred items: ' + error.message, type: 'error' }
|
||
|
|
}));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
render() {
|
||
|
|
const allStarred = [...this.starredFolders, ...this.starredFiles];
|
||
|
|
|
||
|
|
if (allStarred.length === 0) {
|
||
|
|
this.innerHTML = `
|
||
|
|
<div class="starred-items-container">
|
||
|
|
<h2>Starred Items</h2>
|
||
|
|
<p class="empty-state">No starred items found.</p>
|
||
|
|
</div>
|
||
|
|
`;
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
this.innerHTML = `
|
||
|
|
<div class="starred-items-container">
|
||
|
|
<h2>Starred Items</h2>
|
||
|
|
<div class="file-grid">
|
||
|
|
${this.starredFolders.map(folder => this.renderFolder(folder)).join('')}
|
||
|
|
${this.starredFiles.map(file => this.renderFile(file)).join('')}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
`;
|
||
|
|
this.attachListeners();
|
||
|
|
}
|
||
|
|
|
||
|
|
renderFolder(folder) {
|
||
|
|
return `
|
||
|
|
<div class="file-item folder-item" data-folder-id="${folder.id}">
|
||
|
|
<div class="file-icon">📁</div>
|
||
|
|
<div class="file-name">${folder.name}</div>
|
||
|
|
<div class="file-actions-menu">
|
||
|
|
<button class="action-btn star-btn" data-action="unstar-folder" data-id="${folder.id}">★</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
`;
|
||
|
|
}
|
||
|
|
|
||
|
|
renderFile(file) {
|
||
|
|
const icon = this.getFileIcon(file.mime_type);
|
||
|
|
const size = this.formatFileSize(file.size);
|
||
|
|
|
||
|
|
return `
|
||
|
|
<div class="file-item" data-file-id="${file.id}">
|
||
|
|
<div class="file-icon">${icon}</div>
|
||
|
|
<div class="file-name">${file.name}</div>
|
||
|
|
<div class="file-size">${size}</div>
|
||
|
|
<div class="file-actions-menu">
|
||
|
|
<button class="action-btn" data-action="download" data-id="${file.id}">Download</button>
|
||
|
|
<button class="action-btn star-btn" data-action="unstar-file" data-id="${file.id}">★</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
`;
|
||
|
|
}
|
||
|
|
|
||
|
|
getFileIcon(mimeType) {
|
||
|
|
if (mimeType.startsWith('image/')) return '📷';
|
||
|
|
if (mimeType.startsWith('video/')) return '🎥';
|
||
|
|
if (mimeType.startsWith('audio/')) return '🎵';
|
||
|
|
if (mimeType.includes('pdf')) return '📄';
|
||
|
|
if (mimeType.includes('text')) return '📄';
|
||
|
|
return '📄';
|
||
|
|
}
|
||
|
|
|
||
|
|
formatFileSize(bytes) {
|
||
|
|
if (bytes < 1024) return bytes + ' B';
|
||
|
|
if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB';
|
||
|
|
if (bytes < 1073741824) return (bytes / 1048576).toFixed(1) + ' MB';
|
||
|
|
return (bytes / 1073741824).toFixed(1) + ' GB';
|
||
|
|
}
|
||
|
|
|
||
|
|
attachListeners() {
|
||
|
|
this.querySelectorAll('.action-btn').forEach(btn => {
|
||
|
|
btn.addEventListener('click', async (e) => {
|
||
|
|
e.stopPropagation();
|
||
|
|
const action = btn.dataset.action;
|
||
|
|
const id = parseInt(btn.dataset.id);
|
||
|
|
await this.handleAction(action, id);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
async handleAction(action, id) {
|
||
|
|
try {
|
||
|
|
switch (action) {
|
||
|
|
case 'download':
|
||
|
|
const blob = await api.downloadFile(id);
|
||
|
|
const file = this.starredFiles.find(f => f.id === id);
|
||
|
|
const url = URL.createObjectURL(blob);
|
||
|
|
const a = document.createElement('a');
|
||
|
|
a.href = url;
|
||
|
|
a.download = file.name;
|
||
|
|
a.click();
|
||
|
|
URL.revokeObjectURL(url);
|
||
|
|
document.dispatchEvent(new CustomEvent('show-toast', {
|
||
|
|
detail: { message: 'File downloaded successfully!', type: 'success' }
|
||
|
|
}));
|
||
|
|
break;
|
||
|
|
case 'unstar-file':
|
||
|
|
await api.unstarFile(id);
|
||
|
|
document.dispatchEvent(new CustomEvent('show-toast', {
|
||
|
|
detail: { message: 'File unstarred successfully!', type: 'success' }
|
||
|
|
}));
|
||
|
|
await this.loadStarredItems();
|
||
|
|
break;
|
||
|
|
case 'unstar-folder':
|
||
|
|
await api.unstarFolder(id);
|
||
|
|
document.dispatchEvent(new CustomEvent('show-toast', {
|
||
|
|
detail: { message: 'Folder unstarred successfully!', type: 'success' }
|
||
|
|
}));
|
||
|
|
await this.loadStarredItems();
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
} catch (error) {
|
||
|
|
document.dispatchEvent(new CustomEvent('show-toast', {
|
||
|
|
detail: { message: 'Action failed: ' + error.message, type: 'error' }
|
||
|
|
}));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
customElements.define('starred-items', StarredItems);
|