fix: sidebar — x-data vide masquait appState() + header Notion-style + null-guards
- Sidebar avait x-data vide qui créait un scope isolé → vars (workspaceMenuOpen, toggleWorkspaceMenu, sidebarCollapsed) introuvables → rien ne fonctionnait - Suppression x-data → héritage du scope appState() parent - Header restylé Notion: .sidebar-workspace-header avec border-radius + hover bg - Mouse hover (mouseenter/mouseleave) active wsHeaderHover → fond plus clair - Null-guards: folderStack[-1] sécurisé, ctxMenu.node && ctxMenu.node.is_folder
This commit is contained in:
+23
-25
@@ -58,33 +58,30 @@
|
|||||||
<aside class="sidebar"
|
<aside class="sidebar"
|
||||||
:class="{ collapsed: sidebarCollapsed, 'mobile-open': mobileSidebarOpen }"
|
:class="{ collapsed: sidebarCollapsed, 'mobile-open': mobileSidebarOpen }"
|
||||||
id="sidebar"
|
id="sidebar"
|
||||||
x-data x-init="$nextTick(() => { if(typeof initTreeSortable==='function') initTreeSortable(); })">
|
x-init="$nextTick(() => { if(typeof initTreeSortable==='function') initTreeSortable(); })">
|
||||||
<!-- Workspace header + mobile back -->
|
<!-- Workspace header styled like Notion -->
|
||||||
<div style="display:flex;align-items:center;gap:4px;">
|
<div class="sidebar-workspace-header" @click="toggleWorkspaceMenu" @mouseenter="wsHeaderHover=true" @mouseleave="wsHeaderHover=false"
|
||||||
<button class="sidebar-back-btn" @click="mobileSidebarOpen = false; sidebarCollapsed = true;" x-show="mobileSidebarOpen" title="Fermer le menu">
|
:class="{ hover: wsHeaderHover || workspaceMenuOpen }">
|
||||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
|
<div class="workspace-info">
|
||||||
</button>
|
<div class="workspace-avatar">{{ workspaceInitial }}</div>
|
||||||
<div class="sidebar-workspace" @click="toggleWorkspaceMenu" style="flex:1;">
|
<span class="workspace-name">{{ workspaceName }}</span>
|
||||||
<div class="workspace-info">
|
|
||||||
<div class="workspace-avatar">{{ workspaceInitial }}</div>
|
|
||||||
<span class="workspace-name">{{ workspaceName }}</span>
|
|
||||||
</div>
|
|
||||||
<span class="workspace-chevron" :class="{ open: workspaceMenuOpen }">▾</span>
|
|
||||||
</div>
|
</div>
|
||||||
<!-- User menu dropdown -->
|
<span class="workspace-chevron" :class="{ open: workspaceMenuOpen }">▾</span>
|
||||||
<div class="user-menu-dropdown" x-show="workspaceMenuOpen" @click.outside="workspaceMenuOpen=false" x-transition>
|
</div>
|
||||||
<div class="um-user-info">
|
<!-- User menu dropdown -->
|
||||||
<div class="um-avatar">{{ workspaceInitial }}</div>
|
<div class="user-menu-dropdown" x-show="workspaceMenuOpen" @click.outside="workspaceMenuOpen=false" x-transition>
|
||||||
<div>
|
<div class="um-user-info">
|
||||||
<div class="um-name">{{ user.full_name or user.login }}</div>
|
<div class="um-avatar">{{ workspaceInitial }}</div>
|
||||||
<div class="um-plan">{{ user.email or '' }}</div>
|
<div>
|
||||||
</div>
|
<div class="um-name">{{ user.full_name or user.login }}</div>
|
||||||
|
<div class="um-plan">{{ user.email or '' }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="um-sep"></div>
|
</div>
|
||||||
<a href="/settings" class="um-item" @click="workspaceMenuOpen=false">⚙️ Settings</a>
|
<div class="um-sep"></div>
|
||||||
<a href="/workspaces" class="um-item" @click="workspaceMenuOpen=false">🔄 Switch workspace</a>
|
<a href="/settings" class="um-item" @click="workspaceMenuOpen=false">⚙️ Settings</a>
|
||||||
<div class="um-sep"></div>
|
<a href="/workspaces" class="um-item" @click="workspaceMenuOpen=false">🔄 Switch workspace</a>
|
||||||
<a href="/auth/logout" class="um-item um-danger" @click="workspaceMenuOpen=false">🚪 Log out</a>
|
<div class="um-sep"></div>
|
||||||
|
<a href="/auth/logout" class="um-item um-danger" @click="workspaceMenuOpen=false">🚪 Log out</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -523,6 +520,7 @@
|
|||||||
sidebarCollapsed: false,
|
sidebarCollapsed: false,
|
||||||
mobileSidebarOpen: false,
|
mobileSidebarOpen: false,
|
||||||
showInvite: true,
|
showInvite: true,
|
||||||
|
wsHeaderHover: false,
|
||||||
workspaceName: '{{ workspace_name }}',
|
workspaceName: '{{ workspace_name }}',
|
||||||
workspaceInitial: '{{ workspace_initial }}',
|
workspaceInitial: '{{ workspace_initial }}',
|
||||||
currentPage: '{{ current_page }}',
|
currentPage: '{{ current_page }}',
|
||||||
|
|||||||
@@ -723,7 +723,7 @@
|
|||||||
<div class="modal-box">
|
<div class="modal-box">
|
||||||
<h3><span x-text="createType==='folder'?'📁':'📄'"></span> <span x-text="createType==='folder'?'New Folder':'New File'"></span></h3>
|
<h3><span x-text="createType==='folder'?'📁':'📄'"></span> <span x-text="createType==='folder'?'New Folder':'New File'"></span></h3>
|
||||||
<p class="modal-sub">
|
<p class="modal-sub">
|
||||||
In <strong>{{ workspace_name }}</strong> <span x-show="folderStack.length>1">/ <span x-text="folderStack[folderStack.length-1].name"></span></span>
|
In <strong>{{ workspace_name }}</strong> <span x-show="folderStack.length>1">/ <span x-text="(folderStack[folderStack.length-1]||{}).name||''"></span></span>
|
||||||
<span x-show="parentFolder"> / <span x-text="parentFolder?.name"></span></span>
|
<span x-show="parentFolder"> / <span x-text="parentFolder?.name"></span></span>
|
||||||
</p>
|
</p>
|
||||||
<input class="modal-input" x-model="newName" :placeholder="createType==='folder'?'Folder name':'File name'" @keydown.enter="doCreate" x-ref="cinp">
|
<input class="modal-input" x-model="newName" :placeholder="createType==='folder'?'Folder name':'File name'" @keydown.enter="doCreate" x-ref="cinp">
|
||||||
@@ -769,7 +769,7 @@
|
|||||||
@keydown.escape="ctxMenu.visible=false"
|
@keydown.escape="ctxMenu.visible=false"
|
||||||
x-transition>
|
x-transition>
|
||||||
<div class="ctx-item" @click="ctxMenuOpenPage()">📄 Open</div>
|
<div class="ctx-item" @click="ctxMenuOpenPage()">📄 Open</div>
|
||||||
<div class="ctx-item" x-show="ctxMenu.node.is_folder" @click="ctxMenuOpenFolder()">📂 Open folder</div>
|
<div class="ctx-item" x-show="ctxMenu.node && ctxMenu.node.is_folder" @click="ctxMenuOpenFolder()">📂 Open folder</div>
|
||||||
<div class="ctx-item" @click="ctxMenuRename()">✏️ Rename</div>
|
<div class="ctx-item" @click="ctxMenuRename()">✏️ Rename</div>
|
||||||
<div class="ctx-item" @click="ctxMenuDuplicate()">📋 Duplicate</div>
|
<div class="ctx-item" @click="ctxMenuDuplicate()">📋 Duplicate</div>
|
||||||
<div class="ctx-sep"></div>
|
<div class="ctx-sep"></div>
|
||||||
|
|||||||
+17
-1
@@ -128,8 +128,24 @@ input, select, textarea { font-family: inherit; color: inherit; }
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Workspace header */
|
/* Workspace header — Notion style */
|
||||||
|
.sidebar-workspace-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 4px 8px;
|
||||||
|
margin: 4px 8px;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 150ms;
|
||||||
|
min-height: 32px;
|
||||||
|
}
|
||||||
|
.sidebar-workspace-header:hover,
|
||||||
|
.sidebar-workspace-header.hover {
|
||||||
|
background: var(--bg-hover);
|
||||||
|
}
|
||||||
.sidebar-workspace {
|
.sidebar-workspace {
|
||||||
|
/* keep for backward compat */
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|||||||
Reference in New Issue
Block a user