diff --git a/assets/css/file-tree.css b/assets/css/file-tree.css index 5a272ab..45e2bbf 100644 --- a/assets/css/file-tree.css +++ b/assets/css/file-tree.css @@ -6,22 +6,18 @@ /* ===== Tree Panel ===== */ .tree-panel { background-color: var(--color-bg); - border: 1px solid var(--color-border); - border-radius: var(--radius-lg); - box-shadow: var(--shadow-sm); display: flex; flex-direction: column; overflow: hidden; - min-height: 400px; + min-height: 0; } .tree-header { padding: var(--spacing-md) var(--spacing-lg); - border-bottom: 1px solid var(--color-border); - background-color: var(--color-bg-secondary); display: flex; gap: var(--spacing-md); align-items: center; + flex-shrink: 0; } .search-input-wrapper { @@ -35,18 +31,18 @@ flex: 1; width: 100%; padding: var(--spacing-sm) 2.5rem var(--spacing-sm) var(--spacing-md); - border: 1px solid var(--color-border); - border-radius: var(--radius-md); + border: none; + border-bottom: 1px solid var(--color-border); + border-radius: 0; font-size: var(--font-size-sm); - background-color: var(--color-bg); + background-color: transparent; color: var(--color-text); transition: all var(--transition-fast); } .search-input:focus { outline: none; - border-color: var(--color-primary); - box-shadow: 0 0 0 3px var(--color-primary-light); + border-bottom-color: var(--color-primary); } .search-input::placeholder { diff --git a/assets/css/main.css b/assets/css/main.css index c336c58..a87f246 100644 --- a/assets/css/main.css +++ b/assets/css/main.css @@ -200,14 +200,6 @@ body { gap: var(--spacing-lg); } -/* ===== Upload Section ===== */ -.upload-section { - display: grid; - grid-template-columns: 1fr 1fr; - gap: var(--spacing-lg); - flex-shrink: 0; -} - /* ===== Conflicts Banner ===== */ .conflicts-banner { display: flex; @@ -231,15 +223,6 @@ body { font-size: var(--font-size-sm); } -/* ===== Trees Section ===== */ -.trees-section { - display: grid; - grid-template-columns: 1fr 1fr; - gap: var(--spacing-lg); - flex: 1; - min-height: 0; /* Important pour scroll */ -} - /* ===== Footer ===== */ .footer { background-color: var(--color-bg); diff --git a/assets/css/upload-panel.css b/assets/css/upload-panel.css index 3f023f3..8e3333d 100644 --- a/assets/css/upload-panel.css +++ b/assets/css/upload-panel.css @@ -1,33 +1,101 @@ /** - * FuZip - Styles zones d'upload - * Drop zones, boutons browse, progress bars + * FuZip - Styles colonnes et upload + * Colonnes unifiées (upload + tree), drop zones, progress bars */ -/* ===== Panel d'upload ===== */ -.upload-panel { +/* ===== Colonnes Section ===== */ +.columns-section { + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--spacing-lg); + flex: 1; + min-height: 0; +} + +/* ===== Colonne ===== */ +.column { + display: flex; + flex-direction: column; background-color: var(--color-bg); border: 1px solid var(--color-border); border-radius: var(--radius-lg); - padding: var(--spacing-lg); - display: flex; - flex-direction: column; - gap: var(--spacing-md); box-shadow: var(--shadow-sm); + min-height: 0; + overflow: hidden; transition: all var(--transition-base); } -.panel-title { +.column.drag-over { + border-color: var(--color-primary); + background-color: var(--color-primary-light); + box-shadow: 0 0 0 3px var(--color-primary-light); +} + +/* ===== Header de colonne ===== */ +.column-header { + padding: var(--spacing-md) var(--spacing-lg); + border-bottom: 1px solid var(--color-border); + background-color: var(--color-bg-secondary); + display: flex; + align-items: center; + gap: var(--spacing-md); + flex-wrap: wrap; + flex-shrink: 0; +} + +.column-title { font-size: var(--font-size-lg); font-weight: 600; color: var(--color-text); margin: 0; + flex-shrink: 0; +} + +/* Info de colonne (fichier chargé) */ +.column-info { + display: flex; + align-items: center; + gap: var(--spacing-md); + flex: 1; + font-size: var(--font-size-sm); + color: var(--color-text-secondary); +} + +.info-file-name { + font-weight: 600; + color: var(--color-text); + max-width: 200px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.info-separator { + color: var(--color-text-muted); +} + +.info-stat { + font-weight: 500; + color: var(--color-text); +} + +/* ===== Body de colonne ===== */ +.column-body { + flex: 1; + display: flex; + flex-direction: column; + position: relative; + min-height: 0; + overflow: hidden; } /* ===== Drop Zone ===== */ .drop-zone { + flex: 1; border: 2px dashed var(--color-border); border-radius: var(--radius-md); padding: var(--spacing-2xl) var(--spacing-lg); + margin: var(--spacing-lg); text-align: center; background-color: var(--color-bg-secondary); transition: all var(--transition-base); @@ -35,7 +103,9 @@ display: flex; flex-direction: column; align-items: center; + justify-content: center; gap: var(--spacing-md); + min-height: 250px; } .drop-zone:hover { @@ -95,54 +165,19 @@ display: none; } -/* ===== Upload Info ===== */ -.upload-info { - display: flex; - flex-direction: column; - gap: var(--spacing-md); - padding: var(--spacing-md); - background-color: var(--color-bg-secondary); - border-radius: var(--radius-md); - border: 1px solid var(--color-border); -} - -.file-name { - font-weight: 600; - color: var(--color-text); - font-size: var(--font-size-base); - word-break: break-all; -} - -.file-stats { - display: flex; - gap: var(--spacing-lg); - flex-wrap: wrap; -} - -.stat-item { - display: flex; - align-items: center; - gap: var(--spacing-xs); - font-size: var(--font-size-sm); - color: var(--color-text-secondary); -} - -.stat-icon { - width: 1rem; - height: 1rem; - color: var(--color-text-muted); -} - -.stat-value { - font-weight: 600; - color: var(--color-text); -} - /* ===== Progress Bar ===== */ .upload-progress { display: flex; align-items: center; gap: var(--spacing-md); + padding: var(--spacing-md); + background-color: var(--color-bg-secondary); + border-radius: var(--radius-md); + margin: 0 var(--spacing-lg) var(--spacing-lg); + position: absolute; + bottom: 0; + left: 0; + right: 0; } .progress-bar { @@ -192,64 +227,85 @@ text-align: right; } +/* ===== Bouton changer ===== */ +.btn-change-file { + padding: var(--spacing-xs); + background-color: transparent; + color: var(--color-text-secondary); + border: none; + border-radius: 50%; + cursor: pointer; + transition: all var(--transition-fast); + display: inline-flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + width: 2rem; + height: 2rem; + margin-left: auto; +} + +.btn-change-file:hover { + background-color: var(--color-bg-secondary); + color: var(--color-primary); +} + +.btn-change-file svg { + width: 1.125rem; + height: 1.125rem; +} + +/* ===== État compact (fichier chargé) ===== */ +.column-header.compact .column-title { + display: none; +} + +.column-header.compact .column-info { + display: flex; +} + +/* Quand pas compact, cache les infos */ +.column-header:not(.compact) .column-info { + display: none; +} + +/* Cache la drop zone quand compact */ +.column-header.compact ~ .column-body .drop-zone { + display: none; +} + +/* Affiche le tree-panel quand compact */ +.column-header.compact ~ .column-body .tree-panel { + display: flex; + flex-direction: column; + flex: 1; + min-height: 0; +} + /* ===== États spéciaux ===== */ -.upload-panel.uploading { +.column-header.uploading { pointer-events: none; opacity: 0.7; } -.upload-panel.success { - border-color: var(--color-success); - background-color: rgba(16, 185, 129, 0.05); -} - -.upload-panel.error { +.column-header.error { border-color: var(--color-error); - background-color: rgba(239, 68, 68, 0.05); } -/* Message d'erreur */ -.error-message { - padding: var(--spacing-sm) var(--spacing-md); - background-color: #fee2e2; - border: 1px solid var(--color-error); - border-radius: var(--radius-md); - color: #991b1b; - font-size: var(--font-size-sm); - display: flex; - align-items: center; - gap: var(--spacing-sm); -} - -.error-icon { - width: 1.25rem; - height: 1.25rem; - flex-shrink: 0; -} - -/* Message de succès */ -.success-message { - padding: var(--spacing-sm) var(--spacing-md); - background-color: #d1fae5; - border: 1px solid var(--color-success); - border-radius: var(--radius-md); - color: #065f46; - font-size: var(--font-size-sm); - display: flex; - align-items: center; - gap: var(--spacing-sm); -} - -.success-icon { - width: 1.25rem; - height: 1.25rem; - flex-shrink: 0; +.column.error { + background-color: rgba(239, 68, 68, 0.02); } /* ===== Responsive ===== */ @media (max-width: 768px) { + .columns-section { + grid-template-columns: 1fr; + gap: var(--spacing-md); + } + .drop-zone { padding: var(--spacing-xl) var(--spacing-md); + min-height: 200px; } .drop-icon { @@ -261,8 +317,18 @@ font-size: var(--font-size-base); } - .file-stats { + .column-header { flex-direction: column; - gap: var(--spacing-sm); + align-items: flex-start; } + + .column-info { + width: 100%; + flex-wrap: wrap; + } + + .info-file-name { + max-width: 100%; + } + } diff --git a/assets/js/UploadManager.js b/assets/js/UploadManager.js index 190767d..7108dc3 100644 --- a/assets/js/UploadManager.js +++ b/assets/js/UploadManager.js @@ -11,17 +11,19 @@ class UploadManager { this.i18n = window.FUZIP_CONFIG?.i18n || {}; // Éléments DOM - this.panel = document.getElementById(`upload-panel-${side}`); + this.panel = document.getElementById(`upload-panel-${side}`); // column-header + this.column = document.getElementById(`column-${side}`); this.dropZone = document.getElementById(`drop-zone-${side}`); this.fileInput = document.getElementById(`file-input-${side}`); this.btnBrowse = document.getElementById(`btn-browse-${side}`); - this.uploadInfo = document.getElementById(`upload-info-${side}`); + this.panelInfo = document.getElementById(`panel-info-${side}`); this.fileName = document.getElementById(`file-name-${side}`); this.fileSize = document.getElementById(`file-size-${side}`); this.fileCount = document.getElementById(`file-count-${side}`); this.progressBar = document.getElementById(`progress-bar-${side}`); this.progressFill = document.getElementById(`progress-fill-${side}`); this.progressText = document.getElementById(`progress-text-${side}`); + this.treePanel = document.getElementById(`tree-panel-${side}`); // État this.currentFile = null; @@ -35,11 +37,15 @@ class UploadManager { * Initialise les événements */ init() { - // Drag & Drop + // Drag & Drop sur toute la colonne + if (this.column) { + this.column.addEventListener('dragover', (e) => this.onDragOver(e)); + this.column.addEventListener('dragleave', (e) => this.onDragLeave(e)); + this.column.addEventListener('drop', (e) => this.onDrop(e)); + } + + // Click sur drop zone pour ouvrir file picker if (this.dropZone) { - this.dropZone.addEventListener('dragover', (e) => this.onDragOver(e)); - this.dropZone.addEventListener('dragleave', (e) => this.onDragLeave(e)); - this.dropZone.addEventListener('drop', (e) => this.onDrop(e)); this.dropZone.addEventListener('click', () => this.fileInput?.click()); } @@ -56,6 +62,12 @@ class UploadManager { this.fileInput.addEventListener('change', (e) => this.onFileSelected(e)); } + // Bouton "Changer" + const btnChange = document.getElementById(`btn-change-${this.side}`); + if (btnChange) { + btnChange.addEventListener('click', () => this.fileInput?.click()); + } + console.log(`[UploadManager] Initialized for side: ${this.side}`); } @@ -65,7 +77,7 @@ class UploadManager { onDragOver(e) { e.preventDefault(); e.stopPropagation(); - this.dropZone?.classList.add('drag-over'); + this.column?.classList.add('drag-over'); } /** @@ -74,7 +86,10 @@ class UploadManager { onDragLeave(e) { e.preventDefault(); e.stopPropagation(); - this.dropZone?.classList.remove('drag-over'); + // Vérifier qu'on quitte vraiment la colonne (pas juste un élément enfant) + if (!this.column?.contains(e.relatedTarget)) { + this.column?.classList.remove('drag-over'); + } } /** @@ -83,7 +98,7 @@ class UploadManager { onDrop(e) { e.preventDefault(); e.stopPropagation(); - this.dropZone?.classList.remove('drag-over'); + this.column?.classList.remove('drag-over'); const files = e.dataTransfer?.files; if (files && files.length > 0) { @@ -197,10 +212,6 @@ class UploadManager { * @param {number} percent - 0-100 */ showProgress(percent) { - if (this.uploadInfo) { - this.uploadInfo.classList.remove('hidden'); - } - if (this.progressBar) { this.progressBar.classList.remove('hidden'); } @@ -220,7 +231,13 @@ class UploadManager { */ showSuccess(stats) { this.panel?.classList.remove('error'); - this.panel?.classList.add('success'); + this.panel?.classList.add('success', 'compact'); + this.column?.classList.add('success'); + + // Affiche le panel-info + if (this.panelInfo) { + this.panelInfo.classList.remove('hidden'); + } if (this.fileName) { this.fileName.textContent = this.currentFile?.name || ''; @@ -234,6 +251,11 @@ class UploadManager { this.fileCount.textContent = (stats.total_files || 0).toString(); } + // Affiche le tree-panel + if (this.treePanel) { + this.treePanel.classList.remove('hidden'); + } + // Cache la progress bar après 1s setTimeout(() => { this.progressBar?.classList.add('hidden'); @@ -253,8 +275,8 @@ class UploadManager { // Réinitialise this.currentFile = null; this.structure = null; - if (this.uploadInfo) { - this.uploadInfo.classList.add('hidden'); + if (this.panelInfo) { + this.panelInfo.classList.add('hidden'); } if (this.progressBar) { this.progressBar.classList.add('hidden'); @@ -290,9 +312,11 @@ class UploadManager { this.structure = null; this.isUploading = false; - this.panel?.classList.remove('success', 'error', 'uploading'); - this.uploadInfo?.classList.add('hidden'); + this.panel?.classList.remove('success', 'error', 'uploading', 'compact'); + this.column?.classList.remove('success', 'error'); + this.panelInfo?.classList.add('hidden'); this.progressBar?.classList.add('hidden'); + this.treePanel?.classList.add('hidden'); if (this.fileInput) { this.fileInput.value = ''; diff --git a/assets/js/app.js b/assets/js/app.js index c66e7b6..8d0c478 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -115,18 +115,24 @@ class FuZipApp { * @param {string|null} fileNameText - Nom du fichier à afficher (optionnel) */ displayUploadInfo(side, stats, fileNameText = null) { - const uploadInfo = document.getElementById(`upload-info-${side}`); + const panelInfo = document.getElementById(`panel-info-${side}`); const fileName = document.getElementById(`file-name-${side}`); const fileSize = document.getElementById(`file-size-${side}`); const fileCount = document.getElementById(`file-count-${side}`); const panel = document.getElementById(`upload-panel-${side}`); + const column = document.getElementById(`column-${side}`); + const treePanel = document.getElementById(`tree-panel-${side}`); if (panel) { - panel.classList.add('success'); + panel.classList.add('success', 'compact'); } - if (uploadInfo) { - uploadInfo.classList.remove('hidden'); + if (column) { + column.classList.add('success'); + } + + if (panelInfo) { + panelInfo.classList.remove('hidden'); } if (fileName && fileNameText) { @@ -140,6 +146,11 @@ class FuZipApp { if (fileSize && stats.total_size !== undefined) { fileSize.textContent = this.formatBytes(stats.total_size); } + + // Affiche le tree-panel + if (treePanel) { + treePanel.classList.remove('hidden'); + } } /** diff --git a/index.php b/index.php index 28d6622..6179bc2 100644 --- a/index.php +++ b/index.php @@ -45,7 +45,8 @@ $i18n = [ 'selected_files' => 'fichiers sélectionnés', 'loading' => 'Chargement...', 'theme_toggle' => 'Changer de thème', - 'lang_toggle' => 'Language' + 'lang_toggle' => 'Language', + 'change_file' => 'Changer' ], 'en' => [ 'title' => 'FuZip - ZIP Files Merger', @@ -69,7 +70,8 @@ $i18n = [ 'selected_files' => 'files selected', 'loading' => 'Loading...', 'theme_toggle' => 'Toggle theme', - 'lang_toggle' => 'Langue' + 'lang_toggle' => 'Langue', + 'change_file' => 'Change' ] ]; @@ -137,93 +139,6 @@ $t = $i18n[$lang];
- -
- -
-

- -
- - - - - -

-

- - -
- - -
- - -
-

- -
- - - - - -

-

- - -
- - -
-
- - -
- -
-
- -
- -
-
- + +
+ +
+ + + + + +

+

+ + +
+ + + + + +
- -
-
- -
- -
-
- + +
+ +
+ + + + + +

+

+ + +
+ + + + + +