diff --git a/locales/de.json b/locales/de.json index 77ac8bb6..a67ecbb3 100644 --- a/locales/de.json +++ b/locales/de.json @@ -860,6 +860,7 @@ "actions": { "sendCheckpoint": "Send to ComfyUI", "sendRecipe": "Send to ComfyUI", + "copyRecipeSyntax": "Rezept-Syntax kopieren", "deleteRecipeWithShortcut": "Rezept löschen (Del)" }, "navigation": { diff --git a/locales/en.json b/locales/en.json index 60a39c23..1b9f5cf5 100644 --- a/locales/en.json +++ b/locales/en.json @@ -860,6 +860,7 @@ "actions": { "sendCheckpoint": "Send to ComfyUI", "sendRecipe": "Send to ComfyUI", + "copyRecipeSyntax": "Copy Recipe Syntax", "deleteRecipeWithShortcut": "Delete recipe (Del)" }, "navigation": { diff --git a/locales/es.json b/locales/es.json index b7e8e83f..efc5f668 100644 --- a/locales/es.json +++ b/locales/es.json @@ -860,6 +860,7 @@ "actions": { "sendCheckpoint": "Enviar a ComfyUI", "sendRecipe": "Enviar a ComfyUI", + "copyRecipeSyntax": "Copiar sintaxis de receta", "deleteRecipeWithShortcut": "Eliminar receta (Del)" }, "navigation": { diff --git a/locales/fr.json b/locales/fr.json index 812a4567..26de9099 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -860,6 +860,7 @@ "actions": { "sendCheckpoint": "Envoyer vers ComfyUI", "sendRecipe": "Envoyer vers ComfyUI", + "copyRecipeSyntax": "Copier la syntaxe de la recipe", "deleteRecipeWithShortcut": "Supprimer la Recipe (Del)" }, "navigation": { diff --git a/locales/he.json b/locales/he.json index 2fe44542..51fc96a6 100644 --- a/locales/he.json +++ b/locales/he.json @@ -860,6 +860,7 @@ "actions": { "sendCheckpoint": "שלח ל-ComfyUI", "sendRecipe": "שלח ל-ComfyUI", + "copyRecipeSyntax": "העתק תחביר מתכון", "deleteRecipeWithShortcut": "מחק מתכון (Del)" }, "navigation": { diff --git a/locales/ja.json b/locales/ja.json index 7c05edb8..04df3206 100644 --- a/locales/ja.json +++ b/locales/ja.json @@ -860,6 +860,7 @@ "actions": { "sendCheckpoint": "ComfyUIへ送信", "sendRecipe": "ComfyUIへ送信", + "copyRecipeSyntax": "レシピ構文をコピー", "deleteRecipeWithShortcut": "レシピを削除(Del)" }, "navigation": { diff --git a/locales/ko.json b/locales/ko.json index 44f7d71c..1b83fc85 100644 --- a/locales/ko.json +++ b/locales/ko.json @@ -860,6 +860,7 @@ "actions": { "sendCheckpoint": "ComfyUI로 보내기", "sendRecipe": "ComfyUI로 보내기", + "copyRecipeSyntax": "레시피 문법 복사", "deleteRecipeWithShortcut": "레시피 삭제(Del)" }, "navigation": { diff --git a/locales/ru.json b/locales/ru.json index 4f33ba2c..d6c13994 100644 --- a/locales/ru.json +++ b/locales/ru.json @@ -860,6 +860,7 @@ "actions": { "sendCheckpoint": "Отправить в ComfyUI", "sendRecipe": "Отправить в ComfyUI", + "copyRecipeSyntax": "Копировать синтаксис рецепта", "deleteRecipeWithShortcut": "Удалить рецепт (Del)" }, "navigation": { diff --git a/locales/zh-CN.json b/locales/zh-CN.json index db96a3a3..867afc3b 100644 --- a/locales/zh-CN.json +++ b/locales/zh-CN.json @@ -860,6 +860,7 @@ "actions": { "sendCheckpoint": "发送到 ComfyUI", "sendRecipe": "发送到 ComfyUI", + "copyRecipeSyntax": "复制配方语法", "deleteRecipeWithShortcut": "删除配方(Del)" }, "navigation": { diff --git a/locales/zh-TW.json b/locales/zh-TW.json index 732e3f74..153a827a 100644 --- a/locales/zh-TW.json +++ b/locales/zh-TW.json @@ -860,6 +860,7 @@ "actions": { "sendCheckpoint": "傳送到 ComfyUI", "sendRecipe": "傳送到 ComfyUI", + "copyRecipeSyntax": "複製配方語法", "deleteRecipeWithShortcut": "刪除配方(Del)" }, "navigation": { diff --git a/static/css/components/recipe-modal.css b/static/css/components/recipe-modal.css index c9f8c343..2212d045 100644 --- a/static/css/components/recipe-modal.css +++ b/static/css/components/recipe-modal.css @@ -190,6 +190,44 @@ justify-content: center; } +/* Icon-only companion to the Send button: same pill style as its neighbors, + just without the text label. */ +.modal-copy-btn { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 6px 10px; + background: var(--surface-subtle); + border: 1px solid rgba(0, 0, 0, 0.1); + border-radius: var(--border-radius-sm); + color: var(--text-color); + cursor: pointer; + font-size: 0.9em; + transition: var(--transition-base); +} + +[data-theme="dark"] .modal-copy-btn { + background: var(--surface-subtle); + border: 1px solid var(--lora-border); +} + +.modal-copy-btn:hover { + background: oklch(var(--lora-accent-l) var(--lora-accent-c) var(--lora-accent-h) / 0.1); + border-color: var(--lora-accent); + transform: translateY(-1px); +} + +.modal-copy-btn:active { + transform: translateY(0); +} + +.modal-copy-btn i { + font-size: 14px; + display: flex; + align-items: center; + justify-content: center; +} + @media (max-height: 860px) { .recipe-header-actions { padding-bottom: 4px; diff --git a/static/js/components/RecipeModal.js b/static/js/components/RecipeModal.js index b6e198e3..352e116a 100644 --- a/static/js/components/RecipeModal.js +++ b/static/js/components/RecipeModal.js @@ -1383,6 +1383,15 @@ class RecipeModal { }); } + // Copy recipe syntax button (header actions) + const copyRecipeSyntaxBtn = document.getElementById('copyRecipeSyntaxBtn'); + if (copyRecipeSyntaxBtn) { + copyRecipeSyntaxBtn.addEventListener('click', () => { + // Use backend API to get recipe syntax + this.fetchAndCopyRecipeSyntax(); + }); + } + // Send prompt to workflow buttons const sendPromptBtn = document.getElementById('sendPromptBtn'); const sendNegativePromptBtn = document.getElementById('sendNegativePromptBtn'); @@ -1466,6 +1475,35 @@ class RecipeModal { copyToClipboard(text, successMessage); } + // Fetch recipe syntax from backend and copy to clipboard + async fetchAndCopyRecipeSyntax() { + if (!this.recipeId) { + showToast('toast.recipes.noRecipeId', {}, 'error'); + return; + } + + try { + // Fetch recipe syntax from backend + const response = await fetch(`/api/lm/recipe/${this.recipeId}/syntax`); + + if (!response.ok) { + throw new Error(`Failed to get recipe syntax: ${response.statusText}`); + } + + const data = await response.json(); + + if (data.success && data.syntax) { + // Use the centralized copyToClipboard utility function + await copyToClipboard(data.syntax, 'Recipe syntax copied to clipboard'); + } else { + throw new Error(data.error || 'No syntax returned from server'); + } + } catch (error) { + console.error('Error fetching recipe syntax:', error); + showToast('toast.recipes.copyFailed', { message: error.message }, 'error'); + } + } + // Send recipe to ComfyUI workflow async sendRecipeToWorkflow() { if (!this.recipeId) { diff --git a/templates/components/recipe_modal.html b/templates/components/recipe_modal.html index 6949717b..8ab7ec10 100644 --- a/templates/components/recipe_modal.html +++ b/templates/components/recipe_modal.html @@ -14,11 +14,14 @@ - +