333 lines
19 KiB
HTML
333 lines
19 KiB
HTML
{###############################################################################
|
||
_ctx_menu.html — LE menu contextuel UNIQUE de FlowDeck
|
||
═══════════════════════════════════════════════════════════════════════════
|
||
Inclus par library.html ET local_workspace.html (les 2 seules pages du
|
||
contexte fichier). Ce partial est LE SEUL menu : son markup décrit l'UNION
|
||
des options des deux pages d'origine. Les exécutions sont déléguées par
|
||
chaque page au travers d'un store Alpine enregistré PLUS BAS (IIFE + défense
|
||
d'exécution unique → include 2 fois = store 1 fois).
|
||
|
||
Chaque item se masque quand le handler correspondant n'existe pas sur la
|
||
page (x-show="$store.fdCtx.has('key')") → menu structurellement identique,
|
||
avec la capacité respective de la page au clic.
|
||
|
||
Handlers attendus (tous optionnels) :
|
||
open, openTab, peek, folder, rename, setIcon, duplicate, link, download,
|
||
copyContent, move, fav, recent, delete, tagExisting, tagAdd, tagRemove
|
||
############################################################################}
|
||
<script data-cfasync="false">
|
||
/* ═════════════════════════════════════════════════════════════════════
|
||
fdCtx — store Alpine UNIQUE du menu contextuel partagé.
|
||
Enregistré dans 'alpine:init' avec garde d'exécution : que la page
|
||
inclue ce partial dans base.html ou directement, le js ne s'exécute
|
||
qu'une seule fois. Chaque page, à l'ouverture du menu, positionne :
|
||
fdCtx.openMenu(evt, node, pageHash, handlers)
|
||
─────────────────────────────────────────────────────────────────── */
|
||
(function () {
|
||
if (window.__fdCtxMenuRegistered) return;
|
||
window.__fdCtxMenuRegistered = true;
|
||
|
||
document.addEventListener('alpine:init', function () {
|
||
if (window.Alpine && window.Alpine.__fdCtxStore) return;
|
||
if (window.Alpine) window.Alpine.__fdCtxStore = true;
|
||
|
||
Alpine.store('fdCtx', {
|
||
open: false, x: 0, y: 0, node: null, page: null,
|
||
maxH: 0, _cx: 0, _cy: 0, _ro: null,
|
||
handlers: {},
|
||
/* Tags (workspace) */
|
||
availTags: [], tagAdding: false, tagExistingOpen: false,
|
||
newTagColor: '#787774',
|
||
tagColors: ['#787774','#E03E3E','#D9730D','#DFAB01','#0F7B6C','#0B6E99','#6940A5','#AD1A72','#E16259','#D4A72C','#448361','#337EA9','#9065B0','#C94D8B'],
|
||
/* Icon picker */
|
||
iconOpen: false,
|
||
iconChoices: ['📄','📝','📕','📁','⭐','🔖','📌','✅','💡','🔥','🚀','🎯','📊','🗓️','🔗','🧩','📎','🎨','🐛','⚙️','❤️','👍','✨','🏷️','🗒️','📚'],
|
||
|
||
/* Positionne le menu à l'écran et expose les handlers de la page.
|
||
⚠️ Nom : openMenu (et PAS open) — « open » est réservé au booléen
|
||
d'état x-show. Une collision ici rendrait le menu PERMANENT. */
|
||
openMenu(ev, node, pageHash, handlers) {
|
||
handlers = handlers || {};
|
||
this.node = node;
|
||
this.page = pageHash;
|
||
this.handlers = handlers;
|
||
this.tagAdding = false;
|
||
this.tagExistingOpen = false;
|
||
this.iconOpen = false;
|
||
this.newTagColor = (node && node.tags && node.tags[0] && node.tags[0].color) || '#787774';
|
||
var cx = (ev && ev.clientX) || 0;
|
||
var cy = (ev && ev.clientY) || 0;
|
||
this._cx = cx;
|
||
this._cy = cy;
|
||
this.x = Math.max(8, Math.min(cx, window.innerWidth - 240));
|
||
this.y = Math.max(8, Math.min(cy, window.innerHeight - 48));
|
||
this.open = true;
|
||
var self = this;
|
||
/* Mesure la taille réelle du menu (une fois rendu) puis le replace
|
||
pour qu'il reste TOUJOURS entièrement visible dans le viewport.
|
||
Un ResizeObserver relance le placement à chaque fois que le menu
|
||
change de taille (ouverture d'un sous-menu « tag », icônes, …),
|
||
sinon il grandissait vers le bas et sortait de l'écran. */
|
||
var after = function () {
|
||
self._place();
|
||
var el = document.querySelector('.fd-ctx-menu');
|
||
if (el && window.ResizeObserver) {
|
||
if (self._ro) { try { self._ro.disconnect(); } catch (e) {} }
|
||
self._ro = new ResizeObserver(function () { self._place(); });
|
||
self._ro.observe(el);
|
||
}
|
||
};
|
||
if (window.Alpine && window.Alpine.nextTick) window.Alpine.nextTick(after);
|
||
else setTimeout(after, 0);
|
||
},
|
||
/* Reclasse le menu dans le viewport et limite sa hauteur à l'espace
|
||
disponible sous son ancre (le contenu déborde en scroll interne). */
|
||
_place() {
|
||
var el = document.querySelector('.fd-ctx-menu');
|
||
if (!el) return;
|
||
var prev = el.style.maxHeight;
|
||
el.style.maxHeight = 'none';
|
||
var w = el.offsetWidth || 240;
|
||
var h = el.offsetHeight || 320;
|
||
el.style.maxHeight = prev || '';
|
||
var vw = window.innerWidth, vh = window.innerHeight;
|
||
var cx = (this._cx == null ? this.x : this._cx);
|
||
var cy = (this._cy == null ? this.y : this._cy);
|
||
var nx = cx;
|
||
if (nx + w > vw - 8) nx = vw - w - 8;
|
||
nx = Math.max(8, nx);
|
||
var ny = cy;
|
||
if (ny + h > vh - 8) {
|
||
if (cy - h >= 8) ny = cy - h;
|
||
else ny = Math.max(8, vh - h - 8);
|
||
}
|
||
this.x = nx;
|
||
this.y = ny;
|
||
this.maxH = Math.max(120, vh - ny - 8);
|
||
},
|
||
close() {
|
||
if (this._ro) { try { this._ro.disconnect(); } catch (e) {} this._ro = null; }
|
||
this.open = false;
|
||
this.node = null;
|
||
this.handlers = {};
|
||
this.tagAdding = false;
|
||
this.tagExistingOpen = false;
|
||
this.iconOpen = false;
|
||
},
|
||
|
||
/* Un item est-il disponible pour CETTE page ? (union vs capacités) */
|
||
has(key) { return typeof this.handlers[key] === 'function'; },
|
||
|
||
/* Exécute l'action → handler fourni par la page courante. */
|
||
run(key) {
|
||
if (!this.node) { this.close(); return; }
|
||
var fn = this.handlers[key];
|
||
if (fn) try { fn(this.node); } catch (e) { console.error('fdCtx.run', e); }
|
||
this.close();
|
||
},
|
||
|
||
/* ── Tags ── */
|
||
avail() { return this.availTags || []; },
|
||
setAvail(a) { this.availTags = a || []; },
|
||
removeTag(id) {
|
||
var fn = this.handlers.tagRemove;
|
||
if (fn) try { fn(id); } catch (e) { console.error('fdCtx.removeTag', e); }
|
||
},
|
||
addExistingTag(t) {
|
||
var fn = this.handlers.tagExisting;
|
||
if (fn) try { fn(t); } catch (e) { console.error('fdCtx.addExistingTag', e); }
|
||
this.tagExistingOpen = false;
|
||
},
|
||
addNewTag(name, color) {
|
||
name = (name || '').trim();
|
||
if (!name) return;
|
||
var fn = this.handlers.tagAdd;
|
||
if (fn) try { fn(name, color || this.newTagColor); } catch (e) { console.error('fdCtx.addNewTag', e); }
|
||
this.tagAdding = false;
|
||
},
|
||
|
||
/* ── Icon picker ── */
|
||
setIcon(icon) {
|
||
icon = (icon || '').trim();
|
||
var fn = this.handlers.setIcon;
|
||
if (fn) try { fn(icon); } catch (e) { console.error('fdCtx.setIcon', e); }
|
||
this.close();
|
||
},
|
||
openIconPicker() {
|
||
var fn = this.handlers.setIcon;
|
||
if (!fn) return;
|
||
if (!window.FDIconPicker) return;
|
||
window.FDIconPicker.openFor({
|
||
x: this.x,
|
||
y: this.y,
|
||
onPick: fn,
|
||
onRemove: function () { fn(''); }
|
||
});
|
||
this.close();
|
||
},
|
||
});
|
||
});
|
||
})();
|
||
</script>
|
||
|
||
<style>
|
||
.fd-ctx-menu{position:fixed !important;top:0;left:0;min-width:230px;max-width:280px;max-height:calc(100vh - 16px);overflow-y:auto;z-index:2000;padding:4px;}
|
||
.fd-ctx-menu .menu-item{display:flex;align-items:center;gap:8px;padding:6px 10px;font-size:13px;color:var(--text-primary);cursor:pointer;border-radius:4px;transition:background .1s;white-space:nowrap;}
|
||
.fd-ctx-menu .menu-item:hover{background:var(--bg-hover);}
|
||
.fd-ctx-menu .menu-item svg{width:14px;height:14px;flex-shrink:0;}
|
||
.fd-ctx-menu .menu-danger{color:var(--danger);}
|
||
.fd-ctx-menu .menu-shortcut{margin-left:auto;font-size:11px;color:var(--text-dim);padding-left:16px;}
|
||
.fd-ctx-menu .more-sep{height:1px;background:var(--border);margin:4px 6px;}
|
||
.fd-ctx-menu .ctx-label{color:var(--text-dim);font-size:11px;cursor:default;text-transform:uppercase;letter-spacing:.04em;}
|
||
.fd-ctx-menu .ctx-label:hover{background:transparent;}
|
||
.fd-ctx-menu .ctx-empty{color:var(--text-dim);font-size:11px;cursor:default;}
|
||
.fd-ctx-menu .ctx-empty:hover{background:transparent;}
|
||
.fd-ctx-menu .ctx-caret{font-size:10px;color:var(--text-dim);}
|
||
.fd-ctx-menu .ctx-x{color:var(--text-dim);font-size:14px;line-height:1;padding:0 2px;}
|
||
.fd-ctx-menu .ctx-x:hover{color:var(--danger);}
|
||
.fd-ctx-menu .ctx-sub{padding:2px 0 4px;background:var(--bg-tertiary);border-radius:6px;margin:2px 6px;max-height:38vh;overflow-y:auto;}
|
||
.fd-ctx-menu .ctx-tag-color{width:10px;height:10px;border-radius:3px;display:inline-block;flex-shrink:0;}
|
||
.fd-ctx-menu .ctx-colors{display:grid;grid-template-columns:repeat(7,1fr);gap:4px;padding:2px 4px 6px;}
|
||
.fd-ctx-menu .ctx-swatch{width:16px;height:16px;border-radius:4px;cursor:pointer;border:2px solid transparent;}
|
||
.fd-ctx-menu .ctx-swatch.selected{border-color:var(--text-primary);}
|
||
.fd-ctx-menu .ctx-input{flex:1;min-width:0;font-size:12px;padding:3px 6px;background:var(--bg-primary);border:1px solid var(--border);border-radius:4px;color:var(--text-primary);outline:none;}
|
||
.fd-ctx-menu .ctx-input:focus{border-color:var(--accent);}
|
||
.fd-ctx-menu .ctx-btn{padding:3px 10px;font-size:12px;background:var(--accent);color:#fff;border:none;border-radius:4px;cursor:pointer;}
|
||
.fd-ctx-menu .ctx-icons{display:grid;grid-template-columns:repeat(7,1fr);gap:2px;padding:2px 4px 4px;}
|
||
.fd-ctx-menu .ctx-icon{width:26px;height:26px;display:flex;align-items:center;justify-content:center;font-size:15px;background:transparent;border:none;border-radius:4px;cursor:pointer;}
|
||
.fd-ctx-menu .ctx-icon:hover{background:var(--bg-hover);}
|
||
</style>
|
||
|
||
<div class="more-menu fd-ctx-menu" x-show="$store.fdCtx.open" x-cloak
|
||
@click.outside="$store.fdCtx.close()"
|
||
@keydown.escape.window="$store.fdCtx.close()"
|
||
x-transition
|
||
:style="{ top: $store.fdCtx.y + 'px', left: $store.fdCtx.x + 'px', maxHeight: $store.fdCtx.maxH ? $store.fdCtx.maxH + 'px' : 'calc(100vh - 16px)' }">
|
||
|
||
{# ── Open ── #}
|
||
<div class="menu-item" x-show="$store.fdCtx.has('open')" @click="$store.fdCtx.run('open')">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>
|
||
<span style="flex:1;">Open</span>
|
||
</div>
|
||
|
||
{# ── Open in new tab ── #}
|
||
<div class="menu-item" x-show="$store.fdCtx.has('openTab')" @click="$store.fdCtx.run('openTab')">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>
|
||
<span style="flex:1;">Open in new tab</span><span class="menu-shortcut">Ctrl+⇧+↩</span>
|
||
</div>
|
||
|
||
{# ── Open in side peek ── #}
|
||
<div class="menu-item" x-show="$store.fdCtx.has('peek')" @click="$store.fdCtx.run('peek')">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><line x1="15" y1="3" x2="15" y2="21"/></svg>
|
||
<span style="flex:1;">Open in side peek</span><span class="menu-shortcut">Alt+Click</span>
|
||
</div>
|
||
|
||
{# ── Open folder (workspace, dossiers) ── #}
|
||
<div class="menu-item" x-show="$store.fdCtx.has('folder')" @click="$store.fdCtx.run('folder')">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 19a2 2 0 01-2 2H4a2 2 0 01-2-2V5a2 2 0 012-2h5l2 3h9a2 2 0 012 2z"/></svg>
|
||
<span style="flex:1;">Open folder</span>
|
||
</div>
|
||
|
||
<div class="more-sep" x-show="$store.fdCtx.has('rename') || $store.fdCtx.has('setIcon') || $store.fdCtx.has('duplicate') || $store.fdCtx.has('link') || $store.fdCtx.has('move')"></div>
|
||
|
||
{# ── Rename ── #}
|
||
<div class="menu-item" x-show="$store.fdCtx.has('rename')" @click="$store.fdCtx.run('rename')">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/><path d="M18.5 2.5a2.12 2.12 0 013 3L12 15l-4 1 1-4z"/></svg>
|
||
<span style="flex:1;">Rename</span><span class="menu-shortcut">Ctrl+⇧+R</span>
|
||
</div>
|
||
|
||
{# ── Edit icon (sélecteur façon Notion) ── #}
|
||
<div class="menu-item" x-show="$store.fdCtx.has('setIcon')" @click.stop="$store.fdCtx.openIconPicker()">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="9"/><path d="M8 14s1.5 2 4 2 4-2 4-2"/><line x1="9" y1="9" x2="9.01" y2="9"/><line x1="15" y1="9" x2="15.01" y2="9"/></svg>
|
||
<span style="flex:1;">Edit icon</span>
|
||
</div>
|
||
|
||
{# ── Duplicate ── #}
|
||
<div class="menu-item" x-show="$store.fdCtx.has('duplicate')" @click="$store.fdCtx.run('duplicate')">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg>
|
||
<span style="flex:1;">Duplicate</span>
|
||
</div>
|
||
|
||
{# ── Copy link ── #}
|
||
<div class="menu-item" x-show="$store.fdCtx.has('link')" @click="$store.fdCtx.run('link')">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10 13a5 5 0 007.54.54l3-3a5 5 0 00-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 00-7.54-.54l-3 3a5 5 0 007.07 7.07l1.71-1.71"/></svg>
|
||
<span style="flex:1;">Copy link</span>
|
||
</div>
|
||
|
||
{# ── Download file (file pages) ── #}
|
||
<div class="menu-item" x-show="$store.fdCtx.has('download')" @click="$store.fdCtx.run('download')">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
|
||
<span style="flex:1;">Download</span>
|
||
</div>
|
||
|
||
{# ── Copy file content (textual file pages) ── #}
|
||
<div class="menu-item" x-show="$store.fdCtx.has('copyContent')" @click="$store.fdCtx.run('copyContent')">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg>
|
||
<span style="flex:1;">Copy content</span>
|
||
</div>
|
||
|
||
{# ── Move to ── #}
|
||
<div class="menu-item" x-show="$store.fdCtx.has('move')" @click="$store.fdCtx.run('move')">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 19a2 2 0 01-2 2H4a2 2 0 01-2-2V5a2 2 0 012-2h5l2 3h9a2 2 0 012 2z"/></svg>
|
||
<span style="flex:1;">Move to</span><span class="menu-shortcut">Ctrl+⇧+P</span>
|
||
</div>
|
||
|
||
{# ── Favorites ── #}
|
||
<div class="menu-item" x-show="$store.fdCtx.has('fav')" @click="$store.fdCtx.run('fav')">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>
|
||
<span style="flex:1;" x-text="$store.fdCtx.node && $store.fdCtx.node.favorited ? 'Remove from Favorites' : 'Add to Favorites'"></span>
|
||
</div>
|
||
|
||
{# ── Remove from Recents ── #}
|
||
<div class="menu-item" x-show="$store.fdCtx.has('recent')" @click="$store.fdCtx.run('recent')">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M17.94 17.94A10.07 10.07 0 0112 20c-7 0-11-8-11-8a18.45 18.45 0 015.06-5.94M9.9 4.24A9.12 9.12 0 0112 4c7 0 11 8 11 8a18.5 18.5 0 01-2.16 3.19m-6.72-1.07a3 3 0 11-4.24-4.24"/><line x1="1" y1="1" x2="23" y2="23"/></svg>
|
||
<span style="flex:1;">Remove from Recents</span>
|
||
</div>
|
||
|
||
{# ── Tags (workspace) ── #}
|
||
<div class="more-sep" x-show="$store.fdCtx.has('tagRemove') || $store.fdCtx.has('tagAdd')"></div>
|
||
<div x-show="$store.fdCtx.has('tagRemove') || $store.fdCtx.has('tagAdd')">
|
||
<div class="menu-item ctx-label"><span style="flex:1;">Tags</span></div>
|
||
<template x-for="t in ($store.fdCtx.node && $store.fdCtx.node.tags) || []" :key="'ct'+t.id">
|
||
<div class="menu-item" @click.stop="$store.fdCtx.removeTag(t.id)">
|
||
<span style="display:flex;align-items:center;gap:8px;flex:1;overflow:hidden;"><span class="ctx-tag-color" :style="{ background: t.color }"></span><span x-text="t.name" style="overflow:hidden;text-overflow:ellipsis;"></span></span>
|
||
<span class="ctx-x" title="Remove tag">×</span>
|
||
</div>
|
||
</template>
|
||
<div class="menu-item ctx-empty" x-show="!($store.fdCtx.node && ($store.fdCtx.node.tags||[]).length)">No tags</div>
|
||
<div class="menu-item" x-show="$store.fdCtx.avail().length" @click.stop="$store.fdCtx.tagExistingOpen = !$store.fdCtx.tagExistingOpen">
|
||
<span style="flex:1;">Add existing tag</span><span class="ctx-caret" x-text="$store.fdCtx.tagExistingOpen ? '▾' : '▸'"></span>
|
||
</div>
|
||
<div x-show="$store.fdCtx.tagExistingOpen" class="ctx-sub">
|
||
<template x-for="t in $store.fdCtx.avail()" :key="'ca'+t.id">
|
||
<div class="menu-item" @click.stop="$store.fdCtx.addExistingTag(t)">
|
||
<span style="display:flex;align-items:center;gap:8px;"><span class="ctx-tag-color" :style="{ background: t.color }"></span><span x-text="t.name"></span></span>
|
||
</div>
|
||
</template>
|
||
</div>
|
||
<div class="menu-item" @click.stop="$store.fdCtx.tagAdding = !$store.fdCtx.tagAdding">
|
||
<span style="flex:1;">+ New tag</span><span class="ctx-caret" x-text="$store.fdCtx.tagAdding ? '▾' : '▸'"></span>
|
||
</div>
|
||
<div x-show="$store.fdCtx.tagAdding" class="ctx-sub">
|
||
<div class="ctx-colors">
|
||
<template x-for="c in $store.fdCtx.tagColors" :key="'cc'+c">
|
||
<span class="ctx-swatch" :class="{ selected: $store.fdCtx.newTagColor === c }" :style="{ background: c }" @click.stop="$store.fdCtx.newTagColor = c"></span>
|
||
</template>
|
||
</div>
|
||
<div style="display:flex;gap:4px;padding:0 4px;">
|
||
<input class="ctx-input" x-ref="ctxTagInput" placeholder="Tag name…" @click.stop
|
||
@keydown.enter.prevent="$store.fdCtx.addNewTag($event.target.value, $store.fdCtx.newTagColor); $event.target.value = ''"
|
||
@keydown.escape.stop="$store.fdCtx.tagAdding = false">
|
||
<button type="button" class="ctx-btn" @click.stop="$store.fdCtx.addNewTag($refs.ctxTagInput.value, $store.fdCtx.newTagColor); $refs.ctxTagInput.value = ''">Add</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{# ── Delete (danger) ── #}
|
||
<div class="more-sep"></div>
|
||
<div class="menu-item menu-danger" @click="$store.fdCtx.run('delete')">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6"/><path d="M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2"/><line x1="10" y1="11" x2="10" y2="17"/><line x1="14" y1="11" x2="14" y2="17"/></svg>
|
||
<span style="flex:1;">Move to Trash</span><span class="menu-shortcut">Del</span>
|
||
</div>
|
||
</div>
|