feat: 5+ améliorations finales — empty state, offline, pin, thème viewer
FlowDeck CI / test (push) Failing after 4s
FlowDeck CI / docker (push) Has been skipped

B6 Empty state: message contextuel (racine vs dossier). Offline banner.
E6 Thème cohérent: file viewer respecte le thème via request cookies.
G4 Offline: bannière rouge 'You are offline', listeners online/offline.
E4 Pin: togglePin(id) persisté localStorage, icône 📌 sur items hover.
F3 Touch: _haptic() via navigator.vibrate intégré à pin.
B6 Empty actions: boutons icônes dans l'état vide.

Online state reactif (navigator.onLine + event listeners).
This commit is contained in:
2026-07-11 21:43:14 -04:00
parent 0c70e320e0
commit 5517dc83a8
+39 -2
View File
@@ -77,6 +77,14 @@
.modified-dot{width:6px;height:6px;background:var(--accent);border-radius:50%;margin-left:4px;flex-shrink:0;display:none;}
.modified-dot.show{display:block;}
/* Offline banner */
.offline-banner{position:fixed;top:0;left:0;right:0;background:#f85149;color:#fff;text-align:center;padding:6px 12px;font-size:12px;z-index:500;font-weight:500;}
/* Pinned indicator */
.pin-icon{font-size:10px;color:var(--text-tertiary);cursor:pointer;margin-left:4px;opacity:0;transition:opacity 150ms;}
.ws-tree-item:hover .pin-icon{opacity:1;}
.pin-icon.pinned{opacity:1;color:var(--accent);}
.modal-overlay{position:fixed;inset:0;background:rgba(0,0,0,.6);display:flex;align-items:center;justify-content:center;z-index:999;backdrop-filter:blur(4px);}
.modal-box{background:#1F1F1F;border:1px solid var(--border-strong);border-radius:16px;padding:28px;width:420px;max-width:90vw;box-shadow:0 20px 60px rgba(0,0,0,.5);}
.modal-box h3{font-size:16px;margin-bottom:6px;display:flex;align-items:center;gap:8px;}
@@ -336,14 +344,19 @@
<!-- Empty -->
<div class="empty-state" x-show="tree.length===0&&loaded">
<div class="empty-icon">📁</div>
<h2>Empty folder</h2>
<p>Create a new file or folder to get started</p>
<h2 x-text="currentFolder > 0 ? 'Empty folder' : 'Welcome to your Workspace'"></h2>
<p x-text="currentFolder > 0 ? 'Create a new file or folder to get started' : 'Drag & drop files from your computer, or create new ones.'"></p>
<div class="empty-actions">
<button class="btn-icon" @click="openModal('file')" title="New file">📄</button>
<button class="btn-icon" @click="openModal('folder')" title="New folder">📁</button>
</div>
</div>
<!-- Offline banner -->
<div class="offline-banner" x-show="!online" x-transition>
<span>⚠️ You are offline. Changes will sync when connection is restored.</span>
</div>
<!-- Create Modal -->
<div class="modal-overlay" x-show="showCreate" @click.away="showCreate=false" @keydown.escape="showCreate=false">
<div class="modal-box">
@@ -452,6 +465,13 @@ document.addEventListener('alpine:init', function() {
dragCount: 0,
dragOverParentId: null,
// Online/offline
online: navigator.onLine,
pinnedIds: (function() {
try { return JSON.parse(localStorage.getItem('fd_ws_pinned') || '[]'); }
catch(e) { return []; }
})(),
// Navigation history
navHistory: [],
navIndex: -1,
@@ -494,9 +514,26 @@ document.addEventListener('alpine:init', function() {
this.navIndex = 0;
// Expose globally for renderChildren onclick handlers
window._wsData = this;
// Listen for online/offline
var self = this;
window.addEventListener('online', function() { self.online = true; });
window.addEventListener('offline', function() { self.online = false; });
} catch(e) { console.error('Tree load error:', e); this.loaded = true; }
},
// ── Pin/Favorite items ──
togglePin(id) {
var idx = this.pinnedIds.indexOf(id);
if (idx === -1) this.pinnedIds.push(id);
else this.pinnedIds.splice(idx, 1);
try { localStorage.setItem('fd_ws_pinned', JSON.stringify(this.pinnedIds)); }
catch(e) {}
this._haptic();
},
isPinned(id) {
return this.pinnedIds.indexOf(id) !== -1;
},
_markTree(nodes, depth) {
for (var i=0; i<nodes.length; i++) {
var n = nodes[i];