fix(ctxmenu): repair library rendering and complete unified row menu
- library.html: remove leftover syntax error + orphan </template></div> that broke libraryPage() (page showed 'undefined' and no files), call the correct fdCtx.openMenu and use self instead of a throwaway libraryPage() instance - _ctx_menu.html: full conventional menu with shortcuts, tags + colour picker, edit-icon picker; closes on outside click and Escape - local_workspace.html: migrate onContextMenu to the shared fdCtx store with complete handlers; drop legacy window._ctxMenuData DOM hacks - dashboard.py: expose page_icon + favorited in the workspace tree
This commit is contained in:
+115
-153
@@ -526,13 +526,7 @@ window._wsInitData = (function() {
|
||||
viewIcons: {tree:'',list:'',details:'',title:'',content:''},
|
||||
viewLabels: {tree:'Tree',list:'List',details:'Details',title:'Cards',content:'Content'},
|
||||
|
||||
// Context menu
|
||||
ctxMenu: {visible:false,x:0,y:0,node:null,tags:[]},
|
||||
ctxTagAdding: false,
|
||||
ctxTagExistingOpen: false,
|
||||
ctxAvailTags: [],
|
||||
ctxNewTagColor: '#787774',
|
||||
ctxTagColors: ['#787774','#E03E3E','#D9730D','#DFAB01','#0F7B6C','#0B6E99','#6940A5','#AD1A72','#E16259','#D4A72C','#448361','#337EA9','#9065B0','#C94D8B'],
|
||||
// Context menu — state lives in the shared fdCtx Alpine store (_ctx_menu.html)
|
||||
|
||||
// Tags
|
||||
workspaceTags: [],
|
||||
@@ -869,7 +863,7 @@ window._wsInitData = (function() {
|
||||
selectForPreview(node) {
|
||||
var panel = document.getElementById('ws-preview-panel');
|
||||
if (!panel) return;
|
||||
document.getElementById('ws-preview-icon').innerHTML = this._fileIcon(node.name, node.is_folder, node.content_format);
|
||||
document.getElementById('ws-preview-icon').innerHTML = this._fileIcon(node.name, node.is_folder, node.content_format, node.page_icon);
|
||||
document.getElementById('ws-preview-title').textContent = node.name;
|
||||
var openBtn = document.getElementById('ws-preview-open-btn');
|
||||
openBtn.onclick = function() { window.location = '/pages/' + node.id; };
|
||||
@@ -1008,61 +1002,95 @@ window._wsInitData = (function() {
|
||||
// ── Content snippet for content view ──
|
||||
contentSnippetMap: {},
|
||||
|
||||
// ── Context menu ──
|
||||
// ── Context menu (menu unifié partagé via le store Alpine fdCtx) ──
|
||||
onContextMenu(ev) {
|
||||
var el = ev.target.closest('[data-ws-id]');
|
||||
var menu = document.querySelector('.more-menu');
|
||||
if (!el || !menu) { if (menu) menu.style.display = 'none'; return; }
|
||||
if (!el) return;
|
||||
var id = parseInt(el.getAttribute('data-ws-id'));
|
||||
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;
|
||||
this.ctxTagExistingOpen = false;
|
||||
this.ctxNewTagColor = '#787774';
|
||||
this.ctxAvailTags = (this.workspaceTags || []).filter(function(t) {
|
||||
return !(node.tags||[]).some(function(nt) { return nt.id === t.id; });
|
||||
if (!id) return;
|
||||
var node = this._findNodeById(this.displayTree, id) || this._findNodeById(this.tree, id);
|
||||
if (!node) return;
|
||||
var store = window.Alpine && Alpine.store('fdCtx');
|
||||
if (!store) return;
|
||||
var self = this;
|
||||
if (!this.workspaceTags || this.workspaceTags.length === 0) this.loadWorkspaceTags();
|
||||
store.setAvail(this._ctxAvailTags(node));
|
||||
var handlers = {
|
||||
open: function (n) { self.openPage(n.id); },
|
||||
openTab: function (n) { window.open('/pages/' + n.id, '_blank'); },
|
||||
peek: function (n) { self.openSidePeek(n.id); },
|
||||
folder: function (n) { if (n.is_folder) self.navigateToFolder(n.id); },
|
||||
rename: function (n) { self.startRename(n); },
|
||||
setIcon: function (icon) { self.setItemIcon(node, icon); },
|
||||
duplicate: function (n) { self.duplicateItem(n); },
|
||||
link: function (n) { self.copyItemLink(n); },
|
||||
move: function (n) { self._ctxMove(n); },
|
||||
fav: function (n) { self.toggleFavorite(n); },
|
||||
delete: function (n) { self.deleteWithUndo(n); },
|
||||
tagExisting: function (t) { self.ctxAddExistingTag(t); },
|
||||
tagAdd: function (name, color) { self.ctxAddNewTag(name, color); },
|
||||
tagRemove: function (tagId) { self.ctxRemoveTag(tagId); }
|
||||
};
|
||||
store.openMenu(ev, node, 'workspace', handlers);
|
||||
},
|
||||
|
||||
_ctxAvailTags(node) {
|
||||
return (this.workspaceTags || []).filter(function(t) {
|
||||
return !((node && node.tags) || []).some(function(nt) { return nt.id === t.id; });
|
||||
});
|
||||
// DOM manipulation (bypasses Alpine reactivity issues)
|
||||
menu.style.display = 'block';
|
||||
menu.style.left = ev.clientX + 'px';
|
||||
menu.style.top = ev.clientY + 'px';
|
||||
// Reposition if offscreen
|
||||
var rect = menu.getBoundingClientRect();
|
||||
var x = ev.clientX, y = ev.clientY;
|
||||
if (x + rect.width > window.innerWidth - 4) x = window.innerWidth - rect.width - 4;
|
||||
if (y + rect.height > window.innerHeight - 4) y = window.innerHeight - rect.height - 4;
|
||||
if (x < 4) x = 4;
|
||||
if (y < 4) y = 4;
|
||||
menu.style.left = x + 'px';
|
||||
menu.style.top = y + 'px';
|
||||
this.ctxMenu.x = x;
|
||||
this.ctxMenu.y = y;
|
||||
// Sync to _ctxMenuData for Alpine reactivity
|
||||
var c = window._ctxMenuData;
|
||||
c.ctxMenu = this.ctxMenu;
|
||||
c.ctxTagAdding = this.ctxTagAdding;
|
||||
c.ctxTagExistingOpen = this.ctxTagExistingOpen;
|
||||
c.ctxAvailTags = this.ctxAvailTags;
|
||||
c.ctxNewTagColor = this.ctxNewTagColor;
|
||||
// Also force Alpine update on the menu element
|
||||
var menuEl = document.querySelector('.more-menu');
|
||||
if (menuEl && menuEl._x_dataStack && menuEl._x_dataStack[0]) {
|
||||
var d = menuEl._x_dataStack[0];
|
||||
d.ctxMenu = this.ctxMenu;
|
||||
d.ctxTagAdding = this.ctxTagAdding;
|
||||
d.ctxTagExistingOpen = this.ctxTagExistingOpen;
|
||||
d.ctxAvailTags = [...this.ctxAvailTags];
|
||||
d.ctxNewTagColor = this.ctxNewTagColor;
|
||||
},
|
||||
|
||||
_ctxRefreshAvail() {
|
||||
var store = window.Alpine && Alpine.store('fdCtx');
|
||||
if (store && store.node) store.setAvail(this._ctxAvailTags(store.node));
|
||||
},
|
||||
|
||||
copyItemLink(node) {
|
||||
if (!node) return;
|
||||
navigator.clipboard.writeText(window.location.origin + '/pages/' + node.id);
|
||||
if (window.showToast) window.showToast('Link copied', 'success');
|
||||
},
|
||||
|
||||
async toggleFavorite(node) {
|
||||
if (!node) return;
|
||||
try {
|
||||
var method = node.favorited ? 'DELETE' : 'POST';
|
||||
var r = await fetch('/board/api/favorites/' + node.id, { method: method });
|
||||
if (r.ok) {
|
||||
node.favorited = !node.favorited;
|
||||
if (window.appState && window.appState.refreshFavorites) window.appState.refreshFavorites();
|
||||
if (window.showToast) window.showToast(node.favorited ? 'Added to Favorites' : 'Removed from Favorites', 'success');
|
||||
}
|
||||
} catch(e) {}
|
||||
},
|
||||
|
||||
async setItemIcon(node, icon) {
|
||||
if (!node || !node.id) return;
|
||||
icon = (icon || '').trim();
|
||||
if (!icon) return;
|
||||
try {
|
||||
var r = await fetch('/board/api/pages/' + node.id + '/icon', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({icon: icon})
|
||||
});
|
||||
if (!r.ok) throw new Error('icon update failed');
|
||||
node.page_icon = icon;
|
||||
this.displayTree = [...this.tree];
|
||||
this._reloadAfterAction();
|
||||
if (window.showToast) window.showToast('Icon updated', 'success');
|
||||
} catch(e) {
|
||||
if (window.showToast) window.showToast('Failed to update icon', 'error');
|
||||
}
|
||||
},
|
||||
|
||||
_ctxMove(node) {
|
||||
if (!node) return;
|
||||
this.selectedIds = {};
|
||||
this.selectedIds[node.id] = true;
|
||||
this.openMovePicker();
|
||||
},
|
||||
|
||||
// ── Long-press (mobile context menu) ──
|
||||
_touchStartX: 0,
|
||||
_touchStartY: 0,
|
||||
@@ -1107,84 +1135,37 @@ window._wsInitData = (function() {
|
||||
this.ctxAddNewTag(tag.name, tag.color);
|
||||
},
|
||||
|
||||
ctxMenuOpenPage() {
|
||||
if (this.ctxMenu.node) this.openPage(this.ctxMenu.node.id);
|
||||
document.querySelector('.more-menu').style.display = 'none';
|
||||
},
|
||||
|
||||
ctxMenuOpenFolder() {
|
||||
if (this.ctxMenu.node) this.navigateToFolder(this.ctxMenu.node.id);
|
||||
document.querySelector('.more-menu').style.display = 'none';
|
||||
},
|
||||
|
||||
ctxMenuRename() {
|
||||
if (this.ctxMenu.node) { this.startRename(this.ctxMenu.node); document.querySelector('.more-menu').style.display = 'none'; }
|
||||
},
|
||||
|
||||
ctxMenuDuplicate() {
|
||||
if (this.ctxMenu.node) { this.duplicateItem(this.ctxMenu.node); document.querySelector('.more-menu').style.display = 'none'; }
|
||||
},
|
||||
|
||||
ctxMenuDelete() {
|
||||
if (this.ctxMenu.node) { this.deleteWithUndo(this.ctxMenu.node); document.querySelector('.more-menu').style.display = 'none'; }
|
||||
},
|
||||
|
||||
ctxRemoveTag(tagId) {
|
||||
var node = this.ctxMenu.node;
|
||||
var store = window.Alpine && Alpine.store('fdCtx');
|
||||
var node = store && store.node;
|
||||
if (!node) return;
|
||||
this.removeTag(node.id, tagId);
|
||||
this.ctxMenu.tags = this.ctxMenu.tags.filter(function(t) { return t.id !== tagId; });
|
||||
// Refresh available tags
|
||||
this.ctxAvailTags = (this.workspaceTags || []).filter(function(t) {
|
||||
return !(this.ctxMenu.tags||[]).some(function(nt) { return nt.id === t.id; });
|
||||
}.bind(this));
|
||||
// Sync to _ctxMenuData
|
||||
window._ctxMenuData.ctxAvailTags = this.ctxAvailTags;
|
||||
window._ctxMenuData.ctxMenu = this.ctxMenu;
|
||||
// Also force Alpine update
|
||||
var menuEl = document.querySelector('.more-menu');
|
||||
if (menuEl && menuEl._x_dataStack && menuEl._x_dataStack[0]) {
|
||||
menuEl._x_dataStack[0].ctxAvailTags = [...this.ctxAvailTags];
|
||||
menuEl._x_dataStack[0].ctxMenu = this.ctxMenu;
|
||||
}
|
||||
node.tags = (node.tags || []).filter(function(t) { return t.id !== tagId; });
|
||||
this._ctxRefreshAvail();
|
||||
},
|
||||
|
||||
async ctxAddNewTag(tagName, color) {
|
||||
tagName = (tagName || '').trim();
|
||||
if (!tagName) return;
|
||||
var node = this.ctxMenu.node;
|
||||
var store = window.Alpine && Alpine.store('fdCtx');
|
||||
var node = store && store.node;
|
||||
if (!node) return;
|
||||
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})
|
||||
});
|
||||
if (r.ok) {
|
||||
var d = await r.json();
|
||||
this.ctxMenu.tags.push(d.tag);
|
||||
this._updateNodeTags(this.tree, node.id, d.tag, 'add');
|
||||
this.displayTree = [...this.tree];
|
||||
this.loadWorkspaceTags();
|
||||
// Refresh available tags
|
||||
var self = this;
|
||||
setTimeout(function() { self.loadWorkspaceTags().then(function() {
|
||||
self.ctxAvailTags = (self.workspaceTags || []).filter(function(t) {
|
||||
return !(self.ctxMenu.tags||[]).some(function(nt) { return nt.id === t.id; });
|
||||
});
|
||||
// Sync to _ctxMenuData
|
||||
window._ctxMenuData.ctxAvailTags = self.ctxAvailTags;
|
||||
window._ctxMenuData.ctxMenu = self.ctxMenu;
|
||||
// Also force Alpine update
|
||||
var menuEl = document.querySelector('.more-menu');
|
||||
if (menuEl && menuEl._x_dataStack && menuEl._x_dataStack[0]) {
|
||||
menuEl._x_dataStack[0].ctxAvailTags = [...self.ctxAvailTags];
|
||||
menuEl._x_dataStack[0].ctxMenu = self.ctxMenu;
|
||||
}
|
||||
// Close menu after successful add
|
||||
document.querySelector('.more-menu').style.display = 'none';
|
||||
}); }, 200);
|
||||
}
|
||||
this.ctxTagAdding = false;
|
||||
color = color || (store && store.newTagColor) || '#787774';
|
||||
try {
|
||||
var r = await fetch('/api/local-workspace/items/' + node.id + '/tags', {
|
||||
method: 'POST', headers: {'Content-Type':'application/json'},
|
||||
body: JSON.stringify({name: tagName, color: color})
|
||||
});
|
||||
if (r.ok) {
|
||||
var d = await r.json();
|
||||
if (!node.tags) node.tags = [];
|
||||
if (!node.tags.some(function(t) { return t.id === d.tag.id; })) node.tags.push(d.tag);
|
||||
this._updateNodeTags(this.tree, node.id, d.tag, 'add');
|
||||
this.displayTree = [...this.tree];
|
||||
this.loadWorkspaceTags();
|
||||
this._ctxRefreshAvail();
|
||||
}
|
||||
} catch(e) {}
|
||||
},
|
||||
|
||||
_markTree(nodes, depth) {
|
||||
@@ -1205,7 +1186,7 @@ window._wsInitData = (function() {
|
||||
for (var i=0; i<children.length; i++) {
|
||||
var c = children[i];
|
||||
var hasKids = c.children && c.children.length > 0;
|
||||
var icon = this._fileIcon(c.name, c.is_folder, c.content_format);
|
||||
var icon = this._fileIcon(c.name, c.is_folder, c.content_format, c.page_icon);
|
||||
var escName = this.esc(c.name);
|
||||
var escId = c.id;
|
||||
html += '<li><div class="ws-tree-item" style="padding-left:'+(depth*20)+'px" draggable="true"'
|
||||
@@ -1759,7 +1740,8 @@ window._wsInitData = (function() {
|
||||
},
|
||||
|
||||
// ── File type icon ──
|
||||
_fileIcon(name, isFolder, contentFormat) {
|
||||
_fileIcon(name, isFolder, contentFormat, customIcon) {
|
||||
if (customIcon) return '<span class="page-icon-svg" style="font-size:14px;line-height:1;">'+this.esc(customIcon)+'</span>';
|
||||
if (isFolder) return '<span class="page-icon-svg">'+getSvgIcon('folder',14)+'</span>';
|
||||
// FlowDeck internal pages (no extension, blocks/markdown format)
|
||||
if (contentFormat && contentFormat !== 'file') return '<span class="page-icon-svg">'+getSvgIcon('edit',14)+'</span>';
|
||||
@@ -2428,32 +2410,12 @@ for (var _i = 0; _i < _wsKeys.length; _i++) {
|
||||
try { window[_wsKeys[_i]] = window._wsInitData[_wsKeys[_i]]; } catch(e) {}
|
||||
}
|
||||
_wsInitData = window._wsInitData;
|
||||
// Objet léger pour le ctx-menu (évite le conflit $nextTick avec Alpine)
|
||||
window._ctxMenuData = {
|
||||
ctxMenu: {visible:false,x:0,y:0,node:null,tags:[]},
|
||||
ctxTagAdding: false,
|
||||
ctxTagExistingOpen: false,
|
||||
ctxAvailTags: [],
|
||||
ctxNewTagColor: '#787774',
|
||||
ctxTagColors: ['#787774','#E03E3E','#D9730D','#DFAB01','#0F7B6C','#0B6E99','#6940A5','#AD1A72','#E16259','#D4A72C','#448361','#337EA9','#9065B0','#C94D8B'],
|
||||
// Use Alpine proxy (window._wsData) for reactivity, not raw object (window._wsInitData)
|
||||
_ws() { return window._wsData || window._wsInitData; },
|
||||
ctxMenuOpenPage() { this._ws().ctxMenuOpenPage(); },
|
||||
ctxMenuOpenFolder() { this._ws().ctxMenuOpenFolder(); },
|
||||
ctxMenuRename() { this._ws().ctxMenuRename(); },
|
||||
ctxMenuDuplicate() { this._ws().ctxMenuDuplicate(); },
|
||||
ctxMenuDelete() { this._ws().ctxMenuDelete(); },
|
||||
ctxAddExistingTag(t) { this._ws().ctxAddExistingTag(t); },
|
||||
ctxAddNewTag(n, c) { this._ws().ctxAddNewTag(n, c); },
|
||||
ctxRemoveTag(id) { this._ws().ctxRemoveTag(id); },
|
||||
};
|
||||
console.log('FLOWDECK v2.4.6 — IIFE done, _wsInitData keys:', Object.keys(window._wsInitData).length);
|
||||
</script>
|
||||
<script>console.log('FLOWDECK v2.4.6 — ws-split about to render, _wsInitData exists:', typeof window._wsInitData !== 'undefined');</script>
|
||||
|
||||
<div class="ws-split"
|
||||
@contextmenu.prevent="_wsInitData.onContextMenu($event)"
|
||||
@click.self="ctxMenu.visible = false"
|
||||
@touchstart="onTouchStart($event)"
|
||||
@touchend="onTouchEnd($event)"
|
||||
@touchmove="onTouchMove($event)"
|
||||
@@ -2678,7 +2640,7 @@ console.log('FLOWDECK v2.4.6 — IIFE done, _wsInitData keys:', Object.keys(wind
|
||||
<span style="width:16px;flex-shrink:0;"></span>
|
||||
</template>
|
||||
|
||||
<span class="icon" x-html="_fileIcon(node.name, node.is_folder, node.content_format)"></span>
|
||||
<span class="icon" x-html="_fileIcon(node.name, node.is_folder, node.content_format, node.page_icon)"></span>
|
||||
|
||||
<template x-if="node.is_folder">
|
||||
<span class="name folder" @click.stop="navigateToFolder(node.id)"
|
||||
@@ -2776,7 +2738,7 @@ console.log('FLOWDECK v2.4.6 — IIFE done, _wsInitData keys:', Object.keys(wind
|
||||
<tr :class="{ selected: !!selectedIds[node.id] }">
|
||||
<td><input type="checkbox" :checked="!!selectedIds[node.id]" @click.stop="toggleSelect(node, $event)"></td>
|
||||
<td>
|
||||
<span class="table-icon" x-html="_fileIcon(node.name, node.is_folder, node.content_format)"></span>
|
||||
<span class="table-icon" x-html="_fileIcon(node.name, node.is_folder, node.content_format, node.page_icon)"></span>
|
||||
<span x-show="node.is_shared" class="ws-shared-badge" title="Partagé" x-text="'👥'"></span>
|
||||
<span class="col-name" @click="node.is_folder ? navigateToFolder(node.id) : openPage(node.id)" x-text="node.name"></span>
|
||||
</td>
|
||||
@@ -2833,7 +2795,7 @@ console.log('FLOWDECK v2.4.6 — IIFE done, _wsInitData keys:', Object.keys(wind
|
||||
</tr>
|
||||
<template x-for="node in displayTree" :key="'l'+node.id">
|
||||
<tr :data-ws-id="node.id" @click="node.is_folder ? navigateToFolder(node.id) : selectForPreview(node)" @mouseenter="showPreview($event, node)" @mouseleave="hidePreview()" style="cursor:pointer">
|
||||
<td><span x-html="_fileIcon(node.name, node.is_folder, node.content_format)"></span>
|
||||
<td><span x-html="_fileIcon(node.name, node.is_folder, node.content_format, node.page_icon)"></span>
|
||||
<span x-show="node.is_shared" class="ws-shared-badge" title="Partagé" x-text="'👥'"></span></td>
|
||||
<td class="col-name" x-text="node.name"></td>
|
||||
<td style="font-size:12px;color:var(--text-tertiary)" x-text="node.is_folder ? 'Folder' : _fileTypeLabel(node.name, node.content_format)"></td>
|
||||
@@ -2871,7 +2833,7 @@ console.log('FLOWDECK v2.4.6 — IIFE done, _wsInitData keys:', Object.keys(wind
|
||||
<template x-for="node in displayTree" :key="'d'+node.id">
|
||||
<tr :data-ws-id="node.id" @click="node.is_folder ? navigateToFolder(node.id) : selectForPreview(node)" @mouseenter="showPreview($event, node)" @mouseleave="hidePreview()" style="cursor:pointer"
|
||||
:class="{ 'selected-row': previewItem && previewItem.id === node.id }">
|
||||
<td><span class="table-icon" x-html="_fileIcon(node.name, node.is_folder, node.content_format)"></span>
|
||||
<td><span class="table-icon" x-html="_fileIcon(node.name, node.is_folder, node.content_format, node.page_icon)"></span>
|
||||
<span x-show="node.is_shared" class="ws-shared-badge" title="Partagé" x-text="'👥'"></span></td>
|
||||
<td class="col-name" x-text="node.name"></td>
|
||||
<td class="col-path" x-text="node._path || '—'"></td>
|
||||
@@ -2902,7 +2864,7 @@ console.log('FLOWDECK v2.4.6 — IIFE done, _wsInitData keys:', Object.keys(wind
|
||||
<template x-for="node in displayTree" :key="'g'+node.id">
|
||||
<div class="title-card" :data-ws-id="node.id" @click="node.is_folder ? navigateToFolder(node.id) : selectForPreview(node)" @mouseenter="showPreview($event, node)" @mouseleave="hidePreview()"
|
||||
:class="{ 'selected-card': previewItem && previewItem.id === node.id }">
|
||||
<div class="title-card-icon" x-html="node.is_folder ? getSvgIcon('folder',24) : _fileIcon(node.name, node.is_folder, node.content_format)"></div>
|
||||
<div class="title-card-icon" x-html="node.is_folder ? getSvgIcon('folder',24) : _fileIcon(node.name, node.is_folder, node.content_format, node.page_icon)"></div>
|
||||
<div class="title-card-name">
|
||||
<span x-show="node.is_shared" class="ws-shared-badge" title="Partagé" x-text="'👥'"></span>
|
||||
<span x-text="node.name"></span>
|
||||
@@ -2929,7 +2891,7 @@ console.log('FLOWDECK v2.4.6 — IIFE done, _wsInitData keys:', Object.keys(wind
|
||||
<div class="content-item" :data-ws-id="node.id" @click="node.is_folder ? navigateToFolder(node.id) : selectForPreview(node)" @mouseenter="showPreview($event, node)" @mouseleave="hidePreview()"
|
||||
:class="{ 'selected-row': previewItem && previewItem.id === node.id }">
|
||||
<div class="content-item-header">
|
||||
<span x-html="_fileIcon(node.name, node.is_folder, node.content_format)"></span>
|
||||
<span x-html="_fileIcon(node.name, node.is_folder, node.content_format, node.page_icon)"></span>
|
||||
<span x-show="node.is_shared" class="ws-shared-badge" title="Partagé" x-text="'👥'"></span>
|
||||
<span class="col-name" x-text="node.name"></span>
|
||||
<span style="font-size:11px;color:var(--text-tertiary);margin-left:auto" x-text="_formatDate(node.updated_at)"></span>
|
||||
|
||||
Reference in New Issue
Block a user