import { api } from '../api.js'; import './login-view.js'; import './file-list.js'; import './file-upload-view.js'; import './share-modal.js'; import './photo-gallery.js'; import './file-preview.js'; 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 './billing-dashboard.js'; import './admin-billing.js'; import './code-editor-view.js'; import { shortcuts } from '../shortcuts.js'; export class RBoxApp extends HTMLElement { constructor() { super(); this.currentView = 'files'; this.user = null; this.navigationStack = []; } async connectedCallback() { await this.init(); this.addEventListener('show-toast', this.handleShowToast); window.addEventListener('popstate', this.handlePopState.bind(this)); } 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); } async init() { if (!api.getToken()) { this.showLogin(); } else { try { this.user = await api.getCurrentUser(); this.render(); } catch (error) { this.showLogin(); } } } showLogin() { this.innerHTML = ''; const loginView = this.querySelector('login-view'); loginView.addEventListener('auth-success', () => this.init()); } render() { this.innerHTML = `

RBox

`; this.initializeNavigation(); this.attachListeners(); this.registerShortcuts(); } initializeNavigation() { if (!window.history.state) { const hash = window.location.hash.slice(1); if (hash && hash !== '') { const view = hash.split('/')[0]; const validViews = ['files', 'photos', 'shared', 'deleted', 'starred', 'recent', 'admin', 'billing', 'admin-billing']; if (validViews.includes(view)) { window.history.replaceState({ view: view }, '', `#${hash}`); this.currentView = view; } else { window.history.replaceState({ view: 'files' }, '', '#files'); } } else { window.history.replaceState({ view: 'files' }, '', '#files'); } } } registerShortcuts() { shortcuts.register('ctrl+u', () => { const fileList = this.querySelector('file-list'); const folderId = fileList ? fileList.currentFolderId : null; this.showUpload(folderId); }); 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'); }); shortcuts.register('5', () => { if (this.user && this.user.is_superuser) { this.switchView('admin'); } }); shortcuts.register('f2', () => { const fileListComponent = document.querySelector('file-list'); if (fileListComponent && fileListComponent.selectedFiles && fileListComponent.selectedFiles.size === 1) { const fileId = Array.from(fileListComponent.selectedFiles)[0]; const file = fileListComponent.files.find(f => f.id === fileId); if (file) { const newName = prompt('Enter new name:', file.name); if (newName && newName !== file.name) { api.renameFile(fileId, newName).then(() => { fileListComponent.loadContents(fileListComponent.currentFolderId); document.dispatchEvent(new CustomEvent('show-toast', { detail: { message: 'File renamed successfully', type: 'success' } })); }).catch(error => { document.dispatchEvent(new CustomEvent('show-toast', { detail: { message: 'Failed to rename file', type: 'error' } })); }); } } } else if (fileListComponent && fileListComponent.selectedFolders && fileListComponent.selectedFolders.size === 1) { const folderId = Array.from(fileListComponent.selectedFolders)[0]; const folder = fileListComponent.folders.find(f => f.id === folderId); if (folder) { const newName = prompt('Enter new name:', folder.name); if (newName && newName !== folder.name) { api.updateFolder(folderId, { name: newName }).then(() => { fileListComponent.loadContents(fileListComponent.currentFolderId); document.dispatchEvent(new CustomEvent('show-toast', { detail: { message: 'Folder renamed successfully', type: 'success' } })); }).catch(error => { document.dispatchEvent(new CustomEvent('show-toast', { detail: { message: 'Failed to rename folder', type: 'error' } })); }); } } } }); } showShortcutsHelp() { const helpContent = `

Keyboard Shortcuts

File Operations

Ctrl + U Upload files
Ctrl + Shift + N Create new folder
Ctrl + F Focus search

Navigation

1 My Files
2 Photo Gallery
3 Shared Items
4 Deleted Files
${this.user && this.user.is_superuser ? `
5 Admin Dashboard
` : ''}

General

ESC Close modals
Ctrl + / Show this help
`; 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', (e) => { this.showUpload(e.detail.folderId); }); fileList.addEventListener('folder-open', (e) => { fileList.loadContents(e.detail.folderId); }); fileList.addEventListener('share-request', (e) => { const modal = this.querySelector('share-modal'); modal.show(e.detail.fileId); }); } this.addEventListener('upload-complete', () => { const fileList = this.querySelector('file-list'); if (fileList) { fileList.loadContents(fileList.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) => { this.showFilePreview(e.detail.photo); }); this.addEventListener('share-file', (e) => { const modal = this.querySelector('share-modal'); modal.show(e.detail.file.id); }); this.addEventListener('edit-file', (e) => { this.showCodeEditor(e.detail.file); }); } handlePopState(e) { this.closeAllOverlays(); if (e.state && e.state.view) { if (e.state.view === 'code-editor' && e.state.file) { this.showCodeEditor(e.state.file, false); } else if (e.state.view === 'file-preview' && e.state.file) { this.showFilePreview(e.state.file, false); } else if (e.state.view === 'upload') { const folderId = e.state.folderId !== undefined ? e.state.folderId : null; this.showUpload(folderId, false); } else { this.switchView(e.state.view, false); } } else { this.switchView('files', false); } } closeAllOverlays() { const existingEditor = this.querySelector('code-editor-view'); if (existingEditor) { existingEditor.hide(); } const existingPreview = this.querySelector('file-preview'); if (existingPreview) { existingPreview.hide(); } const existingUpload = this.querySelector('file-upload-view'); if (existingUpload) { existingUpload.hide(); } const shareModal = this.querySelector('share-modal'); if (shareModal && shareModal.style.display !== 'none') { shareModal.style.display = 'none'; } } showCodeEditor(file, pushState = true) { this.closeAllOverlays(); const mainElement = this.querySelector('.app-main'); const editorView = document.createElement('code-editor-view'); mainElement.appendChild(editorView); editorView.setFile(file, this.currentView); if (pushState) { window.history.pushState( { view: 'code-editor', file: file }, '', `#editor/${file.id}` ); } } showFilePreview(file, pushState = true) { this.closeAllOverlays(); const mainElement = this.querySelector('.app-main'); const preview = document.createElement('file-preview'); mainElement.appendChild(preview); preview.show(file, false); if (pushState) { window.history.pushState( { view: 'file-preview', file: file }, '', `#preview/${file.id}` ); } } showUpload(folderId = null, pushState = true) { this.closeAllOverlays(); const mainElement = this.querySelector('.app-main'); const uploadView = document.createElement('file-upload-view'); mainElement.appendChild(uploadView); uploadView.setFolder(folderId); if (pushState) { window.history.pushState( { view: 'upload', folderId: folderId }, '', '#upload' ); } } async performSearch(query) { try { const files = await api.searchFiles(query); const mainContent = this.querySelector('#main-content'); mainContent.innerHTML = `

Search Results for "${query}"

`; const fileList = mainContent.querySelector('file-list'); fileList.setFiles(files); this.attachListeners(); } catch (error) { console.error('Search failed:', error); } } switchView(view, pushState = true) { this.closeAllOverlays(); if(this.currentView === view) return; 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'); if (pushState) { window.history.pushState({ view: view }, '', `#${view}`); } switch (view) { case 'files': mainContent.innerHTML = ''; this.attachListeners(); break; case 'photos': mainContent.innerHTML = ''; this.attachListeners(); break; case 'shared': mainContent.innerHTML = ''; this.attachListeners(); break; case 'deleted': mainContent.innerHTML = ''; this.attachListeners(); break; case 'starred': mainContent.innerHTML = ''; this.attachListeners(); break; case 'recent': mainContent.innerHTML = ''; this.attachListeners(); break; case 'admin': mainContent.innerHTML = ''; this.attachListeners(); break; case 'billing': mainContent.innerHTML = ''; this.attachListeners(); break; case 'admin-billing': mainContent.innerHTML = ''; this.attachListeners(); break; } } }