diff options
Diffstat (limited to 'src/main/resources/templates/index.html')
| -rw-r--r-- | src/main/resources/templates/index.html | 573 |
1 files changed, 0 insertions, 573 deletions
diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html deleted file mode 100644 index 98bc45e..0000000 --- a/src/main/resources/templates/index.html +++ /dev/null @@ -1,573 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> -<head> - <meta charset="UTF-8"> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <title>File Storage</title> - <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet"> - <script src="https://unpkg.com/htmx.org@1.9.10"></script> - <style> - /* === RESET & BASE === */ - * { - margin: 0; - padding: 0; - box-sizing: border-box; - } - - body { - background-color: #36393f; - color: #dcddde; - font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; - font-size: 14px; - line-height: 1.4; - } - - /* === LAYOUT === */ - .app-container { - min-height: 100vh; - display: flex; - flex-direction: column; - } - - /* === HEADER === */ - .header { - background-color: #2f3136; - padding: 12px 20px; - border-bottom: 1px solid #202225; - display: flex; - align-items: center; - justify-content: space-between; - position: sticky; - top: 0; - z-index: 100; - } - - .header-left { - display: flex; - align-items: center; - gap: 12px; - } - - .header-title { - font-size: 16px; - font-weight: 600; - color: #ffffff; - display: flex; - align-items: center; - gap: 8px; - } - - .header-subtitle { - font-size: 12px; - color: #72767d; - } - - .header-actions { - display: flex; - gap: 8px; - } - - /* === BUTTONS === */ - .btn { - background-color: transparent; - border: none; - color: #b9bbbe; - padding: 6px 12px; - border-radius: 4px; - font-size: 12px; - cursor: pointer; - transition: all 0.2s; - display: flex; - align-items: center; - gap: 4px; - } - - .btn:hover { - background-color: #40444b; - color: #ffffff; - } - - .btn-primary { - background-color: #5865f2; - color: #ffffff; - } - - .btn-primary:hover { - background-color: #4752c4; - } - - /* === MAIN CONTENT === */ - .main-content { - flex: 1; - padding: 20px; - overflow-y: auto; - } - - /* === SEARCH BAR === */ - .search-bar { - display: flex; - gap: 12px; - margin-bottom: 20px; - flex-wrap: wrap; - } - - .search-input { - flex: 1; - min-width: 200px; - background-color: #40444b; - border: 1px solid #202225; - border-radius: 4px; - padding: 8px 12px; - color: #dcddde; - font-size: 14px; - outline: none; - } - - .search-input:focus { - border-color: #5865f2; - } - - .search-input::placeholder { - color: #72767d; - } - - .select { - background-color: #40444b; - border: 1px solid #202225; - border-radius: 4px; - padding: 8px 12px; - color: #dcddde; - font-size: 14px; - cursor: pointer; - outline: none; - } - - .select:focus { - border-color: #5865f2; - } - - /* === STATS === */ - .stats { - display: flex; - gap: 16px; - margin-bottom: 20px; - align-items: center; - } - - .stat-item { - display: flex; - align-items: center; - gap: 6px; - color: #72767d; - font-size: 12px; - } - - .stat-number { - color: #ffffff; - font-weight: 600; - } - - /* === FILE CONTAINER === */ - .file-container { - background-color: #2f3136; - border-radius: 8px; - border: 1px solid #202225; - overflow: hidden; - } - - /* === FILE TABLE === */ - .file-table { - width: 100%; - border-collapse: collapse; - } - - .file-table th { - background-color: #36393f; - padding: 12px 16px; - text-align: left; - font-size: 12px; - font-weight: 600; - color: #72767d; - text-transform: uppercase; - border-bottom: 1px solid #202225; - } - - .file-table td { - padding: 12px 16px; - border-bottom: 1px solid #202225; - vertical-align: middle; - } - - .file-table tbody tr:hover { - background-color: #36393f; - } - - .file-table tbody tr:last-child td { - border-bottom: none; - } - - /* === FILE ELEMENTS === */ - .file-link { - color: #00aff4; - text-decoration: none; - display: flex; - align-items: center; - gap: 8px; - font-weight: 500; - } - - .file-link:hover { - color: #ffffff; - text-decoration: underline; - } - - .file-icon { - color: #72767d; - width: 16px; - text-align: center; - } - - .file-description { - color: #b9bbbe; - max-width: 200px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - .file-size { - color: #72767d; - font-size: 12px; - font-family: 'Courier New', monospace; - } - - .file-type { - background-color: #5865f2; - color: #ffffff; - padding: 2px 6px; - border-radius: 12px; - font-size: 10px; - font-weight: 600; - text-transform: uppercase; - } - - .file-date { - color: #72767d; - font-size: 12px; - } - - /* === EMPTY STATE === */ - .empty-state { - text-align: center; - padding: 60px 20px; - color: #72767d; - } - - .empty-state-icon { - font-size: 48px; - margin-bottom: 16px; - opacity: 0.5; - } - - .empty-state h3 { - color: #b9bbbe; - margin-bottom: 8px; - font-size: 18px; - font-weight: 600; - } - - .empty-state p { - font-size: 14px; - line-height: 1.5; - } - - /* === LOADING STATES === */ - .htmx-indicator { - display: none; - } - - .htmx-request .htmx-indicator { - display: inline; - } - - .loading-spinner { - animation: spin 1s linear infinite; - } - - @keyframes spin { - from { transform: rotate(0deg); } - to { transform: rotate(360deg); } - } - - /* === RESPONSIVE === */ - @media (max-width: 768px) { - .search-bar { - flex-direction: column; - } - - .search-input { - min-width: 100%; - } - - .file-table th:nth-child(3), - .file-table td:nth-child(3), - .file-table th:nth-child(4), - .file-table td:nth-child(4), - .file-table th:nth-child(5), - .file-table td:nth-child(5) { - display: none; - } - - .header { - padding: 8px 16px; - } - - .main-content { - padding: 16px; - } - } - </style> -</head> -<body hx-boost="true"> - <div class="app-container"> - <!-- Header --> - <header class="header"> - <div class="header-left"> - <div class="header-title"> - <i class="fab fa-discord"></i> - file storage - </div> - <div class="header-subtitle"># root</div> - </div> - <div class="header-actions"> - <button class="btn" - hx-get="http://localhost:7070/api/files" - hx-target="#file-content" - hx-indicator="#loading-spinner"> - <i class="fas fa-sync-alt"></i> - </button> - </div> - </header> - - <!-- Main Content --> - <main class="main-content"> - <!-- Search and Filters --> - <div class="search-bar"> - <input type="text" - class="search-input" - placeholder="search files..." - hx-get="http://localhost:7070/api/files" - hx-trigger="keyup changed delay:300ms" - hx-target="#file-content" - hx-indicator="#loading-spinner" - name="search"> - - <select class="select" - hx-get="http://localhost:7070/api/files" - hx-trigger="change" - hx-target="#file-content" - hx-indicator="#loading-spinner" - name="mimeType"> - <option value="">all types</option> - <option value="image/">images</option> - <option value="video/">videos</option> - <option value="audio/">audio</option> - <option value="application/pdf">pdfs</option> - <option value="text/">text</option> - <option value="application/zip">archives</option> - </select> - - <select class="select" - hx-get="http://localhost:7070/api/files" - hx-trigger="change" - hx-target="#file-content" - hx-indicator="#loading-spinner" - name="sortBy"> - <option value="created_at">newest</option> - <option value="file_name">name</option> - <option value="size">size</option> - </select> - </div> - - <!-- Stats --> - <div class="stats"> - <div class="stat-item"> - <span id="file-count" class="stat-number"> - <span class="htmx-indicator" id="loading-spinner"> - <i class="fas fa-spinner loading-spinner"></i> - </span> - <span id="count-value">loading</span> - </span> - files - </div> - <div class="stat-item"> - <i class="fas fa-server"></i> - localhost:7070 - </div> - <div class="stat-item" id="last-updated"> - <i class="fas fa-clock"></i> - <span id="timestamp">connecting...</span> - </div> - </div> - - <!-- File Container --> - <div class="file-container" - hx-get="http://localhost:7070/api/files" - hx-trigger="load" - hx-target="#file-content" - hx-indicator="#loading-spinner"> - <div id="file-content"> - <div class="empty-state"> - <div class="empty-state-icon"> - <i class="fas fa-spinner loading-spinner"></i> - </div> - <h3>loading files...</h3> - <p>fetching your files from discord storage</p> - </div> - </div> - </div> - </main> - </div> - - <!-- Scripts --> - <script> - // Update timestamp - function updateTimestamp() { - const now = new Date(); - const timeString = now.toLocaleTimeString(); - document.getElementById('timestamp').textContent = `updated ${timeString}`; - } - - // HTMX event listeners - document.addEventListener('htmx:afterSwap', function(evt) { - if (evt.detail.target.id === 'file-content') { - updateTimestamp(); - - // Update file count - const tables = evt.detail.target.querySelectorAll('table'); - if (tables.length > 0) { - const rows = tables[0].querySelectorAll('tbody tr'); - document.getElementById('count-value').textContent = rows.length; - } else { - document.getElementById('count-value').textContent = '0'; - } - } - }); - - // Error handling - document.addEventListener('htmx:responseError', function(evt) { - document.getElementById('file-content').innerHTML = ` - <div class="empty-state"> - <div class="empty-state-icon"> - <i class="fas fa-exclamation-triangle"></i> - </div> - <h3>connection failed</h3> - <p>unable to connect to the backend server</p> - <button class="btn btn-primary" - hx-get="http://localhost:7070/api/files" - hx-target="#file-content"> - <i class="fas fa-retry"></i> try again - </button> - </div> - `; - document.getElementById('count-value').textContent = 'error'; - document.getElementById('timestamp').textContent = 'connection failed'; - }); - - // Auto-refresh every 30 seconds - setInterval(function() { - if (document.visibilityState === 'visible') { - htmx.trigger('.file-container', 'refresh'); - } - }, 30000); - - // Keyboard shortcuts - document.addEventListener('keydown', function(e) { - // Ctrl+R or F5 to refresh - if ((e.ctrlKey && e.key === 'r') || e.key === 'F5') { - e.preventDefault(); - htmx.trigger('.file-container', 'refresh'); - } - }); - - // Global clear filters function - window.clearFilters = function() { - document.querySelector('input[name="search"]').value = ''; - document.querySelector('select[name="mimeType"]').value = ''; - document.querySelector('select[name="sortBy"]').value = 'created_at'; - htmx.trigger('.file-container', 'refresh'); - }; - - // Directory creation function - function createDirectory(event) { - event.preventDefault(); - const input = document.getElementById('new-directory-name'); - const message = document.getElementById('create-directory-message'); - const path = input.value.trim(); - - // Validation - if (!path) { - showMessage(message, 'Please enter a directory name', 'error'); - return; - } - - if (path.length < 1 || path.length > 100) { - showMessage(message, 'Directory name must be 1-100 characters', 'error'); - return; - } - - // Check for invalid characters - const invalidChars = /[<>:"/\\|?*\x00-\x1f]/; - if (invalidChars.test(path)) { - showMessage(message, 'Directory name contains invalid characters', 'error'); - return; - } - - if (path === '.' || path === '..') { - showMessage(message, 'Invalid directory name', 'error'); - return; - } - - // Show loading - input.disabled = true; - showMessage(message, 'Creating directory...', 'loading'); - - fetch('http://localhost:7070/api/directories', { - method: 'POST', - headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, - body: 'path=' + encodeURIComponent(path) - }) - .then(response => response.json()) - .then(data => { - input.disabled = false; - if (data.success) { - showMessage(message, 'Directory created!', 'success'); - input.value = ''; - // Refresh directory list - htmx.trigger('[hx-get*="/api/directories-html"]', 'click'); - } else { - showMessage(message, data.message || 'Failed to create directory', 'error'); - } - }) - .catch(error => { - input.disabled = false; - showMessage(message, 'Network error: ' + error.message, 'error'); - }); - } - - function showMessage(element, text, type) { - element.textContent = text; - element.className = 'form-message ' + type; - if (type === 'success') { - setTimeout(() => { - element.textContent = ''; - element.className = 'form-message'; - }, 3000); - } - } - - // Initialize - updateTimestamp(); - </script> -</body> -</html>
\ No newline at end of file |
