Spaces:
Paused
Paused
| <html lang="fr"> | |
| <head> | |
| <meta charset="utf-8"/> | |
| <meta content="width=device-width, initial-scale=1.0" name="viewport"/> | |
| <title>📁 Gestionnaire de Fichiers Pro</title> | |
| <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet"/> | |
| <style> | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| body { | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| min-height: 100vh; | |
| padding: 20px; | |
| } | |
| .container { | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| background: white; | |
| border-radius: 20px; | |
| box-shadow: 0 20px 40px rgba(0,0,0,0.1); | |
| overflow: hidden; | |
| } | |
| .header { | |
| background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); | |
| color: white; | |
| padding: 30px; | |
| text-align: center; | |
| position: relative; | |
| } | |
| .header h1 { | |
| font-size: 2.5em; | |
| margin-bottom: 10px; | |
| text-shadow: 0 2px 4px rgba(0,0,0,0.3); | |
| } | |
| .header p { | |
| font-size: 1.2em; | |
| opacity: 0.9; | |
| } | |
| .user-info { | |
| position: absolute; | |
| top: 20px; | |
| right: 20px; | |
| background: rgba(255,255,255,0.2); | |
| padding: 10px 15px; | |
| border-radius: 20px; | |
| color: white; | |
| font-size: 0.9em; | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| .admin-badge { | |
| background: #dc3545; | |
| color: white; | |
| font-size: 0.7em; | |
| padding: 2px 6px; | |
| border-radius: 10px; | |
| margin-left: 5px; | |
| } | |
| .logout-btn, .admin-btn { | |
| background: rgba(255,255,255,0.2); | |
| color: white; | |
| border: 1px solid rgba(255,255,255,0.3); | |
| padding: 5px 10px; | |
| border-radius: 15px; | |
| text-decoration: none; | |
| font-size: 0.8em; | |
| transition: all 0.3s ease; | |
| cursor: pointer; | |
| } | |
| .logout-btn:hover, .admin-btn:hover { | |
| background: rgba(255,255,255,0.3); | |
| } | |
| .stats { | |
| display: flex; | |
| justify-content: space-around; | |
| background: #f8f9fa; | |
| padding: 20px; | |
| border-bottom: 1px solid #e9ecef; | |
| } | |
| .stat-item { | |
| text-align: center; | |
| } | |
| .stat-number { | |
| font-size: 2em; | |
| font-weight: bold; | |
| color: #4facfe; | |
| } | |
| .stat-label { | |
| color: #6c757d; | |
| font-size: 0.9em; | |
| } | |
| .upload-section { | |
| padding: 40px; | |
| text-align: center; | |
| } | |
| .upload-area { | |
| border: 3px dashed #4facfe; | |
| border-radius: 15px; | |
| padding: 60px 20px; | |
| background: #f8f9ff; | |
| transition: all 0.3s ease; | |
| cursor: pointer; | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .upload-area:hover { | |
| border-color: #00f2fe; | |
| background: #f0f8ff; | |
| transform: translateY(-2px); | |
| } | |
| .upload-area.dragover { | |
| border-color: #00f2fe; | |
| background: #e6f3ff; | |
| transform: scale(1.02); | |
| } | |
| .upload-icon { | |
| font-size: 4em; | |
| color: #4facfe; | |
| margin-bottom: 20px; | |
| } | |
| .upload-text { | |
| font-size: 1.3em; | |
| color: #333; | |
| margin-bottom: 15px; | |
| } | |
| .upload-subtext { | |
| color: #6c757d; | |
| font-size: 1em; | |
| } | |
| #fileInput { | |
| display: none; | |
| } | |
| .btn { | |
| background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); | |
| color: white; | |
| border: none; | |
| padding: 15px 30px; | |
| border-radius: 50px; | |
| font-size: 1.1em; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| margin: 10px; | |
| box-shadow: 0 4px 15px rgba(79, 172, 254, 0.4); | |
| } | |
| .btn:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 6px 20px rgba(79, 172, 254, 0.6); | |
| } | |
| .btn:active { | |
| transform: translateY(0); | |
| } | |
| .progress-container { | |
| margin: 20px 0; | |
| display: none; | |
| } | |
| .progress-bar { | |
| width: 100%; | |
| height: 20px; | |
| background: #e9ecef; | |
| border-radius: 10px; | |
| overflow: hidden; | |
| box-shadow: inset 0 2px 4px rgba(0,0,0,0.1); | |
| } | |
| .progress-fill { | |
| height: 100%; | |
| background: linear-gradient(90deg, #4facfe, #00f2fe); | |
| width: 0%; | |
| transition: width 0.3s ease; | |
| border-radius: 10px; | |
| } | |
| .progress-text { | |
| text-align: center; | |
| margin-top: 10px; | |
| font-weight: bold; | |
| color: #333; | |
| } | |
| .files-section { | |
| padding: 40px; | |
| background: #f8f9fa; | |
| } | |
| .files-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 30px; | |
| } | |
| .files-title { | |
| font-size: 1.8em; | |
| color: #333; | |
| } | |
| .refresh-btn { | |
| background: #28a745; | |
| font-size: 0.9em; | |
| padding: 10px 20px; | |
| } | |
| .files-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); | |
| gap: 20px; | |
| } | |
| .file-card { | |
| background: white; | |
| border-radius: 15px; | |
| padding: 20px; | |
| box-shadow: 0 4px 15px rgba(0,0,0,0.1); | |
| transition: all 0.3s ease; | |
| border: 1px solid #e9ecef; | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .file-card:hover { | |
| transform: translateY(-5px); | |
| box-shadow: 0 8px 25px rgba(0,0,0,0.15); | |
| } | |
| .file-preview { | |
| width: 100%; | |
| height: 150px; | |
| background: #f8f9fa; | |
| border-radius: 10px; | |
| margin-bottom: 15px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| overflow: hidden; | |
| position: relative; | |
| cursor: pointer; | |
| } | |
| .file-preview img { | |
| max-width: 100%; | |
| max-height: 100%; | |
| object-fit: cover; | |
| border-radius: 8px; | |
| } | |
| .file-preview video { | |
| max-width: 100%; | |
| max-height: 100%; | |
| object-fit: cover; | |
| border-radius: 8px; | |
| } | |
| .file-preview-icon { | |
| font-size: 3em; | |
| color: #dee2e6; | |
| } | |
| .video-overlay { | |
| position: absolute; | |
| top: 50%; | |
| left: 50%; | |
| transform: translate(-50%, -50%); | |
| background: rgba(0,0,0,0.7); | |
| color: white; | |
| border-radius: 50%; | |
| width: 50px; | |
| height: 50px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 1.2em; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| } | |
| .video-overlay:hover { | |
| background: rgba(0,0,0,0.9); | |
| transform: translate(-50%, -50%) scale(1.1); | |
| } | |
| .preview-modal { | |
| display: none; | |
| position: fixed; | |
| z-index: 1000; | |
| left: 0; | |
| top: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: rgba(0,0,0,0.9); | |
| backdrop-filter: blur(5px); | |
| } | |
| .modal-content { | |
| position: absolute; | |
| top: 50%; | |
| left: 50%; | |
| transform: translate(-50%, -50%); | |
| max-width: 90vw; | |
| max-height: 90vh; | |
| background: white; | |
| border-radius: 15px; | |
| overflow: hidden; | |
| box-shadow: 0 20px 40px rgba(0,0,0,0.3); | |
| } | |
| .modal-header { | |
| background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); | |
| color: white; | |
| padding: 15px 20px; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| } | |
| .modal-title { | |
| font-size: 1.2em; | |
| font-weight: 600; | |
| } | |
| .modal-close { | |
| background: none; | |
| border: none; | |
| color: white; | |
| font-size: 1.5em; | |
| cursor: pointer; | |
| padding: 5px; | |
| border-radius: 5px; | |
| transition: background 0.3s ease; | |
| } | |
| .modal-close:hover { | |
| background: rgba(255,255,255,0.2); | |
| } | |
| .modal-body { | |
| padding: 0; | |
| text-align: center; | |
| } | |
| .modal-body img, | |
| .modal-body video { | |
| max-width: 100%; | |
| max-height: 70vh; | |
| object-fit: contain; | |
| } | |
| .modal-body video { | |
| width: 100%; | |
| } | |
| .file-info { | |
| display: flex; | |
| align-items: center; | |
| margin-bottom: 15px; | |
| } | |
| .file-details h3 { | |
| color: #333; | |
| font-size: 1.1em; | |
| margin-bottom: 5px; | |
| word-break: break-word; | |
| } | |
| .file-meta { | |
| color: #6c757d; | |
| font-size: 0.9em; | |
| } | |
| .file-actions { | |
| display: flex; | |
| gap: 10px; | |
| } | |
| .btn-small { | |
| padding: 8px 16px; | |
| font-size: 0.9em; | |
| border-radius: 20px; | |
| } | |
| .btn-download { | |
| background: linear-gradient(135deg, #28a745, #20c997); | |
| } | |
| .btn-delete { | |
| background: linear-gradient(135deg, #dc3545, #fd7e14); | |
| } | |
| .message { | |
| padding: 15px; | |
| border-radius: 10px; | |
| margin: 20px 0; | |
| font-weight: bold; | |
| text-align: center; | |
| } | |
| .message.success { | |
| background: #d4edda; | |
| color: #155724; | |
| border: 1px solid #c3e6cb; | |
| } | |
| .message.error { | |
| background: #f8d7da; | |
| color: #721c24; | |
| border: 1px solid #f5c6cb; | |
| } | |
| .empty-state { | |
| text-align: center; | |
| padding: 60px 20px; | |
| color: #6c757d; | |
| } | |
| .empty-icon { | |
| font-size: 4em; | |
| margin-bottom: 20px; | |
| opacity: 0.5; | |
| } | |
| .loading { | |
| display: none; | |
| text-align: center; | |
| padding: 40px; | |
| } | |
| .spinner { | |
| border: 4px solid #f3f3f3; | |
| border-top: 4px solid #4facfe; | |
| border-radius: 50%; | |
| width: 50px; | |
| height: 50px; | |
| animation: spin 1s linear infinite; | |
| margin: 0 auto 20px; | |
| } | |
| @keyframes spin { | |
| 0% { transform: rotate(0deg); } | |
| 100% { transform: rotate(360deg); } | |
| } | |
| /* Admin Panel */ | |
| .admin-panel { | |
| background: #f8f9fa; | |
| border: 1px solid #dee2e6; | |
| border-radius: 15px; | |
| padding: 30px; | |
| margin: 20px 40px; | |
| display: none; | |
| box-shadow: 0 4px 15px rgba(0,0,0,0.1); | |
| } | |
| .admin-panel h3 { | |
| color: #333; | |
| margin-bottom: 25px; | |
| font-size: 1.5em; | |
| text-align: center; | |
| } | |
| .admin-tabs { | |
| display: flex; | |
| gap: 10px; | |
| margin-bottom: 25px; | |
| justify-content: center; | |
| } | |
| .admin-tab { | |
| background: #e9ecef; | |
| color: #495057; | |
| border: none; | |
| padding: 10px 20px; | |
| border-radius: 25px; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| font-weight: 500; | |
| } | |
| .admin-tab.active { | |
| background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); | |
| color: white; | |
| } | |
| .admin-content { | |
| background: white; | |
| border-radius: 10px; | |
| padding: 25px; | |
| box-shadow: 0 2px 10px rgba(0,0,0,0.05); | |
| } | |
| .add-user-section { | |
| display: none; | |
| } | |
| .add-user-section.active { | |
| display: block; | |
| } | |
| .form-grid { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr 1fr auto; | |
| gap: 15px; | |
| align-items: end; | |
| margin-bottom: 20px; | |
| } | |
| .form-group-admin { | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| .form-label-admin { | |
| font-weight: 600; | |
| color: #333; | |
| margin-bottom: 5px; | |
| font-size: 0.9em; | |
| } | |
| .form-input-admin { | |
| padding: 12px 15px; | |
| border: 2px solid #e9ecef; | |
| border-radius: 8px; | |
| font-size: 14px; | |
| transition: border-color 0.3s ease; | |
| outline: none; | |
| } | |
| .form-input-admin:focus { | |
| border-color: #4facfe; | |
| box-shadow: 0 0 0 3px rgba(79, 172, 254, 0.1); | |
| } | |
| .btn-add-user { | |
| background: linear-gradient(135deg, #28a745, #20c997); | |
| color: white; | |
| border: none; | |
| padding: 12px 20px; | |
| border-radius: 8px; | |
| cursor: pointer; | |
| font-weight: 600; | |
| transition: all 0.3s ease; | |
| white-space: nowrap; | |
| } | |
| .btn-add-user:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 4px 15px rgba(40, 167, 69, 0.3); | |
| } | |
| .users-list-section { | |
| display: block; | |
| } | |
| .users-list-section.active { | |
| display: block; | |
| } | |
| .users-grid { | |
| display: grid; | |
| gap: 15px; | |
| } | |
| .user-card { | |
| background: #f8f9fa; | |
| border: 1px solid #e9ecef; | |
| border-radius: 10px; | |
| padding: 15px; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| transition: all 0.3s ease; | |
| } | |
| .user-card:hover { | |
| background: #e9ecef; | |
| transform: translateY(-2px); | |
| } | |
| .user-info { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| .user-avatar { | |
| width: 40px; | |
| height: 40px; | |
| background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); | |
| border-radius: 50%; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| color: white; | |
| font-weight: bold; | |
| } | |
| .user-details h4 { | |
| margin: 0; | |
| color: #333; | |
| font-size: 1.1em; | |
| } | |
| .user-role { | |
| font-size: 0.8em; | |
| color: #6c757d; | |
| margin-top: 2px; | |
| } | |
| .btn-delete-user { | |
| background: linear-gradient(135deg, #dc3545, #fd7e14); | |
| color: white; | |
| border: none; | |
| padding: 8px 15px; | |
| border-radius: 6px; | |
| cursor: pointer; | |
| font-size: 0.9em; | |
| transition: all 0.3s ease; | |
| } | |
| .btn-delete-user:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 4px 15px rgba(220, 53, 69, 0.3); | |
| } | |
| .btn-delete-user:disabled { | |
| opacity: 0.5; | |
| cursor: not-allowed; | |
| transform: none; | |
| } | |
| /* Responsive Design */ | |
| @media (max-width: 768px) { | |
| body { | |
| padding: 10px; | |
| } | |
| .header h1 { | |
| font-size: 2em; | |
| } | |
| .header p { | |
| font-size: 1em; | |
| } | |
| .user-info { | |
| position: static; | |
| margin-bottom: 20px; | |
| justify-content: center; | |
| } | |
| .upload-section, .files-section { | |
| padding: 20px; | |
| } | |
| .upload-area { | |
| padding: 40px 15px; | |
| } | |
| .upload-icon { | |
| font-size: 3em; | |
| } | |
| .upload-text { | |
| font-size: 1.1em; | |
| } | |
| .stats { | |
| flex-direction: column; | |
| gap: 15px; | |
| } | |
| .files-header { | |
| flex-direction: column; | |
| gap: 15px; | |
| text-align: center; | |
| } | |
| .files-grid { | |
| grid-template-columns: 1fr; | |
| } | |
| .file-actions { | |
| flex-direction: column; | |
| } | |
| .admin-panel { | |
| margin: 20px; | |
| padding: 20px; | |
| } | |
| .admin-tabs { | |
| flex-direction: column; | |
| gap: 5px; | |
| } | |
| .admin-tab { | |
| padding: 8px 15px; | |
| font-size: 0.9em; | |
| } | |
| .form-grid { | |
| grid-template-columns: 1fr; | |
| gap: 10px; | |
| } | |
| .form-group-admin { | |
| margin-bottom: 15px; | |
| } | |
| .btn-add-user { | |
| width: 100%; | |
| margin-top: 10px; | |
| } | |
| .user-card { | |
| flex-direction: column; | |
| gap: 15px; | |
| text-align: center; | |
| } | |
| .user-info { | |
| justify-content: center; | |
| } | |
| } | |
| @media (max-width: 480px) { | |
| .header { | |
| padding: 20px; | |
| } | |
| .header h1 { | |
| font-size: 1.8em; | |
| } | |
| .upload-area { | |
| padding: 30px 10px; | |
| } | |
| .btn { | |
| padding: 12px 24px; | |
| font-size: 1em; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <!-- Header --> | |
| <div class="header"> | |
| <div class="user-info"> | |
| <i class="fas fa-user"></i> {{ username }} | |
| {% if is_admin %} | |
| <span class="admin-badge">ADMIN</span> | |
| <button class="admin-btn" onclick="toggleAdminPanel()"> | |
| <i class="fas fa-cog"></i> Admin | |
| </button> | |
| {% endif %} | |
| <a class="logout-btn" href="/logout"> | |
| <i class="fas fa-sign-out-alt"></i> Déconnexion | |
| </a> | |
| </div> | |
| <h1>📁 Gestionnaire de Fichiers Pro</h1> | |
| <p>Upload, téléchargez et gérez vos fichiers facilement</p> | |
| </div> | |
| <!-- Admin Panel --> | |
| {% if is_admin %} | |
| <div class="admin-panel" id="adminPanel"> | |
| <h3><i class="fas fa-users-cog"></i> Panel d'Administration</h3> | |
| <div class="admin-tabs"> | |
| <button class="admin-tab active" onclick="switchAdminTab('add-user')"> | |
| <i class="fas fa-user-plus"></i> Ajouter Utilisateur | |
| </button> | |
| <button class="admin-tab" onclick="switchAdminTab('manage-users')"> | |
| <i class="fas fa-users"></i> Gérer Utilisateurs | |
| </button> | |
| </div> | |
| <div class="admin-content"> | |
| <!-- Ajouter un utilisateur --> | |
| <div class="add-user-section active" id="add-user-section"> | |
| <h4 style="margin-bottom: 20px; color: #333;"> | |
| <i class="fas fa-user-plus"></i> Créer un nouvel utilisateur | |
| </h4> | |
| <div class="form-grid"> | |
| <div class="form-group-admin"> | |
| <label class="form-label-admin">Nom d'utilisateur</label> | |
| <input class="form-input-admin" id="newUsername" placeholder="Entrez le nom d'utilisateur" type="text"/> | |
| </div> | |
| <div class="form-group-admin"> | |
| <label class="form-label-admin">Mot de passe</label> | |
| <input class="form-input-admin" id="newPassword" placeholder="Entrez le mot de passe" type="password"/> | |
| </div> | |
| <div class="form-group-admin"> | |
| <label class="form-label-admin">Rôle</label> | |
| <select class="form-input-admin" id="newRole"> | |
| <option value="user">Utilisateur</option> | |
| <option value="admin">Administrateur</option> | |
| </select> | |
| </div> | |
| <button class="btn-add-user" onclick="addUser()"> | |
| <i class="fas fa-plus"></i> Créer | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Gérer les utilisateurs --> | |
| <div class="users-list-section" id="manage-users-section" style="display: none;"> | |
| <h4 style="margin-bottom: 20px; color: #333;"> | |
| <i class="fas fa-users"></i> Utilisateurs existants | |
| </h4> | |
| <div class="users-grid" id="usersList"> | |
| <!-- Liste des utilisateurs chargée dynamiquement --> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| {% endif %} | |
| <!-- Stats --> | |
| <div class="stats"> | |
| <div class="stat-item"> | |
| <div class="stat-number" id="totalFiles">0</div> | |
| <div class="stat-label">Fichiers</div> | |
| </div> | |
| <div class="stat-item"> | |
| <div class="stat-number" id="totalSize">0 B</div> | |
| <div class="stat-label">Taille totale</div> | |
| </div> | |
| <div class="stat-item"> | |
| <div class="stat-number">8 GB</div> | |
| <div class="stat-label">Limite par fichier</div> | |
| </div> | |
| </div> | |
| <!-- Upload Section --> | |
| <div class="upload-section"> | |
| <div class="upload-area" id="uploadArea"> | |
| <div class="upload-icon">📤</div> | |
| <div class="upload-text">Glissez-déposez vos fichiers ici</div> | |
| <div class="upload-subtext">ou cliquez pour sélectionner</div> | |
| <input id="fileInput" multiple="" type="file"/> | |
| </div> | |
| <div class="progress-container" id="progressContainer"> | |
| <div class="progress-bar"> | |
| <div class="progress-fill" id="progressFill"></div> | |
| </div> | |
| <div class="progress-text" id="progressText">Upload en cours...</div> | |
| </div> | |
| <button class="btn" onclick="document.getElementById('fileInput').click()"> | |
| 📁 Sélectionner des fichiers | |
| </button> | |
| </div> | |
| <!-- Messages --> | |
| <div id="messageContainer"></div> | |
| <!-- Files Section --> | |
| <div class="files-section"> | |
| <div class="files-header"> | |
| <h2 class="files-title">📂 Mes Fichiers</h2> | |
| <button class="btn refresh-btn" onclick="loadFiles()"> | |
| 🔄 Actualiser | |
| </button> | |
| </div> | |
| <div class="loading" id="loading"> | |
| <div class="spinner"></div> | |
| <p>Chargement des fichiers...</p> | |
| </div> | |
| <div class="files-grid" id="filesGrid"></div> | |
| </div> | |
| </div> | |
| <!-- Modal de prévisualisation --> | |
| <div class="preview-modal" id="previewModal"> | |
| <div class="modal-content"> | |
| <div class="modal-header"> | |
| <div class="modal-title" id="modalTitle">Aperçu du fichier</div> | |
| <button class="modal-close" onclick="closePreview()"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| </div> | |
| <div class="modal-body" id="modalBody"> | |
| <!-- Contenu dynamique --> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // Variables globales | |
| let isUploading = false; | |
| const isAdmin = {{ 'true' if is_admin else 'false' }}; | |
| // Initialisation | |
| document.addEventListener('DOMContentLoaded', function() { | |
| loadFiles(); | |
| setupEventListeners(); | |
| if (isAdmin) { | |
| loadUsers(); | |
| } | |
| }); | |
| function setupEventListeners() { | |
| const uploadArea = document.getElementById('uploadArea'); | |
| const fileInput = document.getElementById('fileInput'); | |
| // Drag & Drop | |
| uploadArea.addEventListener('dragover', function(e) { | |
| e.preventDefault(); | |
| uploadArea.classList.add('dragover'); | |
| }); | |
| uploadArea.addEventListener('dragleave', function(e) { | |
| e.preventDefault(); | |
| uploadArea.classList.remove('dragover'); | |
| }); | |
| uploadArea.addEventListener('drop', function(e) { | |
| e.preventDefault(); | |
| uploadArea.classList.remove('dragover'); | |
| const files = e.dataTransfer.files; | |
| if (files.length > 0) { | |
| handleFiles(files); | |
| } | |
| }); | |
| // Click to upload | |
| uploadArea.addEventListener('click', function() { | |
| if (!isUploading) { | |
| fileInput.click(); | |
| } | |
| }); | |
| // File input change | |
| fileInput.addEventListener('change', function(e) { | |
| if (e.target.files.length > 0) { | |
| handleFiles(e.target.files); | |
| } | |
| }); | |
| } | |
| function handleFiles(files) { | |
| if (isUploading) { | |
| showMessage('Un upload est déjà en cours...', 'error'); | |
| return; | |
| } | |
| if (files.length === 0) { | |
| showMessage('Aucun fichier sélectionné', 'error'); | |
| return; | |
| } | |
| uploadFilesSequentially(Array.from(files), 0); | |
| } | |
| function uploadFilesSequentially(files, index) { | |
| if (index >= files.length) { | |
| hideProgress(); | |
| loadFiles(); | |
| return; | |
| } | |
| const file = files[index]; | |
| const totalFiles = files.length; | |
| showProgress(); | |
| updateProgress(0, `Upload ${index + 1}/${totalFiles}: ${file.name}`); | |
| uploadSingleFile(file, function(success) { | |
| if (success) { | |
| updateProgress(100, `✅ ${file.name} uploadé avec succès`); | |
| } else { | |
| updateProgress(100, `❌ Erreur lors de l'upload de ${file.name}`); | |
| } | |
| setTimeout(() => { | |
| uploadFilesSequentially(files, index + 1); | |
| }, 1000); | |
| }); | |
| } | |
| function uploadSingleFile(file, callback) { | |
| const formData = new FormData(); | |
| formData.append('file', file); | |
| const xhr = new XMLHttpRequest(); | |
| xhr.upload.addEventListener('progress', function(e) { | |
| if (e.lengthComputable) { | |
| const percentComplete = (e.loaded / e.total) * 100; | |
| updateProgress(percentComplete, `Upload en cours: ${file.name}`); | |
| } | |
| }); | |
| xhr.addEventListener('load', function() { | |
| isUploading = false; | |
| try { | |
| const response = JSON.parse(xhr.responseText); | |
| if (xhr.status === 200 && response.success) { | |
| showMessage(response.message, 'success'); | |
| callback(true); | |
| } else { | |
| showMessage(response.error || 'Erreur lors de l\'upload', 'error'); | |
| callback(false); | |
| } | |
| } catch (e) { | |
| showMessage('Erreur lors de l\'upload', 'error'); | |
| callback(false); | |
| } | |
| }); | |
| xhr.addEventListener('error', function() { | |
| isUploading = false; | |
| showMessage('Erreur réseau lors de l\'upload', 'error'); | |
| callback(false); | |
| }); | |
| isUploading = true; | |
| xhr.open('POST', '/upload'); | |
| xhr.send(formData); | |
| } | |
| function loadFiles() { | |
| const loading = document.getElementById('loading'); | |
| const filesGrid = document.getElementById('filesGrid'); | |
| loading.style.display = 'block'; | |
| filesGrid.innerHTML = ''; | |
| fetch('/api/files') | |
| .then(response => response.json()) | |
| .then(data => { | |
| loading.style.display = 'none'; | |
| displayFiles(data.files); | |
| updateStats(data.total_files, data.total_size); | |
| }) | |
| .catch(error => { | |
| loading.style.display = 'none'; | |
| showMessage('Erreur lors du chargement des fichiers', 'error'); | |
| console.error('Error:', error); | |
| }); | |
| } | |
| function displayFiles(files) { | |
| const filesGrid = document.getElementById('filesGrid'); | |
| if (files.length === 0) { | |
| filesGrid.innerHTML = ` | |
| <div class="empty-state"> | |
| <div class="empty-icon">📭</div> | |
| <h3>Aucun fichier</h3> | |
| <p>Uploadez vos premiers fichiers pour commencer</p> | |
| </div> | |
| `; | |
| return; | |
| } | |
| filesGrid.innerHTML = files.map(file => { | |
| let previewHtml = ''; | |
| if (file.is_image && file.thumbnail) { | |
| previewHtml = ` | |
| <div class="file-preview" onclick="openPreview('${file.name}', 'image')"> | |
| <img src="/thumbnail/${file.thumbnail}" alt="${file.name}" loading="lazy"> | |
| </div> | |
| `; | |
| } else if (file.is_video) { | |
| previewHtml = ` | |
| <div class="file-preview" onclick="openPreview('${file.name}', 'video')"> | |
| <video preload="metadata"> | |
| <source src="/preview/${encodeURIComponent(file.name)}" type="video/mp4"> | |
| </video> | |
| <div class="video-overlay"> | |
| <i class="fas fa-play"></i> | |
| </div> | |
| </div> | |
| `; | |
| } else { | |
| previewHtml = ` | |
| <div class="file-preview"> | |
| <div class="file-preview-icon">${getFileIcon(file.name)}</div> | |
| </div> | |
| `; | |
| } | |
| return ` | |
| <div class="file-card"> | |
| ${previewHtml} | |
| <div class="file-info"> | |
| <div class="file-details"> | |
| <h3>${file.name}</h3> | |
| <div class="file-meta"> | |
| ${file.size} • ${file.date} | |
| </div> | |
| </div> | |
| </div> | |
| <div class="file-actions"> | |
| <button class="btn btn-small btn-download" onclick="downloadFile('${file.name}')"> | |
| <i class="fas fa-download"></i> Télécharger | |
| </button> | |
| <button class="btn btn-small btn-delete" onclick="deleteFile('${file.name}')"> | |
| <i class="fas fa-trash"></i> Supprimer | |
| </button> | |
| </div> | |
| </div> | |
| `; | |
| }).join(''); | |
| } | |
| function getFileIcon(filename) { | |
| const ext = filename.split('.').pop().toLowerCase(); | |
| const icons = { | |
| 'pdf': '📄', | |
| 'doc': '📝', 'docx': '📝', | |
| 'xls': '📊', 'xlsx': '📊', | |
| 'ppt': '📽️', 'pptx': '📽️', | |
| 'txt': '📃', | |
| 'jpg': '🖼️', 'jpeg': '🖼️', 'png': '🖼️', 'gif': '🖼️', | |
| 'mp3': '🎵', 'wav': '🎵', | |
| 'mp4': '🎬', 'avi': '🎬', 'mov': '🎬', | |
| 'zip': '📦', 'rar': '📦', '7z': '📦', | |
| 'py': '🐍', 'js': '💛', 'html': '🌐', 'css': '🎨' | |
| }; | |
| return icons[ext] || '📄'; | |
| } | |
| function downloadFile(filename) { | |
| window.open(`/download/${encodeURIComponent(filename)}`, '_blank'); | |
| } | |
| function deleteFile(filename) { | |
| if (!confirm(`Êtes-vous sûr de vouloir supprimer "${filename}" ?`)) { | |
| return; | |
| } | |
| fetch(`/delete/${encodeURIComponent(filename)}`, { | |
| method: 'DELETE' | |
| }) | |
| .then(response => response.json()) | |
| .then(data => { | |
| if (data.success) { | |
| showMessage(data.message, 'success'); | |
| loadFiles(); | |
| } else { | |
| showMessage(data.error, 'error'); | |
| } | |
| }) | |
| .catch(error => { | |
| showMessage('Erreur lors de la suppression', 'error'); | |
| console.error('Error:', error); | |
| }); | |
| } | |
| function showProgress() { | |
| document.getElementById('progressContainer').style.display = 'block'; | |
| } | |
| function hideProgress() { | |
| document.getElementById('progressContainer').style.display = 'none'; | |
| document.getElementById('progressFill').style.width = '0%'; | |
| } | |
| function updateProgress(percent, text) { | |
| document.getElementById('progressFill').style.width = percent + '%'; | |
| document.getElementById('progressText').textContent = text; | |
| } | |
| function updateStats(totalFiles, totalSize) { | |
| document.getElementById('totalFiles').textContent = totalFiles; | |
| document.getElementById('totalSize').textContent = totalSize; | |
| } | |
| function showMessage(message, type) { | |
| const container = document.getElementById('messageContainer'); | |
| const messageDiv = document.createElement('div'); | |
| messageDiv.className = `message ${type}`; | |
| messageDiv.textContent = message; | |
| container.appendChild(messageDiv); | |
| setTimeout(() => { | |
| messageDiv.remove(); | |
| }, 5000); | |
| } | |
| // Fonctions de prévisualisation | |
| function openPreview(filename, type) { | |
| const modal = document.getElementById('previewModal'); | |
| const modalTitle = document.getElementById('modalTitle'); | |
| const modalBody = document.getElementById('modalBody'); | |
| modalTitle.textContent = filename; | |
| if (type === 'image') { | |
| modalBody.innerHTML = `<img src="/preview/${encodeURIComponent(filename)}" alt="${filename}">`; | |
| } else if (type === 'video') { | |
| modalBody.innerHTML = ` | |
| <video controls autoplay> | |
| <source src="/preview/${encodeURIComponent(filename)}" type="video/mp4"> | |
| Votre navigateur ne supporte pas la lecture vidéo. | |
| </video> | |
| `; | |
| } | |
| modal.style.display = 'block'; | |
| document.body.style.overflow = 'hidden'; | |
| } | |
| function closePreview() { | |
| const modal = document.getElementById('previewModal'); | |
| const modalBody = document.getElementById('modalBody'); | |
| modal.style.display = 'none'; | |
| document.body.style.overflow = 'auto'; | |
| modalBody.innerHTML = ''; | |
| } | |
| // Fermer la modal en cliquant à l'extérieur | |
| document.getElementById('previewModal').addEventListener('click', function(e) { | |
| if (e.target === this) { | |
| closePreview(); | |
| } | |
| }); | |
| // Fermer la modal avec la touche Escape | |
| document.addEventListener('keydown', function(e) { | |
| if (e.key === 'Escape') { | |
| closePreview(); | |
| } | |
| }); | |
| // Fonctions d'administration | |
| function toggleAdminPanel() { | |
| const panel = document.getElementById('adminPanel'); | |
| if (panel.style.display === 'none' || panel.style.display === '') { | |
| panel.style.display = 'block'; | |
| loadUsers(); | |
| } else { | |
| panel.style.display = 'none'; | |
| } | |
| } | |
| function switchAdminTab(tab) { | |
| // Gérer les onglets | |
| document.querySelectorAll('.admin-tab').forEach(t => t.classList.remove('active')); | |
| document.querySelector(`[onclick="switchAdminTab('${tab}')"]`).classList.add('active'); | |
| // Gérer les sections | |
| document.getElementById('add-user-section').style.display = tab === 'add-user' ? 'block' : 'none'; | |
| document.getElementById('manage-users-section').style.display = tab === 'manage-users' ? 'block' : 'none'; | |
| // Charger les utilisateurs si on va sur l'onglet de gestion | |
| if (tab === 'manage-users') { | |
| loadUsers(); | |
| } | |
| } | |
| function loadUsers() { | |
| if (!isAdmin) return; | |
| fetch('/admin/users') | |
| .then(response => response.json()) | |
| .then(data => { | |
| const usersList = document.getElementById('usersList'); | |
| usersList.innerHTML = data.users.map(user => ` | |
| <div class="user-card"> | |
| <div class="user-info"> | |
| <div class="user-avatar"> | |
| ${user.username.charAt(0).toUpperCase()} | |
| </div> | |
| <div class="user-details"> | |
| <h4>${user.username}</h4> | |
| <div class="user-role"> | |
| ${user.role === 'admin' ? '👑 Administrateur' : '👤 Utilisateur'} | |
| </div> | |
| </div> | |
| </div> | |
| ${user.username !== 'admin' ? | |
| `<button class="btn-delete-user" onclick="deleteUser('${user.username}')"> | |
| <i class="fas fa-trash"></i> Supprimer | |
| </button>` : | |
| `<button class="btn-delete-user" disabled> | |
| <i class="fas fa-shield-alt"></i> Protégé | |
| </button>` | |
| } | |
| </div> | |
| `).join(''); | |
| }) | |
| .catch(error => { | |
| console.error('Erreur lors du chargement des utilisateurs:', error); | |
| showMessage('Erreur lors du chargement des utilisateurs', 'error'); | |
| }); | |
| } | |
| function addUser() { | |
| const username = document.getElementById('newUsername').value.trim(); | |
| const password = document.getElementById('newPassword').value.trim(); | |
| const role = document.getElementById('newRole').value; | |
| if (!username || !password) { | |
| showMessage('Nom d\'utilisateur et mot de passe requis', 'error'); | |
| return; | |
| } | |
| fetch('/admin/users', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json' | |
| }, | |
| body: JSON.stringify({ | |
| username: username, | |
| password: password, | |
| role: role | |
| }) | |
| }) | |
| .then(response => response.json()) | |
| .then(data => { | |
| if (data.success) { | |
| showMessage(data.message, 'success'); | |
| document.getElementById('newUsername').value = ''; | |
| document.getElementById('newPassword').value = ''; | |
| document.getElementById('newRole').value = 'user'; | |
| loadUsers(); | |
| } else { | |
| showMessage(data.error, 'error'); | |
| } | |
| }) | |
| .catch(error => { | |
| showMessage('Erreur lors de l\'ajout de l\'utilisateur', 'error'); | |
| console.error('Error:', error); | |
| }); | |
| } | |
| function deleteUser(username) { | |
| if (!confirm(`Êtes-vous sûr de vouloir supprimer l'utilisateur "${username}" et tous ses fichiers ?`)) { | |
| return; | |
| } | |
| fetch(`/admin/users/${encodeURIComponent(username)}`, { | |
| method: 'DELETE' | |
| }) | |
| .then(response => response.json()) | |
| .then(data => { | |
| if (data.success) { | |
| showMessage(data.message, 'success'); | |
| loadUsers(); | |
| } else { | |
| showMessage(data.error, 'error'); | |
| } | |
| }) | |
| .catch(error => { | |
| showMessage('Erreur lors de la suppression de l\'utilisateur', 'error'); | |
| console.error('Error:', error); | |
| }); | |
| } | |
| // Reset file input après upload | |
| function resetFileInput() { | |
| document.getElementById('fileInput').value = ''; | |
| } | |
| </script> | |
| </body> | |
| </html> |