aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/resources/templates/index.html
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/resources/templates/index.html')
-rw-r--r--src/main/resources/templates/index.html573
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
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage