feat: brain sidebar manage mode — add/delete folders and tags
- "Manage folders & tags" button at bottom of sidebar - Click to enter manage mode: - + button appears next to Folders/Tags headers - Inline input to type and add new folder/tag - × delete button appears on each item - Delete confirms before removing - "Done" button exits manage mode - Tags/folders created/deleted via taxonomy API - Sidebar refreshes after changes Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -341,26 +341,63 @@
|
|||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class="sidebar-separator"></div>
|
<div class="sidebar-separator"></div>
|
||||||
<div class="sidebar-section-label">Folders</div>
|
<div class="sidebar-section-head">
|
||||||
|
<div class="sidebar-section-label">Folders</div>
|
||||||
|
{#if showManage}
|
||||||
|
<button class="sidebar-section-add" onclick={() => { newTaxName = ''; sidebarView = 'folders'; }}>+</button>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{#if showManage && sidebarView === 'folders'}
|
||||||
|
<div class="sidebar-add-row">
|
||||||
|
<input class="sidebar-add-input" placeholder="New folder..." bind:value={newTaxName} onkeydown={(e) => { if (e.key === 'Enter') addTaxonomy(); }} />
|
||||||
|
<button class="sidebar-add-go" onclick={addTaxonomy}>Add</button>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
<nav class="sidebar-nav">
|
<nav class="sidebar-nav">
|
||||||
{#each sidebarFolders.filter(f => f.is_active) as folder}
|
{#each sidebarFolders.filter(f => f.is_active) as folder}
|
||||||
<button class="nav-item" class:active={activeFolder === folder.name} onclick={() => { activeFolder = folder.name; activeFolderId = folder.id; activeTag = null; activeTagId = null; loadItems(); }}>
|
<button class="nav-item" class:active={activeFolder === folder.name} onclick={() => { activeFolder = folder.name; activeFolderId = folder.id; activeTag = null; activeTagId = null; loadItems(); }}>
|
||||||
<span class="nav-label">{folder.name}</span>
|
<span class="nav-label">{folder.name}</span>
|
||||||
{#if folder.item_count > 0}<span class="nav-count">{folder.item_count}</span>{/if}
|
{#if showManage}
|
||||||
|
<button class="nav-delete" onclick={(e) => { e.stopPropagation(); if (confirm(`Delete "${folder.name}"? Items will be moved.`)) deleteTaxonomy(folder.id); }}>×</button>
|
||||||
|
{:else if folder.item_count > 0}
|
||||||
|
<span class="nav-count">{folder.item_count}</span>
|
||||||
|
{/if}
|
||||||
</button>
|
</button>
|
||||||
{/each}
|
{/each}
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class="sidebar-separator"></div>
|
<div class="sidebar-separator"></div>
|
||||||
<div class="sidebar-section-label">Tags</div>
|
<div class="sidebar-section-head">
|
||||||
|
<div class="sidebar-section-label">Tags</div>
|
||||||
|
{#if showManage}
|
||||||
|
<button class="sidebar-section-add" onclick={() => { newTaxName = ''; sidebarView = 'tags'; }}>+</button>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{#if showManage && sidebarView === 'tags'}
|
||||||
|
<div class="sidebar-add-row">
|
||||||
|
<input class="sidebar-add-input" placeholder="New tag..." bind:value={newTaxName} onkeydown={(e) => { if (e.key === 'Enter') addTaxonomy(); }} />
|
||||||
|
<button class="sidebar-add-go" onclick={addTaxonomy}>Add</button>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
<nav class="sidebar-nav">
|
<nav class="sidebar-nav">
|
||||||
{#each sidebarTags.filter(t => t.is_active) as tag}
|
{#each sidebarTags.filter(t => t.is_active) as tag}
|
||||||
<button class="nav-item" class:active={activeTag === tag.name} onclick={() => { activeTag = tag.name; activeTagId = tag.id; activeFolder = null; activeFolderId = null; loadItems(); }}>
|
<button class="nav-item" class:active={activeTag === tag.name} onclick={() => { activeTag = tag.name; activeTagId = tag.id; activeFolder = null; activeFolderId = null; loadItems(); }}>
|
||||||
<span class="nav-label">{tag.name}</span>
|
<span class="nav-label">{tag.name}</span>
|
||||||
<span class="nav-count">{tag.item_count}</span>
|
{#if showManage}
|
||||||
|
<button class="nav-delete" onclick={(e) => { e.stopPropagation(); if (confirm(`Delete tag "${tag.name}"?`)) deleteTaxonomy(tag.id); }}>×</button>
|
||||||
|
{:else if tag.item_count > 0}
|
||||||
|
<span class="nav-count">{tag.item_count}</span>
|
||||||
|
{/if}
|
||||||
</button>
|
</button>
|
||||||
{/each}
|
{/each}
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
<div class="sidebar-separator"></div>
|
||||||
|
<div class="sidebar-manage-row">
|
||||||
|
<button class="sidebar-manage-btn" onclick={() => showManage = !showManage}>
|
||||||
|
{showManage ? 'Done' : 'Manage folders & tags'}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<!-- Main content -->
|
<!-- Main content -->
|
||||||
@@ -761,10 +798,56 @@
|
|||||||
.nav-item.active .nav-count { color: #7f5f3d; opacity: 0.8; }
|
.nav-item.active .nav-count { color: #7f5f3d; opacity: 0.8; }
|
||||||
|
|
||||||
.sidebar-separator { height: 1px; background: rgba(35,26,17,0.08); margin: 12px 18px; }
|
.sidebar-separator { height: 1px; background: rgba(35,26,17,0.08); margin: 12px 18px; }
|
||||||
|
|
||||||
|
.sidebar-section-head {
|
||||||
|
display: flex; align-items: center; justify-content: space-between;
|
||||||
|
padding: 4px 18px 6px;
|
||||||
|
}
|
||||||
.sidebar-section-label {
|
.sidebar-section-label {
|
||||||
font-size: 0.68rem; font-weight: 700; text-transform: uppercase;
|
font-size: 0.68rem; font-weight: 700; text-transform: uppercase;
|
||||||
letter-spacing: 0.14em; color: #8c7b69; padding: 4px 18px 6px;
|
letter-spacing: 0.14em; color: #8c7b69;
|
||||||
}
|
}
|
||||||
|
.sidebar-section-add {
|
||||||
|
width: 20px; height: 20px; border-radius: 6px;
|
||||||
|
border: none; background: rgba(35,26,17,0.06);
|
||||||
|
color: #7f5f3d; font-size: 0.85rem; font-weight: 700;
|
||||||
|
display: flex; align-items: center; justify-content: center;
|
||||||
|
cursor: pointer; transition: all 140ms;
|
||||||
|
}
|
||||||
|
.sidebar-section-add:hover { background: rgba(35,26,17,0.12); }
|
||||||
|
|
||||||
|
.sidebar-add-row {
|
||||||
|
display: flex; gap: 4px; padding: 0 12px; margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
.sidebar-add-input {
|
||||||
|
flex: 1; padding: 6px 10px; border-radius: 10px;
|
||||||
|
border: 1px solid rgba(35,26,17,0.12); background: rgba(255,255,255,0.7);
|
||||||
|
font-size: 0.8rem; font-family: var(--font); color: #1e1812; outline: none;
|
||||||
|
}
|
||||||
|
.sidebar-add-input:focus { border-color: rgba(179,92,50,0.4); }
|
||||||
|
.sidebar-add-input::placeholder { color: #8c7b69; }
|
||||||
|
.sidebar-add-go {
|
||||||
|
padding: 6px 10px; border-radius: 10px; border: none;
|
||||||
|
background: #1e1812; color: white; font-size: 0.75rem; font-weight: 600;
|
||||||
|
font-family: var(--font); cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-delete {
|
||||||
|
width: 22px; height: 22px; border-radius: 6px;
|
||||||
|
border: none; background: none; color: #8c7b69;
|
||||||
|
font-size: 0.9rem; display: flex; align-items: center; justify-content: center;
|
||||||
|
cursor: pointer; transition: all 140ms; flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.nav-delete:hover { background: rgba(220,38,38,0.1); color: #DC2626; }
|
||||||
|
|
||||||
|
.sidebar-manage-row { padding: 0 12px; }
|
||||||
|
.sidebar-manage-btn {
|
||||||
|
width: 100%; padding: 8px; border-radius: 10px;
|
||||||
|
border: 1px solid rgba(35,26,17,0.08); background: none;
|
||||||
|
font-size: 0.78rem; color: #8c7b69; font-family: var(--font);
|
||||||
|
cursor: pointer; transition: all 140ms;
|
||||||
|
}
|
||||||
|
.sidebar-manage-btn:hover { background: rgba(255,248,241,0.72); color: #1f1811; }
|
||||||
|
|
||||||
.brain-content {
|
.brain-content {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user