diff --git a/app/templates/local_workspace.html b/app/templates/local_workspace.html index 93d22e3..f343130 100644 --- a/app/templates/local_workspace.html +++ b/app/templates/local_workspace.html @@ -751,6 +751,10 @@ window._wsInitData = (function() { if (!id) { menu.style.display = 'none'; return; } var node = this._findNodeById(this.displayTree, id); if (!node) { menu.style.display = 'none'; return; } + // Ensure workspace tags are loaded + if (!this.workspaceTags || this.workspaceTags.length === 0) { + this.loadWorkspaceTags(); + } // Store in Alpine data for menu actions (ctxMenuOpenPage, etc.) this.ctxMenu = {visible:true, x:ev.clientX, y:ev.clientY, node:node, tags:[...(node.tags||[])]}; this.ctxTagAdding = false; @@ -868,7 +872,7 @@ window._wsInitData = (function() { if (!tagName) return; var node = this.ctxMenu.node; if (!node) return; - color = color || this.ctxNewTagColor; + color = color || window._ctxMenuData.ctxNewTagColor; var r = await fetch('/api/local-workspace/items/' + node.id + '/tags', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({name: tagName.trim(), color: color}) @@ -1393,9 +1397,28 @@ window._wsInitData = (function() { var q = (this.searchQuery || '').toLowerCase().trim(); var ft = this.filterType || ''; if (!q && !ft && !this.tagFilter) { this.displayTree = [...this.tree]; this._computeFilteredTableItems(); return; } - this.displayTree = [...this.tree]; + if (this.tagFilter) { + // Filter tree by tag + this.displayTree = this._filterTreeByTag([...this.tree], this.tagFilter); + } else { + this.displayTree = [...this.tree]; + } this._computeFilteredTableItems(); }, + _filterTreeByTag(nodes, tagName) { + var result = []; + for (var i=0; i 0) { + var clone = Object.assign({}, n); + clone.children = filteredChildren; + result.push(clone); + } + } + return result; + }, filterByType(type) { this.filterType = (this.filterType === type) ? '' : type; this.doFilter(); diff --git a/app/templates/settings.html b/app/templates/settings.html index ce8b447..8f86f6c 100644 --- a/app/templates/settings.html +++ b/app/templates/settings.html @@ -57,6 +57,13 @@ .color-swatch:hover{transform:scale(1.15);} .color-swatch.selected{border-color:var(--text);box-shadow:0 0 0 2px var(--accent);} +/* Modal (for tag delete/rename) */ +.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:var(--bg);border:1px solid var(--border-strong);border-radius:12px;padding:24px;min-width:320px;box-shadow:0 12px 40px rgba(0,0,0,.5);} +.modal-box h3{font-size:16px;font-weight:600;color:var(--text);} +.btn-danger{background:#E03E3E;color:#fff;border:none;padding:6px 16px;border-radius:6px;cursor:pointer;font-size:13px;} +.btn-danger:hover{background:#C93535;} + /* Close button */ .settings-close{position:absolute;top:12px;right:12px;width:32px;height:32px;background:none;border:none;color:var(--text-dim);font-size:20px;cursor:pointer;border-radius:6px;display:flex;align-items:center;justify-content:center;} .settings-close:hover{background:var(--bg-hover);color:var(--text);} @@ -218,7 +225,7 @@

Are you sure you want to delete the tag ""? - ⚠️ This tag is used on item(s). Removing it will also remove it from those items. + ⚠️ This tag is used on item(s).

@@ -227,6 +234,22 @@
+ + @@ -288,6 +311,8 @@ document.addEventListener('alpine:init', function() { newTagName: '', newTagColor: '#787774', deletingTag: null, + renamingTag: null, + renameValue: '', presetColors: ['#787774','#E03E3E','#D9730D','#DFAB01','#0F7B6C','#0B6E99','#6940A5','#AD1A72','#E16259','#D4A72C','#448361','#337EA9','#9065B0','#C94D8B'], avatarUrl: '{{ avatar_url or "" }}', avatarColor: '{{ avatar_color or "#3A3A3A" }}', @@ -332,12 +357,27 @@ document.addEventListener('alpine:init', function() { }, async renameTag(tag) { - var newName = prompt('Rename tag "' + tag.name + '":', tag.name); - if (!newName || !newName.trim() || newName.trim().toLowerCase() === tag.name.toLowerCase()) return; + this.renamingTag = tag; + this.renameValue = tag.name; + // Focus the input after Alpine renders the modal + var self = this; + this.$nextTick(function() { + var input = document.querySelector('.modal-box input[type=text]'); + if (input) { input.focus(); input.select(); } + }); + }, + + async confirmRenameTag() { + var tag = this.renamingTag; + var newName = this.renameValue.trim(); + if (!tag || !newName || newName.toLowerCase() === tag.name.toLowerCase()) { + this.renamingTag = null; return; + } await fetch('/api/settings/tags/' + tag.id, { method: 'PUT', headers: {'Content-Type':'application/json'}, - body: JSON.stringify({name: newName.trim()}) + body: JSON.stringify({name: newName}) }); + this.renamingTag = null; await this.loadTags(); },