feat: step 10 done (claimed)
This commit is contained in:
@@ -64,6 +64,35 @@
|
||||
"translationValidation.revalidate": "Erneut validieren",
|
||||
"translationValidation.fix": "Probleme beheben",
|
||||
"translationValidation.toast.fixSuccess": "%{dbRows} DB-Zeilen und %{files} Dateien gelöscht, %{flushed} Übersetzungen auf Datenträger geschrieben",
|
||||
"menuEditor.tabTitle": "Blog-Menü",
|
||||
"menuEditor.title": "Blog-Menü-Editor",
|
||||
"menuEditor.description": "Verwalte die zentrale Blog-Navigationsstruktur und speichere sie in meta/menu.opml.",
|
||||
"menuEditor.save": "Menü speichern",
|
||||
"menuEditor.saved": "Blog-Menü gespeichert",
|
||||
"menuEditor.addEntry": "Eintrag hinzufügen",
|
||||
"menuEditor.addCategoryArchive": "Kategorie-Archiv hinzufügen",
|
||||
"menuEditor.addCategoryArchiveShort": "K+",
|
||||
"menuEditor.addSubmenu": "Untermenü hinzufügen",
|
||||
"menuEditor.moveUp": "Nach oben",
|
||||
"menuEditor.moveDown": "Nach unten",
|
||||
"menuEditor.indent": "Einrücken",
|
||||
"menuEditor.unindent": "Ausrücken",
|
||||
"menuEditor.delete": "Löschen",
|
||||
"menuEditor.newEntryPlaceholder": "Seitentitel oder Untermenü-Bezeichnung eingeben",
|
||||
"menuEditor.newCategoryPlaceholder": "Kategorienamen eingeben",
|
||||
"menuEditor.createHint": "Wähle unten eine Seite aus oder drücke Enter, um ein Untermenü zu erstellen",
|
||||
"menuEditor.dragHandle": "Menüeintrag ziehen",
|
||||
"menuEditor.empty": "Noch keine Menüeinträge. Füge eine Seite oder ein Untermenü hinzu, um zu beginnen.",
|
||||
"menuEditor.newPage": "Neue Seite",
|
||||
"menuEditor.newSubmenu": "Neues Untermenü",
|
||||
"menuEditor.pagePicker.title": "Seite auswählen",
|
||||
"menuEditor.pagePicker.empty": "Keine passenden Seiten gefunden.",
|
||||
"menuEditor.categoryPicker.hint": "Wähle eine vorhandene Kategorie oder drücke Enter, um einen neuen Archiv-Eintrag zu erstellen",
|
||||
"menuEditor.categoryPicker.empty": "Keine passenden Kategorien gefunden.",
|
||||
"menuEditor.type.page": "Seite",
|
||||
"menuEditor.type.home": "Startseite",
|
||||
"menuEditor.type.submenu": "Untermenü",
|
||||
"menuEditor.type.categoryArchive": "Kategorie-Archiv",
|
||||
"chat.newChat": "Neuer Chat",
|
||||
"chat.setupTitle": "KI-Chat-Einrichtung",
|
||||
"chat.apiKeyRequiredTitle": "API-Schlüssel erforderlich",
|
||||
|
||||
@@ -64,6 +64,35 @@
|
||||
"translationValidation.revalidate": "Revalidate",
|
||||
"translationValidation.fix": "Fix Issues",
|
||||
"translationValidation.toast.fixSuccess": "Deleted %{dbRows} DB rows and %{files} files, flushed %{flushed} translations to disk",
|
||||
"menuEditor.tabTitle": "Blog Menu",
|
||||
"menuEditor.title": "Blog Menu Editor",
|
||||
"menuEditor.description": "Manage the central blog navigation outline and save it to meta/menu.opml.",
|
||||
"menuEditor.save": "Save Menu",
|
||||
"menuEditor.saved": "Blog menu saved",
|
||||
"menuEditor.addEntry": "Add Entry",
|
||||
"menuEditor.addCategoryArchive": "Add Category Archive",
|
||||
"menuEditor.addCategoryArchiveShort": "C+",
|
||||
"menuEditor.addSubmenu": "Add Submenu",
|
||||
"menuEditor.moveUp": "Move Up",
|
||||
"menuEditor.moveDown": "Move Down",
|
||||
"menuEditor.indent": "Indent",
|
||||
"menuEditor.unindent": "Unindent",
|
||||
"menuEditor.delete": "Delete",
|
||||
"menuEditor.newEntryPlaceholder": "Type a page title or submenu label",
|
||||
"menuEditor.newCategoryPlaceholder": "Type a category name",
|
||||
"menuEditor.createHint": "Select a page below or press Enter to create a submenu",
|
||||
"menuEditor.dragHandle": "Drag menu item",
|
||||
"menuEditor.empty": "No menu entries yet. Add a page or submenu to start.",
|
||||
"menuEditor.newPage": "New Page",
|
||||
"menuEditor.newSubmenu": "New Submenu",
|
||||
"menuEditor.pagePicker.title": "Select Page",
|
||||
"menuEditor.pagePicker.empty": "No matching pages found.",
|
||||
"menuEditor.categoryPicker.hint": "Select an existing category or press Enter to create a new archive entry",
|
||||
"menuEditor.categoryPicker.empty": "No matching categories found.",
|
||||
"menuEditor.type.page": "Page",
|
||||
"menuEditor.type.home": "Home",
|
||||
"menuEditor.type.submenu": "Submenu",
|
||||
"menuEditor.type.categoryArchive": "Category Archive",
|
||||
"chat.newChat": "New Chat",
|
||||
"chat.setupTitle": "AI Chat Setup",
|
||||
"chat.apiKeyRequiredTitle": "API Key Required",
|
||||
|
||||
@@ -64,6 +64,35 @@
|
||||
"translationValidation.revalidate": "Revalidar",
|
||||
"translationValidation.fix": "Corregir problemas",
|
||||
"translationValidation.toast.fixSuccess": "%{dbRows} filas de BD y %{files} archivos eliminados, %{flushed} traducciones escritas a disco",
|
||||
"menuEditor.tabTitle": "Menú del blog",
|
||||
"menuEditor.title": "Editor del menú del blog",
|
||||
"menuEditor.description": "Gestiona la estructura central de navegación del blog y guárdala en meta/menu.opml.",
|
||||
"menuEditor.save": "Guardar menú",
|
||||
"menuEditor.saved": "Menú del blog guardado",
|
||||
"menuEditor.addEntry": "Agregar entrada",
|
||||
"menuEditor.addCategoryArchive": "Agregar archivo de categoría",
|
||||
"menuEditor.addCategoryArchiveShort": "C+",
|
||||
"menuEditor.addSubmenu": "Agregar submenú",
|
||||
"menuEditor.moveUp": "Subir",
|
||||
"menuEditor.moveDown": "Bajar",
|
||||
"menuEditor.indent": "Indentar",
|
||||
"menuEditor.unindent": "Desindentar",
|
||||
"menuEditor.delete": "Eliminar",
|
||||
"menuEditor.newEntryPlaceholder": "Escribe un título de página o una etiqueta de submenú",
|
||||
"menuEditor.newCategoryPlaceholder": "Escribe un nombre de categoría",
|
||||
"menuEditor.createHint": "Selecciona una página abajo o pulsa Enter para crear un submenú",
|
||||
"menuEditor.dragHandle": "Arrastrar elemento del menú",
|
||||
"menuEditor.empty": "Todavía no hay entradas de menú. Agrega una página o un submenú para empezar.",
|
||||
"menuEditor.newPage": "Nueva página",
|
||||
"menuEditor.newSubmenu": "Nuevo submenú",
|
||||
"menuEditor.pagePicker.title": "Seleccionar página",
|
||||
"menuEditor.pagePicker.empty": "No se encontraron páginas coincidentes.",
|
||||
"menuEditor.categoryPicker.hint": "Selecciona una categoría existente o pulsa Enter para crear una nueva entrada de archivo",
|
||||
"menuEditor.categoryPicker.empty": "No se encontraron categorías coincidentes.",
|
||||
"menuEditor.type.page": "Página",
|
||||
"menuEditor.type.home": "Inicio",
|
||||
"menuEditor.type.submenu": "Submenú",
|
||||
"menuEditor.type.categoryArchive": "Archivo de categoría",
|
||||
"chat.newChat": "Nuevo chat",
|
||||
"chat.setupTitle": "Configuración de chat IA",
|
||||
"chat.apiKeyRequiredTitle": "Clave API requerida",
|
||||
|
||||
@@ -64,6 +64,35 @@
|
||||
"translationValidation.revalidate": "Revalider",
|
||||
"translationValidation.fix": "Corriger les problèmes",
|
||||
"translationValidation.toast.fixSuccess": "%{dbRows} lignes DB et %{files} fichiers supprimés, %{flushed} traductions écrites sur disque",
|
||||
"menuEditor.tabTitle": "Menu du blog",
|
||||
"menuEditor.title": "Éditeur du menu du blog",
|
||||
"menuEditor.description": "Gérez la structure centrale de navigation du blog et enregistrez-la dans meta/menu.opml.",
|
||||
"menuEditor.save": "Enregistrer le menu",
|
||||
"menuEditor.saved": "Menu du blog enregistré",
|
||||
"menuEditor.addEntry": "Ajouter une entrée",
|
||||
"menuEditor.addCategoryArchive": "Ajouter une archive de catégorie",
|
||||
"menuEditor.addCategoryArchiveShort": "C+",
|
||||
"menuEditor.addSubmenu": "Ajouter un sous-menu",
|
||||
"menuEditor.moveUp": "Monter",
|
||||
"menuEditor.moveDown": "Descendre",
|
||||
"menuEditor.indent": "Indenter",
|
||||
"menuEditor.unindent": "Désindenter",
|
||||
"menuEditor.delete": "Supprimer",
|
||||
"menuEditor.newEntryPlaceholder": "Saisissez un titre de page ou un libellé de sous-menu",
|
||||
"menuEditor.newCategoryPlaceholder": "Saisissez un nom de catégorie",
|
||||
"menuEditor.createHint": "Sélectionnez une page ci-dessous ou appuyez sur Entrée pour créer un sous-menu",
|
||||
"menuEditor.dragHandle": "Faire glisser l’entrée du menu",
|
||||
"menuEditor.empty": "Aucune entrée de menu pour le moment. Ajoutez une page ou un sous-menu pour commencer.",
|
||||
"menuEditor.newPage": "Nouvelle page",
|
||||
"menuEditor.newSubmenu": "Nouveau sous-menu",
|
||||
"menuEditor.pagePicker.title": "Sélectionner une page",
|
||||
"menuEditor.pagePicker.empty": "Aucune page correspondante trouvée.",
|
||||
"menuEditor.categoryPicker.hint": "Sélectionnez une catégorie existante ou appuyez sur Entrée pour créer une nouvelle entrée d’archive",
|
||||
"menuEditor.categoryPicker.empty": "Aucune catégorie correspondante trouvée.",
|
||||
"menuEditor.type.page": "Page",
|
||||
"menuEditor.type.home": "Accueil",
|
||||
"menuEditor.type.submenu": "Sous-menu",
|
||||
"menuEditor.type.categoryArchive": "Archive de catégorie",
|
||||
"chat.newChat": "Nouveau chat",
|
||||
"chat.welcomeTitle": "Bienvenue dans l’assistant IA",
|
||||
"chat.welcomeDescription": "Je peux vous aider à gérer votre blog avec des visualisations riches. Essayez par exemple :",
|
||||
|
||||
@@ -64,6 +64,35 @@
|
||||
"translationValidation.revalidate": "Rivalidare",
|
||||
"translationValidation.fix": "Correggi problemi",
|
||||
"translationValidation.toast.fixSuccess": "%{dbRows} righe DB e %{files} file eliminati, %{flushed} traduzioni scritte su disco",
|
||||
"menuEditor.tabTitle": "Menu del blog",
|
||||
"menuEditor.title": "Editor del menu del blog",
|
||||
"menuEditor.description": "Gestisci la struttura centrale di navigazione del blog e salvala in meta/menu.opml.",
|
||||
"menuEditor.save": "Salva menu",
|
||||
"menuEditor.saved": "Menu del blog salvato",
|
||||
"menuEditor.addEntry": "Aggiungi voce",
|
||||
"menuEditor.addCategoryArchive": "Aggiungi archivio categoria",
|
||||
"menuEditor.addCategoryArchiveShort": "C+",
|
||||
"menuEditor.addSubmenu": "Aggiungi sottomenu",
|
||||
"menuEditor.moveUp": "Sposta su",
|
||||
"menuEditor.moveDown": "Sposta giù",
|
||||
"menuEditor.indent": "Rientra",
|
||||
"menuEditor.unindent": "Riduci rientro",
|
||||
"menuEditor.delete": "Elimina",
|
||||
"menuEditor.newEntryPlaceholder": "Digita un titolo pagina o un'etichetta del sottomenu",
|
||||
"menuEditor.newCategoryPlaceholder": "Digita un nome categoria",
|
||||
"menuEditor.createHint": "Seleziona una pagina qui sotto o premi Invio per creare un sottomenu",
|
||||
"menuEditor.dragHandle": "Trascina voce di menu",
|
||||
"menuEditor.empty": "Nessuna voce di menu ancora. Aggiungi una pagina o un sottomenu per iniziare.",
|
||||
"menuEditor.newPage": "Nuova pagina",
|
||||
"menuEditor.newSubmenu": "Nuovo sottomenu",
|
||||
"menuEditor.pagePicker.title": "Seleziona pagina",
|
||||
"menuEditor.pagePicker.empty": "Nessuna pagina corrispondente trovata.",
|
||||
"menuEditor.categoryPicker.hint": "Seleziona una categoria esistente o premi Invio per creare una nuova voce di archivio",
|
||||
"menuEditor.categoryPicker.empty": "Nessuna categoria corrispondente trovata.",
|
||||
"menuEditor.type.page": "Pagina",
|
||||
"menuEditor.type.home": "Home",
|
||||
"menuEditor.type.submenu": "Sottomenu",
|
||||
"menuEditor.type.categoryArchive": "Archivio categoria",
|
||||
"chat.newChat": "Nuova chat",
|
||||
"chat.setupTitle": "Configurazione chat IA",
|
||||
"chat.apiKeyRequiredTitle": "Chiave API richiesta",
|
||||
|
||||
289
priv/ui/app.css
289
priv/ui/app.css
@@ -2550,6 +2550,295 @@ button svg * {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
.menu-editor-view {
|
||||
padding: 1rem;
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
overflow: hidden;
|
||||
background: var(--vscode-editor-background);
|
||||
}
|
||||
|
||||
.menu-editor-header {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.menu-editor-header h2 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.menu-editor-header p {
|
||||
margin: 0.25rem 0 0;
|
||||
color: var(--vscode-descriptionForeground);
|
||||
}
|
||||
|
||||
.menu-editor-main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.menu-editor-tree-wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
border: 1px solid var(--vscode-panel-border);
|
||||
border-radius: 6px;
|
||||
background: var(--vscode-editor-background);
|
||||
padding: 0.5rem;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.menu-editor-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.2rem;
|
||||
margin-bottom: 0.5rem;
|
||||
padding-bottom: 0.4rem;
|
||||
border-bottom: 1px solid var(--vscode-panel-border);
|
||||
}
|
||||
|
||||
.menu-editor-tool {
|
||||
width: 1.8rem;
|
||||
height: 1.8rem;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
background: transparent;
|
||||
color: var(--vscode-foreground);
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.menu-editor-tool:hover:not(:disabled) {
|
||||
background: var(--vscode-toolbar-hoverBackground);
|
||||
border-color: var(--vscode-panel-border);
|
||||
}
|
||||
|
||||
.menu-editor-tool:disabled {
|
||||
opacity: 0.45;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.menu-editor-tree-shell {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.menu-editor-tree-level {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.menu-editor-tree-item {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.menu-editor-row {
|
||||
--menu-editor-indent: calc(var(--menu-editor-depth) * 1rem);
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 0.5rem;
|
||||
padding: 0.3rem 0.45rem 0.3rem calc(0.4rem + var(--menu-editor-indent));
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.menu-editor-row.is-selected {
|
||||
background: var(--vscode-list-activeSelectionBackground);
|
||||
color: var(--vscode-list-activeSelectionForeground);
|
||||
}
|
||||
|
||||
.menu-editor-row.is-dragging {
|
||||
opacity: 0.45;
|
||||
}
|
||||
|
||||
.menu-editor-row.is-drop-before::before,
|
||||
.menu-editor-row.is-drop-after::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: calc(0.4rem + var(--menu-editor-indent));
|
||||
right: 0.45rem;
|
||||
height: 2px;
|
||||
background: var(--vscode-focusBorder);
|
||||
}
|
||||
|
||||
.menu-editor-row.is-drop-before::before {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.menu-editor-row.is-drop-after::after {
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.menu-editor-row.is-drop-inside {
|
||||
box-shadow: inset 0 0 0 1px var(--vscode-focusBorder);
|
||||
background: var(--vscode-list-hoverBackground);
|
||||
}
|
||||
|
||||
.menu-editor-row-handle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 1rem;
|
||||
min-width: 1rem;
|
||||
color: var(--vscode-descriptionForeground);
|
||||
cursor: grab;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.menu-editor-row-handle:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.menu-editor-row-kind {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 1rem;
|
||||
min-width: 1rem;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.menu-editor-row-title {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.menu-editor-row-title.is-editing {
|
||||
white-space: normal;
|
||||
overflow: visible;
|
||||
text-overflow: clip;
|
||||
}
|
||||
|
||||
.menu-editor-entry-form {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.menu-editor-inline-input {
|
||||
width: 100%;
|
||||
border: 1px solid var(--vscode-focusBorder);
|
||||
border-radius: 4px;
|
||||
background: var(--vscode-input-background);
|
||||
color: var(--vscode-input-foreground);
|
||||
padding: 0.25rem 0.45rem;
|
||||
min-height: 1.8rem;
|
||||
}
|
||||
|
||||
.menu-editor-inline-search {
|
||||
margin-top: 0.5rem;
|
||||
border-top: 1px solid var(--vscode-panel-border);
|
||||
padding-top: 0.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.4rem;
|
||||
max-height: 18rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.menu-editor-inline-search-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.menu-editor-inline-search-head strong {
|
||||
display: block;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.menu-editor-inline-search-head span {
|
||||
color: var(--vscode-descriptionForeground);
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.menu-editor-inline-actions {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.menu-editor-inline-action {
|
||||
border: 1px solid var(--vscode-button-border, transparent);
|
||||
border-radius: 4px;
|
||||
background: var(--vscode-button-secondaryBackground);
|
||||
color: var(--vscode-button-secondaryForeground);
|
||||
padding: 0.2rem 0.5rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.menu-editor-inline-action:hover {
|
||||
background: var(--vscode-button-secondaryHoverBackground);
|
||||
}
|
||||
|
||||
.menu-editor-picker-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.35rem;
|
||||
max-height: 16rem;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.menu-editor-picker-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
border: 1px solid var(--vscode-panel-border);
|
||||
border-radius: 4px;
|
||||
background: var(--vscode-input-background);
|
||||
color: var(--vscode-input-foreground);
|
||||
padding: 0.45rem 0.55rem;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.menu-editor-picker-item:hover {
|
||||
border-color: var(--vscode-focusBorder);
|
||||
background: var(--vscode-list-hoverBackground);
|
||||
}
|
||||
|
||||
.menu-editor-picker-item small,
|
||||
.menu-editor-picker-state {
|
||||
color: var(--vscode-descriptionForeground);
|
||||
}
|
||||
|
||||
.menu-editor-empty {
|
||||
color: var(--vscode-descriptionForeground);
|
||||
padding: 0.5rem 0.25rem;
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.menu-editor-inline-search-head {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.menu-editor-inline-actions {
|
||||
width: 100%;
|
||||
justify-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
[data-testid="media-editor"] {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
|
||||
135
priv/ui/live.js
135
priv/ui/live.js
@@ -790,6 +790,141 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
}
|
||||
},
|
||||
|
||||
MenuEditorTree: {
|
||||
mounted() {
|
||||
this.dragItemId = null;
|
||||
this.dragSourceEl = null;
|
||||
this.dropTargetEl = null;
|
||||
this.dropPosition = null;
|
||||
|
||||
this.clearDropTarget = () => {
|
||||
if (this.dropTargetEl) {
|
||||
this.dropTargetEl.classList.remove("is-drop-before", "is-drop-after", "is-drop-inside");
|
||||
}
|
||||
|
||||
this.dropTargetEl = null;
|
||||
this.dropPosition = null;
|
||||
};
|
||||
|
||||
this.setDropTarget = (row, position) => {
|
||||
if (this.dropTargetEl === row && this.dropPosition === position) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.clearDropTarget();
|
||||
this.dropTargetEl = row;
|
||||
this.dropPosition = position;
|
||||
row.classList.add(`is-drop-${position}`);
|
||||
};
|
||||
|
||||
this.handleDragStart = (event) => {
|
||||
const handle = event.target.closest("[data-menu-drag-handle='true']");
|
||||
const row = event.target.closest("[data-menu-item-id]");
|
||||
|
||||
if (!handle || !row || !this.el.contains(row)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dragItemId = row.dataset.menuItemId || null;
|
||||
this.dragSourceEl = row;
|
||||
row.classList.add("is-dragging");
|
||||
|
||||
if (event.dataTransfer) {
|
||||
event.dataTransfer.effectAllowed = "move";
|
||||
event.dataTransfer.setData("text/plain", this.dragItemId || "");
|
||||
}
|
||||
};
|
||||
|
||||
this.handleDragOver = (event) => {
|
||||
const row = event.target.closest("[data-menu-item-id]");
|
||||
|
||||
if (!this.dragItemId || !row || !this.el.contains(row)) {
|
||||
this.clearDropTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
const targetItemId = row.dataset.menuItemId || "";
|
||||
|
||||
if (!targetItemId || targetItemId === this.dragItemId) {
|
||||
this.clearDropTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
const rect = row.getBoundingClientRect();
|
||||
const offsetY = event.clientY - rect.top;
|
||||
const allowInside = row.dataset.menuCanDropInside === "true";
|
||||
const insideBandTop = rect.height * 0.3;
|
||||
const insideBandBottom = rect.height * 0.7;
|
||||
|
||||
const position =
|
||||
allowInside && offsetY >= insideBandTop && offsetY <= insideBandBottom
|
||||
? "inside"
|
||||
: offsetY < rect.height / 2
|
||||
? "before"
|
||||
: "after";
|
||||
|
||||
this.setDropTarget(row, position);
|
||||
|
||||
if (event.dataTransfer) {
|
||||
event.dataTransfer.dropEffect = "move";
|
||||
}
|
||||
};
|
||||
|
||||
this.handleDrop = (event) => {
|
||||
const row = event.target.closest("[data-menu-item-id]");
|
||||
|
||||
if (!this.dragItemId || !row || !this.el.contains(row) || !this.dropPosition) {
|
||||
this.clearDropTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
this.pushEvent("menu_editor_drop_item", {
|
||||
drag_item_id: this.dragItemId,
|
||||
target_item_id: row.dataset.menuItemId,
|
||||
position: this.dropPosition
|
||||
});
|
||||
|
||||
this.clearDropTarget();
|
||||
};
|
||||
|
||||
this.handleDragLeave = (event) => {
|
||||
const related = event.relatedTarget;
|
||||
|
||||
if (this.dropTargetEl && (!related || !this.dropTargetEl.contains(related))) {
|
||||
this.clearDropTarget();
|
||||
}
|
||||
};
|
||||
|
||||
this.handleDragEnd = () => {
|
||||
if (this.dragSourceEl) {
|
||||
this.dragSourceEl.classList.remove("is-dragging");
|
||||
}
|
||||
|
||||
this.dragItemId = null;
|
||||
this.dragSourceEl = null;
|
||||
this.clearDropTarget();
|
||||
};
|
||||
|
||||
this.el.addEventListener("dragstart", this.handleDragStart);
|
||||
this.el.addEventListener("dragover", this.handleDragOver);
|
||||
this.el.addEventListener("drop", this.handleDrop);
|
||||
this.el.addEventListener("dragleave", this.handleDragLeave);
|
||||
this.el.addEventListener("dragend", this.handleDragEnd);
|
||||
},
|
||||
|
||||
destroyed() {
|
||||
this.el.removeEventListener("dragstart", this.handleDragStart);
|
||||
this.el.removeEventListener("dragover", this.handleDragOver);
|
||||
this.el.removeEventListener("drop", this.handleDrop);
|
||||
this.el.removeEventListener("dragleave", this.handleDragLeave);
|
||||
this.el.removeEventListener("dragend", this.handleDragEnd);
|
||||
}
|
||||
},
|
||||
|
||||
MonacoEditor: {
|
||||
mounted() {
|
||||
this.textarea = document.getElementById(this.el.dataset.monacoInputId) || this.el.querySelector("textarea");
|
||||
|
||||
Reference in New Issue
Block a user