feat(content): v4.6.0 Content Blocks enrichis — Callout, TOC, Math (KaTeX), Toggle, Multi-colonnes
- Ajout blocs enrichis dans l'éditeur: callout (avec sélecteur d'emoji), table of contents (ancres), math (LaTeX/KaTeX), toggle lists (enfants collapsibles), multi-colonnes - Intégration KaTeX 0.16.11 self-hosté (JS/CSS/fonts) — aucun CDN externe - Rendu des nouveaux blocs dans les pages publiques (/p/<slug>): TOC, KaTeX, colonnes, toggle <details> - Persistance 'children' (colonnes/toggle) + export Markdown étendu - Sidebar customization par utilisateur (config API + colonne sidebar_config) - Correctif test_views_calendar: parsing des query params year/month (le défaut ouvrait sur le mois courant) - Tests: 184 passing
This commit is contained in:
+244
-34
@@ -6,6 +6,7 @@
|
||||
<title>FlowDeck — {% block title_prefix %}Home{% endblock %}</title>
|
||||
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg">
|
||||
<link rel="stylesheet" href="/static/css/app.css?v=3.0.0">
|
||||
<link rel="stylesheet" href="/static/css/katex.min.css?v=0.16.11">
|
||||
<style>
|
||||
/* ── Mobile responsive (v4.0.2) ── */
|
||||
@media (max-width: 768px) {
|
||||
@@ -222,10 +223,10 @@
|
||||
|
||||
<div class="sidebar-scroll">
|
||||
<!-- Workspace / Private -->
|
||||
<div class="sidebar-section">
|
||||
<div class="sidebar-section-header" @click="toggleSection('workspace')">
|
||||
<div class="sidebar-section" x-show="isSectionVisible('workspace')" x-transition:enter="transition ease-out duration-200" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100">
|
||||
<div class="sidebar-section-header" @click="toggleSection('workspace')" @contextmenu.prevent="openSectionMenu($event, 'workspace')">
|
||||
<div class="sidebar-section-title">
|
||||
<span class="chevron" :class="{ open: sectionsOpen.workspace }" x-text="sectionsOpen.workspace ? '▼' : '▶'"></span>
|
||||
<span class="chevron" :class="{ open: sectionsOpen.workspace }">▶</span>
|
||||
{% if has_active_workspace %}
|
||||
<span><span style="vertical-align:sub;margin-right:4px;">{{ fd_icon("folder",16) }}</span>{{ active_ws_name if active_ws_name else "" }}{% if gitea_workspace or (workspace_key and "/" in workspace_key) %} {{ fd_icon("link",12) }}{% endif %}</span>
|
||||
{% else %}
|
||||
@@ -237,6 +238,7 @@
|
||||
<button class="section-action-btn" title="New Page" @click.stop="window.FlowDeck.createPage()">{{ fd_icon("file",16) }}</button>
|
||||
<button class="section-action-btn" title="New Folder" @click.stop="window.FlowDeck.showCreateFolderModal()">{{ fd_icon("folder",16) }}</button>
|
||||
<a class="section-action-btn" href="/local-workspace" title="Open workspace page" style="text-decoration:none;">{{ fd_icon("external-link",16) }}</a>
|
||||
<button class="section-action-btn section-menu-btn" title="Section options" @click.stop="openSectionMenu($event, 'workspace')" @contextmenu.stop="openSectionMenu($event, 'workspace')">⋮</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -261,14 +263,16 @@
|
||||
|
||||
<!-- Repository (Gitea) — only visible for Gitea workspaces -->
|
||||
{% if gitea_workspace %}
|
||||
<div class="sidebar-section">
|
||||
<div class="sidebar-section-header" @click="toggleSection('gitea')">
|
||||
<div class="sidebar-section" x-show="isSectionVisible('gitea')" x-transition:enter="transition ease-out duration-200" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100">
|
||||
<div class="sidebar-section-header" @click="toggleSection('gitea')" @contextmenu.prevent="openSectionMenu($event, 'gitea')">
|
||||
<div class="sidebar-section-title">
|
||||
<span class="chevron" :class="{ open: sectionsOpen.gitea }" x-text="sectionsOpen.gitea ? '▼' : '▶'"></span>
|
||||
<span>{{ fd_icon("link",14) }} Repository (Gitea)</span>
|
||||
<span class="chevron" :class="{ open: sectionsOpen.gitea }">▶</span>
|
||||
<span class="section-icon">{{ fd_icon("link",14) }}</span>
|
||||
<span class="section-label">Repository (Gitea)</span>
|
||||
</div>
|
||||
<div class="sidebar-section-actions">
|
||||
<button class="section-action-btn" title="Refresh" @click.stop="if(window._gwData)window._gwData.refreshTree()">{{ fd_icon("refresh",16) }}</button>
|
||||
<button class="section-action-btn section-menu-btn" title="Section options" @click.stop="openSectionMenu($event, 'gitea')">⋮</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-section-items" x-show="sectionsOpen.gitea" x-transition>
|
||||
@@ -280,16 +284,18 @@
|
||||
{% endif %}
|
||||
|
||||
<!-- Meetings -->
|
||||
<div class="sidebar-section">
|
||||
<div class="sidebar-section-header" @click="toggleSection('meetings')">
|
||||
<div class="sidebar-section" x-show="isSectionVisible('meetings')" x-transition:enter="transition ease-out duration-200" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100">
|
||||
<div class="sidebar-section-header" @click="toggleSection('meetings')" @contextmenu.prevent="openSectionMenu($event, 'meetings')">
|
||||
<div class="sidebar-section-title">
|
||||
<span class="chevron" :class="{ open: sectionsOpen.meetings }" x-text="sectionsOpen.meetings ? '▼' : '▶'"></span>
|
||||
<span>Meetings</span>
|
||||
<span class="chevron" :class="{ open: sectionsOpen.meetings }">▶</span>
|
||||
<span class="section-icon">{{ fd_icon("calendar",14) }}</span>
|
||||
<span class="section-label">Meetings</span>
|
||||
</div>
|
||||
<div class="sidebar-section-actions">
|
||||
{% if has_active_workspace %}
|
||||
<button class="section-action-btn" title="Add" @click.stop="window.FlowDeck.createPage()">+</button>
|
||||
{% endif %}
|
||||
<button class="section-action-btn section-menu-btn" title="Section options" @click.stop="openSectionMenu($event, 'meetings')">⋮</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-section-items" x-show="sectionsOpen.meetings" x-transition>
|
||||
@@ -298,14 +304,16 @@
|
||||
</div>
|
||||
|
||||
<!-- Recents -->
|
||||
<div class="sidebar-section">
|
||||
<div class="sidebar-section-header" @click="toggleSection('recents')">
|
||||
<div class="sidebar-section" x-show="isSectionVisible('recents')" x-transition:enter="transition ease-out duration-200" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100">
|
||||
<div class="sidebar-section-header" @click="toggleSection('recents')" @contextmenu.prevent="openSectionMenu($event, 'recents')">
|
||||
<div class="sidebar-section-title">
|
||||
<span class="chevron" :class="{ open: sectionsOpen.recents }" x-text="sectionsOpen.recents ? '▼' : '▶'"></span>
|
||||
<span>Recents</span>
|
||||
<span class="chevron" :class="{ open: sectionsOpen.recents }">▶</span>
|
||||
<span class="section-icon">{{ fd_icon("clock",14) }}</span>
|
||||
<span class="section-label">Recents</span>
|
||||
</div>
|
||||
<div class="sidebar-section-actions">
|
||||
<a href="/library?tab=Recents" class="library-link-btn" title="View in Library" @click.stop>{{ fd_icon("book",14) }}</a>
|
||||
<button class="section-action-btn section-menu-btn" title="Section options" @click.stop="openSectionMenu($event, 'recents')">⋮</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-section-items" x-show="sectionsOpen.recents" x-transition>
|
||||
@@ -321,14 +329,16 @@
|
||||
</div>
|
||||
|
||||
<!-- Favorites -->
|
||||
<div class="sidebar-section">
|
||||
<div class="sidebar-section-header" @click="toggleSection('favorites')">
|
||||
<div class="sidebar-section" x-show="isSectionVisible('favorites')" x-transition:enter="transition ease-out duration-200" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100">
|
||||
<div class="sidebar-section-header" @click="toggleSection('favorites')" @contextmenu.prevent="openSectionMenu($event, 'favorites')">
|
||||
<div class="sidebar-section-title">
|
||||
<span class="chevron" :class="{ open: sectionsOpen.favorites }" x-text="sectionsOpen.favorites ? '▼' : '▶'"></span>
|
||||
<span>Favorites</span>
|
||||
<span class="chevron" :class="{ open: sectionsOpen.favorites }">▶</span>
|
||||
<span class="section-icon">{{ fd_icon("star",14) }}</span>
|
||||
<span class="section-label">Favorites</span>
|
||||
</div>
|
||||
<div class="sidebar-section-actions">
|
||||
<a href="/library?tab=Favorites" class="library-link-btn" title="View in Library" @click.stop>{{ fd_icon("book",14) }}</a>
|
||||
<button class="section-action-btn section-menu-btn" title="Section options" @click.stop="openSectionMenu($event, 'favorites')">⋮</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-section-items" x-show="sectionsOpen.favorites" x-transition>
|
||||
@@ -344,9 +354,17 @@
|
||||
</div>
|
||||
|
||||
<!-- Agents -->
|
||||
<div class="sidebar-section">
|
||||
<div class="sidebar-section-header" @click="toggleSection('agents')">
|
||||
<div class="sidebar-section-title"><span>Agents</span></div>
|
||||
<div class="sidebar-section" x-show="isSectionVisible('agents')" x-transition:enter="transition ease-out duration-200" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100">
|
||||
<div class="sidebar-section-header" @click="toggleSection('agents')" @contextmenu.prevent="openSectionMenu($event, 'agents')">
|
||||
<div class="sidebar-section-title">
|
||||
<span class="chevron" :class="{ open: sectionsOpen.agents }">▶</span>
|
||||
<span class="section-icon">{{ fd_icon("bot",14) }}</span>
|
||||
<span class="section-label">Agents</span>
|
||||
</div>
|
||||
<div class="sidebar-section-actions">
|
||||
<button class="section-action-btn" title="New agent" @click.stop="">+</button>
|
||||
<button class="section-action-btn section-menu-btn" title="Section options" @click.stop="openSectionMenu($event, 'agents')">⋮</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-section-items" x-show="sectionsOpen.agents" x-transition>
|
||||
<ul class="sidebar-items"><li class="sidebar-item empty-hint"><span class="page-icon page-icon-svg">{{ fd_icon("bot",16) }}</span><span class="page-name text-dim">No agents configured</span></li></ul>
|
||||
@@ -354,14 +372,16 @@
|
||||
</div>
|
||||
|
||||
<!-- Shared -->
|
||||
<div class="sidebar-section">
|
||||
<div class="sidebar-section-header" @click="toggleSection('shared')">
|
||||
<div class="sidebar-section" x-show="isSectionVisible('shared')" x-transition:enter="transition ease-out duration-200" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100">
|
||||
<div class="sidebar-section-header" @click="toggleSection('shared')" @contextmenu.prevent="openSectionMenu($event, 'shared')">
|
||||
<div class="sidebar-section-title">
|
||||
<span class="chevron" :class="{ open: sectionsOpen.shared }" x-text="sectionsOpen.shared ? '▼' : '▶'"></span>
|
||||
<span>Shared</span>
|
||||
<span class="chevron" :class="{ open: sectionsOpen.shared }">▶</span>
|
||||
<span class="section-icon">{{ fd_icon("users",14) }}</span>
|
||||
<span class="section-label">Shared</span>
|
||||
</div>
|
||||
<div class="sidebar-section-actions">
|
||||
<a href="/library?tab=Shared" class="library-link-btn" title="View in Library" @click.stop>{{ fd_icon("book",14) }}</a>
|
||||
<button class="section-action-btn section-menu-btn" title="Section options" @click.stop="openSectionMenu($event, 'shared')">⋮</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-section-items" x-show="sectionsOpen.shared" x-transition>
|
||||
@@ -377,14 +397,16 @@
|
||||
</div>
|
||||
|
||||
<!-- Published -->
|
||||
<div class="sidebar-section">
|
||||
<div class="sidebar-section-header" @click="toggleSection('published')">
|
||||
<div class="sidebar-section" x-show="isSectionVisible('published')" x-transition:enter="transition ease-out duration-200" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100">
|
||||
<div class="sidebar-section-header" @click="toggleSection('published')" @contextmenu.prevent="openSectionMenu($event, 'published')">
|
||||
<div class="sidebar-section-title">
|
||||
<span class="chevron" :class="{ open: sectionsOpen.published }" x-text="sectionsOpen.published ? '▼' : '▶'"></span>
|
||||
<span>Published</span>
|
||||
<span class="chevron" :class="{ open: sectionsOpen.published }">▶</span>
|
||||
<span class="section-icon">{{ fd_icon("globe",14) }}</span>
|
||||
<span class="section-label">Published</span>
|
||||
</div>
|
||||
<div class="sidebar-section-actions">
|
||||
<a href="/library?tab=Published" class="library-link-btn" title="View in Library" @click.stop>{{ fd_icon("book",14) }}</a>
|
||||
<button class="section-action-btn section-menu-btn" title="Section options" @click.stop="openSectionMenu($event, 'published')">⋮</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-section-items" x-show="sectionsOpen.published" x-transition>
|
||||
@@ -401,14 +423,16 @@
|
||||
|
||||
<!-- Private -->
|
||||
{% if auth_method != 'local' or '/' in workspace_key %}
|
||||
<div class="sidebar-section">
|
||||
<div class="sidebar-section-header" @click="toggleSection('private')">
|
||||
<div class="sidebar-section" x-show="isSectionVisible('private')" x-transition:enter="transition ease-out duration-200" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100">
|
||||
<div class="sidebar-section-header" @click="toggleSection('private')" @contextmenu.prevent="openSectionMenu($event, 'private')">
|
||||
<div class="sidebar-section-title">
|
||||
<span class="chevron" :class="{ open: sectionsOpen.private }" x-text="sectionsOpen.private ? '▼' : '▶'"></span>
|
||||
<span>Private</span>
|
||||
<span class="chevron" :class="{ open: sectionsOpen.private }">▶</span>
|
||||
<span class="section-icon">{{ fd_icon("lock",14) }}</span>
|
||||
<span class="section-label">Private</span>
|
||||
</div>
|
||||
<div class="sidebar-section-actions">
|
||||
<a href="/library?tab=Private" class="library-link-btn" title="View in Library" @click.stop>{{ fd_icon("book",14) }}</a>
|
||||
<button class="section-action-btn section-menu-btn" title="Section options" @click.stop="openSectionMenu($event, 'private')">⋮</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-section-items" x-show="sectionsOpen.private" x-transition>
|
||||
@@ -424,6 +448,30 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Customize Sidebar → shown in customize mode -->
|
||||
<div class="sidebar-customize-panel" x-show="customizing" x-cloak x-transition:enter="transition ease-out duration-200" x-transition:enter-start="opacity-0 translate-y-2" x-transition:enter-end="opacity-100 translate-y-0">
|
||||
<div class="scp-header">
|
||||
<span class="scp-title">Customize Sidebar</span>
|
||||
<button class="scp-done" @click="toggleCustomize()">Done</button>
|
||||
</div>
|
||||
<div class="scp-list">
|
||||
<template x-for="(cfg, key) in (Object.keys(sidebarConfig).length ? sidebarConfig : {
|
||||
workspace:{visible:true,order:0},meetings:{visible:true,order:1},
|
||||
recents:{visible:true,order:2},favorites:{visible:true,order:3},
|
||||
agents:{visible:true,order:4},shared:{visible:true,order:5},published:{visible:true,order:6}
|
||||
})" :key="key">
|
||||
<div class="scp-item" @click="toggleSectionVisibility(key)">
|
||||
<div class="scp-item-left">
|
||||
<span class="scp-item-icon" x-text="getSectionIcon(key)"></span>
|
||||
<span class="scp-item-name" x-text="getSectionLabel(key)"></span>
|
||||
</div>
|
||||
<span class="scp-item-eye" x-show="cfg.visible !== false">👁</span>
|
||||
<span class="scp-item-eye scp-item-eye-off" x-show="cfg.visible === false">👁🗨</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Notion apps / Utilities → replaced by static links footer (v4.0.2) -->
|
||||
<!-- Bottom links (always visible, no section wrapper) -->
|
||||
<div class="sidebar-static-links" style="padding: 4px 12px;">
|
||||
@@ -456,6 +504,51 @@
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- /sidebar-scroll -->
|
||||
|
||||
<!-- Section options menu (⋮ dropdown) -->
|
||||
<div class="section-menu-overlay" x-show="sectionMenu.visible" @click="closeSectionMenu()" @contextmenu.prevent="closeSectionMenu()"></div>
|
||||
<div class="section-menu" x-show="sectionMenu.visible" x-cloak
|
||||
:style="{ top: sectionMenu.y + 'px', left: Math.min(sectionMenu.x, window.innerWidth - 220) + 'px' }"
|
||||
@click.outside="closeSectionMenu()">
|
||||
<div class="section-menu-item" @click="closeSectionMenu(); setShowCount(sectionMenu.section, 5)">
|
||||
<span class="smi-label">Show 5 items</span>
|
||||
<span class="smi-check" x-show="sidebarConfig[sectionMenu.section] && sidebarConfig[sectionMenu.section].show_count === 5">✓</span>
|
||||
</div>
|
||||
<div class="section-menu-item" @click="closeSectionMenu(); setShowCount(sectionMenu.section, 10)">
|
||||
<span class="smi-label">Show 10 items</span>
|
||||
<span class="smi-check" x-show="!sidebarConfig[sectionMenu.section] || sidebarConfig[sectionMenu.section].show_count === 10 || sidebarConfig[sectionMenu.section].show_count == null">✓</span>
|
||||
</div>
|
||||
<div class="section-menu-item" @click="closeSectionMenu(); setShowCount(sectionMenu.section, 15)">
|
||||
<span class="smi-label">Show 15 items</span>
|
||||
<span class="smi-check" x-show="sidebarConfig[sectionMenu.section] && sidebarConfig[sectionMenu.section].show_count === 15">✓</span>
|
||||
</div>
|
||||
<div class="section-menu-item" @click="closeSectionMenu(); setShowCount(sectionMenu.section, 20)">
|
||||
<span class="smi-label">Show 20 items</span>
|
||||
<span class="smi-check" x-show="sidebarConfig[sectionMenu.section] && sidebarConfig[sectionMenu.section].show_count === 20">✓</span>
|
||||
</div>
|
||||
<div class="section-menu-sep"></div>
|
||||
<div class="section-menu-item" @click="closeSectionMenu(); moveSection(sectionMenu.section, 'up')">
|
||||
<span class="smi-icon">↑</span>
|
||||
<span class="smi-label">Move up</span>
|
||||
</div>
|
||||
<div class="section-menu-item" @click="closeSectionMenu(); moveSection(sectionMenu.section, 'down')">
|
||||
<span class="smi-icon">↓</span>
|
||||
<span class="smi-label">Move down</span>
|
||||
</div>
|
||||
<div class="section-menu-sep"></div>
|
||||
<div class="section-menu-item" @click="closeSectionMenu(); toggleSectionVisibility(sectionMenu.section)">
|
||||
<span class="smi-icon">👁</span>
|
||||
<span class="smi-label" x-text="isSectionVisible(sectionMenu.section) ? 'Hide section' : 'Show section'"></span>
|
||||
</div>
|
||||
<div class="section-menu-sep"></div>
|
||||
<div class="section-menu-item section-menu-customize" @click="closeSectionMenu(); toggleCustomize()">
|
||||
<span class="smi-icon">⚙️</span>
|
||||
<span class="smi-label">Customize sidebar</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Customize sidebar overlay + panel (full sidebar takeover) -->
|
||||
<div class="customize-overlay" x-show="customizing" @click="toggleCustomize()" x-cloak></div>
|
||||
</aside>
|
||||
|
||||
<!-- Uncollapse button → inside topbar, no overlap -->
|
||||
@@ -832,6 +925,7 @@
|
||||
return {
|
||||
init() {
|
||||
window.appState = this;
|
||||
this.loadSidebarConfig();
|
||||
},
|
||||
sidebarCollapsed: false,
|
||||
mobileSidebarOpen: false,
|
||||
@@ -993,6 +1087,122 @@
|
||||
try { localStorage.setItem('fd_sections', JSON.stringify(this.sectionsOpen)); }
|
||||
catch(e) {}
|
||||
},
|
||||
// ── Sidebar customization ──
|
||||
customizing: false,
|
||||
sidebarConfig: {},
|
||||
sectionMenu: { section: null, visible: false, x: 0, y: 0 },
|
||||
|
||||
loadSidebarConfig() {
|
||||
var self = this;
|
||||
try {
|
||||
var raw = {{ sidebar_config|default('{}')|safe }};
|
||||
if (raw && raw.config) {
|
||||
self.sidebarConfig = raw.config;
|
||||
} else if (typeof raw === 'object') {
|
||||
self.sidebarConfig = raw;
|
||||
}
|
||||
} catch(e) {
|
||||
self.sidebarConfig = {};
|
||||
}
|
||||
},
|
||||
|
||||
saveSidebarConfig() {
|
||||
var self = this;
|
||||
fetch('/api/sidebar/config', {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': window.FlowDeck.getCsrfToken() },
|
||||
body: JSON.stringify({ config: this.sidebarConfig })
|
||||
}).then(function(r) {
|
||||
if (!r.ok) self.toast('Failed to save sidebar config', 'error');
|
||||
}).catch(function() {
|
||||
self.toast('Failed to save sidebar config', 'error');
|
||||
});
|
||||
},
|
||||
|
||||
isSectionVisible(key) {
|
||||
var cfg = this.sidebarConfig[key];
|
||||
return cfg ? cfg.visible !== false : true;
|
||||
},
|
||||
|
||||
getSectionOrder(key) {
|
||||
var cfg = this.sidebarConfig[key];
|
||||
var sections = ['workspace','gitea','meetings','recents','favorites','agents','shared','published'];
|
||||
if (cfg && typeof cfg.order === 'number') return cfg.order;
|
||||
return sections.indexOf(key);
|
||||
},
|
||||
|
||||
toggleSectionVisibility(key) {
|
||||
if (!this.sidebarConfig[key]) this.sidebarConfig[key] = {};
|
||||
this.sidebarConfig[key].visible = !this.isSectionVisible(key);
|
||||
this.sidebarConfig = Object.assign({}, this.sidebarConfig);
|
||||
this.saveSidebarConfig();
|
||||
},
|
||||
|
||||
moveSection(key, direction) {
|
||||
var self = this;
|
||||
var sections = Object.keys(this.sidebarConfig).length ?
|
||||
Object.keys(this.sidebarConfig).sort(function(a,b) {
|
||||
return (self.sidebarConfig[a] && self.sidebarConfig[a].order || 99) -
|
||||
(self.sidebarConfig[b] && self.sidebarConfig[b].order || 99);
|
||||
}) :
|
||||
['workspace','gitea','meetings','recents','favorites','agents','shared','published'];
|
||||
var idx = sections.indexOf(key);
|
||||
if (idx < 0) return;
|
||||
var swapIdx = direction === 'up' ? idx - 1 : idx + 1;
|
||||
if (swapIdx < 0 || swapIdx >= sections.length) return;
|
||||
var swapKey = sections[swapIdx];
|
||||
var aOrder = this.sidebarConfig[key] && this.sidebarConfig[key].order;
|
||||
var bOrder = this.sidebarConfig[swapKey] && this.sidebarConfig[swapKey].order;
|
||||
if (aOrder == null) aOrder = idx;
|
||||
if (bOrder == null) bOrder = swapIdx;
|
||||
if (!this.sidebarConfig[key]) this.sidebarConfig[key] = {};
|
||||
if (!this.sidebarConfig[swapKey]) this.sidebarConfig[swapKey] = {};
|
||||
this.sidebarConfig[key].order = bOrder;
|
||||
this.sidebarConfig[swapKey].order = aOrder;
|
||||
this.sidebarConfig = Object.assign({}, this.sidebarConfig);
|
||||
this.saveSidebarConfig();
|
||||
},
|
||||
|
||||
setShowCount(key, count) {
|
||||
if (!this.sidebarConfig[key]) this.sidebarConfig[key] = {};
|
||||
this.sidebarConfig[key].show_count = count;
|
||||
this.sidebarConfig = Object.assign({}, this.sidebarConfig);
|
||||
this.saveSidebarConfig();
|
||||
},
|
||||
|
||||
toggleCustomize() {
|
||||
this.customizing = !this.customizing;
|
||||
this.sectionMenu.visible = false;
|
||||
},
|
||||
|
||||
openSectionMenu(ev, section) {
|
||||
ev.stopPropagation();
|
||||
this.sectionMenu = { section: section, visible: true, x: ev.clientX, y: ev.clientY };
|
||||
},
|
||||
|
||||
closeSectionMenu() {
|
||||
this.sectionMenu.visible = false;
|
||||
},
|
||||
|
||||
getSectionIcon(key) {
|
||||
var icons = {
|
||||
workspace: '📁', meetings: '📅', recents: '🕐', favorites: '⭐',
|
||||
agents: '🤖', shared: '👥', published: '🌐', gitea: '🔗',
|
||||
private: '🔒', library: '📚', 'my-tasks': '✅', marketplace: '🛒',
|
||||
help: '❓', trash: '🗑️'
|
||||
};
|
||||
return icons[key] || '📋';
|
||||
},
|
||||
getSectionLabel(key) {
|
||||
var labels = {
|
||||
workspace: 'Workspace', gitea: 'Repository (Gitea)', meetings: 'Meetings',
|
||||
recents: 'Recents', favorites: 'Favorites', agents: 'Agents',
|
||||
shared: 'Shared', published: 'Published', private: 'Private',
|
||||
library: 'Library', 'my-tasks': 'My Tasks', marketplace: 'Marketplace',
|
||||
help: 'Help', trash: 'Trash'
|
||||
};
|
||||
return labels[key] || key;
|
||||
},
|
||||
workspaceMenuOpen: false,
|
||||
toggleWorkspaceMenu() {
|
||||
this.workspaceMenuOpen = !this.workspaceMenuOpen;
|
||||
|
||||
Reference in New Issue
Block a user