388 lines
14 KiB
JavaScript
Raw Normal View History

2025-11-09 23:29:07 +01:00
import { api } from '../api.js';
import './login-view.js';
import './file-list.js';
import './file-upload.js';
import './share-modal.js';
import './photo-gallery.js';
import './file-preview.js';
2025-11-10 01:58:41 +01:00
import './deleted-files.js';
import './admin-dashboard.js';
import './toast-notification.js';
import './starred-items.js';
import './recent-files.js';
import './shared-items.js'; // Import the new component
2025-11-09 23:29:07 +01:00
import { shortcuts } from '../shortcuts.js';
export class RBoxApp extends HTMLElement {
constructor() {
super();
this.currentView = 'files';
this.currentFolderId = null;
this.user = null;
}
async connectedCallback() {
await this.init();
2025-11-10 01:58:41 +01:00
this.addEventListener('show-toast', this.handleShowToast);
}
disconnectedCallback() {
this.removeEventListener('show-toast', this.handleShowToast);
}
handleShowToast = (event) => {
const { message, type, duration } = event.detail;
this.showToast(message, type, duration);
}
showToast(message, type = 'info', duration = 3000) {
const toast = document.createElement('toast-notification');
document.body.appendChild(toast);
toast.show(message, type, duration);
2025-11-09 23:29:07 +01:00
}
async init() {
if (!api.getToken()) {
this.showLogin();
} else {
try {
this.user = await api.getCurrentUser();
this.render();
} catch (error) {
this.showLogin();
}
}
}
showLogin() {
this.innerHTML = '<login-view></login-view>';
const loginView = this.querySelector('login-view');
loginView.addEventListener('auth-success', () => this.init());
}
render() {
this.innerHTML = `
<div class="app-container">
<header class="app-header">
<div class="header-left">
<h1 class="app-title">RBox</h1>
</div>
<div class="header-center">
<input type="search" placeholder="Search..." class="search-input" id="search-input">
</div>
<div class="header-right">
<span class="user-info">${this.user.username}</span>
<button class="button" id="logout-btn">Logout</button>
</div>
</header>
<div class="app-body">
<aside class="app-sidebar">
<nav class="sidebar-nav">
<h3 class="nav-title">Navigation</h3>
<ul class="nav-list">
<li><a href="#" class="nav-link active" data-view="files">My Files</a></li>
<li><a href="#" class="nav-link" data-view="photos">Photo Gallery</a></li>
<li><a href="#" class="nav-link" data-view="shared">Shared Items</a></li>
<li><a href="#" class="nav-link" data-view="deleted">Deleted Files</a></li>
2025-11-10 01:58:41 +01:00
${this.user && this.user.is_superuser ? `<li><a href="#" class="nav-link" data-view="admin">Admin Dashboard</a></li>` : ''}
2025-11-09 23:29:07 +01:00
</ul>
<h3 class="nav-title">Quick Access</h3>
<ul class="nav-list">
<li><a href="#" class="nav-link" data-view="starred">Starred</a></li>
<li><a href="#" class="nav-link" data-view="recent">Recent</a></li>
</ul>
</nav>
</aside>
<main class="app-main">
<div id="main-content">
<file-list></file-list>
</div>
</main>
</div>
<file-upload></file-upload>
<share-modal></share-modal>
<file-preview></file-preview>
</div>
`;
this.attachListeners();
this.registerShortcuts();
}
registerShortcuts() {
shortcuts.register('ctrl+u', () => {
const upload = this.querySelector('file-upload');
if (upload) {
upload.setFolder(this.currentFolderId);
upload.show();
}
});
shortcuts.register('ctrl+f', () => {
const searchInput = this.querySelector('#search-input');
if (searchInput) {
searchInput.focus();
}
});
shortcuts.register('ctrl+/', () => {
this.showShortcutsHelp();
});
shortcuts.register('ctrl+shift+n', () => {
if (this.currentView === 'files') {
const fileList = this.querySelector('file-list');
if (fileList) {
fileList.triggerCreateFolder();
}
}
});
shortcuts.register('1', () => {
this.switchView('files');
});
shortcuts.register('2', () => {
this.switchView('photos');
});
shortcuts.register('3', () => {
this.switchView('shared');
});
shortcuts.register('4', () => {
this.switchView('deleted');
});
2025-11-10 01:58:41 +01:00
shortcuts.register('5', () => {
if (this.user && this.user.is_superuser) {
this.switchView('admin');
}
});
2025-11-09 23:29:07 +01:00
shortcuts.register('f2', () => {
console.log('Rename shortcut - to be implemented');
});
}
showShortcutsHelp() {
const helpContent = `
<div class="shortcuts-help-modal">
<div class="shortcuts-help-content">
<h2>Keyboard Shortcuts</h2>
<div class="shortcuts-list">
<h3>File Operations</h3>
<div class="shortcut-item">
<kbd>Ctrl + U</kbd>
<span>Upload files</span>
</div>
<div class="shortcut-item">
<kbd>Ctrl + Shift + N</kbd>
<span>Create new folder</span>
</div>
<div class="shortcut-item">
<kbd>Ctrl + F</kbd>
<span>Focus search</span>
</div>
<h3>Navigation</h3>
<div class="shortcut-item">
<kbd>1</kbd>
<span>My Files</span>
</div>
<div class="shortcut-item">
<kbd>2</kbd>
<span>Photo Gallery</span>
</div>
<div class="shortcut-item">
<kbd>3</kbd>
<span>Shared Items</span>
</div>
<div class="shortcut-item">
<kbd>4</kbd>
<span>Deleted Files</span>
</div>
2025-11-10 01:58:41 +01:00
${this.user && this.user.is_superuser ? `
<div class="shortcut-item">
<kbd>5</kbd>
<span>Admin Dashboard</span>
</div>` : ''}
2025-11-09 23:29:07 +01:00
<h3>General</h3>
<div class="shortcut-item">
<kbd>ESC</kbd>
<span>Close modals</span>
</div>
<div class="shortcut-item">
<kbd>Ctrl + /</kbd>
<span>Show this help</span>
</div>
</div>
<button class="button" id="close-shortcuts-help">Close</button>
</div>
</div>
`;
const helpDiv = document.createElement('div');
helpDiv.innerHTML = helpContent;
helpDiv.querySelector('.shortcuts-help-modal').style.cssText = `
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 10000;
`;
document.body.appendChild(helpDiv);
const closeHelp = () => {
document.body.removeChild(helpDiv);
document.removeEventListener('keydown', handleEscape);
};
const handleEscape = (e) => {
if (e.key === 'Escape') {
closeHelp();
}
};
const closeBtn = helpDiv.querySelector('#close-shortcuts-help');
closeBtn.addEventListener('click', closeHelp);
helpDiv.querySelector('.shortcuts-help-modal').addEventListener('click', (e) => {
if (e.target.classList.contains('shortcuts-help-modal')) closeHelp();
});
document.addEventListener('keydown', handleEscape);
}
attachListeners() {
this.querySelector('#logout-btn')?.addEventListener('click', () => {
api.logout();
});
this.querySelectorAll('.nav-link').forEach(link => {
link.addEventListener('click', (e) => {
e.preventDefault();
const view = link.dataset.view;
this.switchView(view);
});
});
const fileList = this.querySelector('file-list');
if (fileList) {
fileList.addEventListener('upload-request', () => {
const upload = this.querySelector('file-upload');
upload.setFolder(this.currentFolderId);
upload.show();
});
fileList.addEventListener('folder-open', (e) => {
this.currentFolderId = e.detail.folderId;
fileList.loadContents(this.currentFolderId);
});
fileList.addEventListener('share-request', (e) => {
const modal = this.querySelector('share-modal');
modal.show(e.detail.fileId);
});
}
const upload = this.querySelector('file-upload');
if (upload) {
upload.addEventListener('upload-complete', () => {
const fileList = this.querySelector('file-list');
fileList.loadContents(this.currentFolderId);
});
}
const searchInput = this.querySelector('#search-input');
if (searchInput) {
let searchTimeout;
searchInput.addEventListener('input', (e) => {
clearTimeout(searchTimeout);
const query = e.target.value.trim();
if (query.length > 0) {
searchTimeout = setTimeout(() => this.performSearch(query), 300);
}
});
}
this.addEventListener('photo-click', (e) => {
const preview = this.querySelector('file-preview');
preview.show(e.detail.photo);
});
this.addEventListener('share-file', (e) => {
const modal = this.querySelector('share-modal');
modal.show(e.detail.file.id);
});
}
async performSearch(query) {
try {
const files = await api.searchFiles(query);
const mainContent = this.querySelector('#main-content');
mainContent.innerHTML = `
<div class="search-results">
<h2>Search Results for "${query}"</h2>
<file-list data-search-mode="true"></file-list>
</div>
`;
const fileList = mainContent.querySelector('file-list');
fileList.setFiles(files);
this.attachListeners();
} catch (error) {
console.error('Search failed:', error);
}
}
switchView(view) {
this.currentView = view;
this.querySelectorAll('.nav-link').forEach(link => {
link.classList.remove('active');
});
this.querySelector(`[data-view="${view}"]`)?.classList.add('active');
const mainContent = this.querySelector('#main-content');
switch (view) {
case 'files':
mainContent.innerHTML = '<file-list></file-list>';
this.attachListeners();
break;
case 'photos':
mainContent.innerHTML = '<photo-gallery></photo-gallery>';
this.attachListeners();
break;
case 'shared':
2025-11-10 01:58:41 +01:00
mainContent.innerHTML = '<shared-items></shared-items>';
this.attachListeners();
2025-11-09 23:29:07 +01:00
break;
case 'deleted':
2025-11-10 01:58:41 +01:00
mainContent.innerHTML = '<deleted-files></deleted-files>';
this.attachListeners(); // Re-attach listeners for the new component
2025-11-09 23:29:07 +01:00
break;
case 'starred':
2025-11-10 01:58:41 +01:00
mainContent.innerHTML = '<starred-items></starred-items>';
this.attachListeners();
2025-11-09 23:29:07 +01:00
break;
case 'recent':
2025-11-10 01:58:41 +01:00
mainContent.innerHTML = '<recent-files></recent-files>';
this.attachListeners();
break;
case 'admin':
mainContent.innerHTML = '<admin-dashboard></admin-dashboard>';
this.attachListeners();
2025-11-09 23:29:07 +01:00
break;
}
}
}