feat(recipe-studio): overhaul recipe detail to modern studio layout with plain language and zero-overhead performance
This commit is contained in:
+27
-27
@@ -500,10 +500,10 @@ export const i18n = {
|
||||
recipeOpenCanvas: '新画布打开',
|
||||
recipeOpenError: '无法在新画布中打开此配方。',
|
||||
recipeScope: '配方类型',
|
||||
recipeScopePartial: '局部配方',
|
||||
recipeScopeComplete: '整体配方',
|
||||
recipeScopePartialSaveHint: '检测到未闭合的必需连接或缺少输出节点,将保存为局部配方;使用时默认追加到当前画布。',
|
||||
recipeScopeCompleteSaveHint: '检测到可独立运行的闭合工作流,将保存为整体配方;使用时会在新画布中打开。',
|
||||
recipeScopePartial: '功能模块',
|
||||
recipeScopeComplete: '完整工作流',
|
||||
recipeScopePartialSaveHint: '检测到未闭合的节点链,将保存为可追加到当前画布的功能模块。',
|
||||
recipeScopeCompleteSaveHint: '检测到完整可独立运行的工作流,将保存为完整工作流;支持在新画布中独立打开。',
|
||||
recipeDelete: '删除',
|
||||
recipeDeleteConfirm: '确定删除这个工作流配方吗?',
|
||||
recipeDeleteError: '删除工作流配方失败。',
|
||||
@@ -550,7 +550,7 @@ export const i18n = {
|
||||
recipeUpdateError: '更新工作流配方失败。',
|
||||
recipeViewDetails: '查看详情',
|
||||
recipeDetailBack: '返回配方列表',
|
||||
recipeDetailOverview: '概览',
|
||||
recipeDetailOverview: '配方概览',
|
||||
recipeGallery: '图库',
|
||||
recipeGalleryLoading: '正在查找匹配的历史出图…',
|
||||
recipeGalleryEmpty: '未在最近 200 张含工作流数据的 PNG 中找到与此配方结构匹配的出图。',
|
||||
@@ -569,30 +569,30 @@ export const i18n = {
|
||||
recipeGalleryDifferenceHint: '以下是节点参数的差异;图库匹配本身只关注节点类型。',
|
||||
recipeGalleryRecipeValue: '配方',
|
||||
recipeGalleryImageValue: '图片',
|
||||
recipeDetailModels: '模型与复现',
|
||||
recipeDetailParameters: '参数笔记本',
|
||||
recipeDetailParametersHint: '这里展示配方保存的完整参数;长文本可展开并复制。参数图库只匹配相同参数,不会因为本地路径不同而失效。',
|
||||
recipeParameterSnapshots: '参数快照',
|
||||
recipeParameterSnapshotsHint: '每次保存配方都会留下一个只读版本。',
|
||||
recipeParameterShowing: '当前显示的参数笔记',
|
||||
recipeParameterCurrentRecipe: '当前配方参数',
|
||||
recipeParameterActive: '当前',
|
||||
recipeParameterRefresh: '刷新快照',
|
||||
recipeParameterLoading: '正在读取参数快照…',
|
||||
recipeParameterLoadError: '无法读取参数快照。',
|
||||
recipeParameterNoSnapshots: '这个配方还没有参数快照。',
|
||||
recipeParameterUntitled: '未命名参数快照',
|
||||
recipeParameterDelete: '删除参数笔记',
|
||||
recipeParameterDeleteConfirm: '确定删除参数笔记“{name}”吗?此操作无法撤销。',
|
||||
recipeParameterDeleteError: '无法删除参数笔记,请稍后重试。',
|
||||
recipeParameterNew: '新建参数笔记',
|
||||
recipeParameterReadCurrent: '读取当前并新建',
|
||||
recipeParameterReadCurrentSaving: '正在读取并保存…',
|
||||
recipeDetailModels: '模型装备清单',
|
||||
recipeDetailParameters: '调参预设',
|
||||
recipeDetailParametersHint: '这里展示此配方保存的全部生成参数。可直接一键应用到当前画布,或从当前画布保存新预设。',
|
||||
recipeParameterSnapshots: '已存调参预设',
|
||||
recipeParameterSnapshotsHint: '同一个工作流可保存多组不同的调参预设,方便随时切换。',
|
||||
recipeParameterShowing: '当前选中的预设',
|
||||
recipeParameterCurrentRecipe: '默认配方参数',
|
||||
recipeParameterActive: '当前生效',
|
||||
recipeParameterRefresh: '刷新预设',
|
||||
recipeParameterLoading: '正在读取预设…',
|
||||
recipeParameterLoadError: '无法读取预设列表。',
|
||||
recipeParameterNoSnapshots: '当前配方还没有额外保存的调参预设。',
|
||||
recipeParameterUntitled: '未命名调参预设',
|
||||
recipeParameterDelete: '删除此预设',
|
||||
recipeParameterDeleteConfirm: '确定删除调参预设“{name}”吗?此操作无法撤销。',
|
||||
recipeParameterDeleteError: '无法删除预设,请稍后重试。',
|
||||
recipeParameterNew: '新建预设',
|
||||
recipeParameterReadCurrent: '从当前画布保存新预设',
|
||||
recipeParameterReadCurrentSaving: '正在保存当前画布参数…',
|
||||
recipeParameterReadCurrentError: '无法读取当前画布参数。',
|
||||
recipeParameterSkeletonMismatch: '当前画布缺少配方骨架节点,未执行任何修改。',
|
||||
recipeParameterWidgetMismatch: '当前画布的节点控件与参数笔记不一致:',
|
||||
recipeParameterSkeletonMismatch: '当前画布缺少配方必需的核心节点,无法直接应用参数。',
|
||||
recipeParameterWidgetMismatch: '当前画布的节点输入项与预设不一致:',
|
||||
recipeParameterNodeUnavailable: '无法在当前画布中定位匹配节点:',
|
||||
recipeParameterApply: '应用到当前工作流',
|
||||
recipeParameterApply: '应用到当前画布',
|
||||
recipeParameterApplying: '正在检查骨架并应用…',
|
||||
recipeParameterApplied: '已应用 {count} 项参数',
|
||||
recipeParameterApplyError: '应用参数失败,当前画布未完成修改。',
|
||||
|
||||
+156
-82
@@ -948,90 +948,174 @@ function renderReadinessBanner(parent, owner, recipe, references, finish, onRere
|
||||
parent.appendChild(banner);
|
||||
}
|
||||
|
||||
function renderPromptOverviewSection(parent, recipe) {
|
||||
const prompts = promptValues(recipe, recipe);
|
||||
if (!prompts?.entries?.length) return;
|
||||
|
||||
const wrap = document.createElement('div');
|
||||
wrap.style.display = 'grid';
|
||||
wrap.style.gap = '10px';
|
||||
wrap.style.marginBottom = '16px';
|
||||
|
||||
for (const entry of prompts.entries) {
|
||||
if (!entry?.value || typeof entry.value !== 'string' || !entry.value.trim()) continue;
|
||||
const isNegative = entry.role === 'negative';
|
||||
const box = document.createElement('div');
|
||||
box.className = `anomalous-recipe-prompt-box ${isNegative ? 'is-negative' : 'is-positive'}`;
|
||||
|
||||
const header = document.createElement('div');
|
||||
header.style.display = 'flex';
|
||||
header.style.justifyContent = 'space-between';
|
||||
header.style.alignItems = 'center';
|
||||
header.style.marginBottom = '6px';
|
||||
|
||||
const label = appendText(header, 'strong', isNegative ? '🔴 负向提示词 (Negative Prompt)' : '🟢 正向提示词 (Positive Prompt)');
|
||||
label.style.fontSize = '0.78rem';
|
||||
|
||||
const copyBtn = button(header, '📋 复制', 'anomalous-recipe-prompt-copy-btn');
|
||||
copyBtn.onclick = () => {
|
||||
navigator.clipboard.writeText(entry.value).then(() => {
|
||||
copyBtn.textContent = '✅ 已复制';
|
||||
setTimeout(() => { copyBtn.textContent = '📋 复制'; }, 1500);
|
||||
});
|
||||
};
|
||||
|
||||
box.appendChild(header);
|
||||
const text = appendText(box, 'div', entry.value);
|
||||
text.style.whiteSpace = 'pre-wrap';
|
||||
text.style.fontFamily = 'monospace';
|
||||
text.style.fontSize = '0.82rem';
|
||||
|
||||
wrap.appendChild(box);
|
||||
}
|
||||
|
||||
if (wrap.childElementCount) {
|
||||
parent.appendChild(wrap);
|
||||
}
|
||||
}
|
||||
|
||||
function renderOverview(content, owner, recipe, references, finish) {
|
||||
const overview = document.createElement('div');
|
||||
overview.className = 'anomalous-recipe-detail-overview';
|
||||
const hero = document.createElement('div');
|
||||
hero.className = 'anomalous-recipe-detail-hero';
|
||||
appendRecipeCover(hero, owner, recipe);
|
||||
|
||||
// Left media wrap
|
||||
const mediaWrap = document.createElement('div');
|
||||
mediaWrap.className = 'anomalous-recipe-detail-hero-media';
|
||||
appendRecipeCover(mediaWrap, owner, recipe);
|
||||
hero.appendChild(mediaWrap);
|
||||
|
||||
// Right control deck
|
||||
const copy = document.createElement('div');
|
||||
copy.className = 'anomalous-recipe-detail-hero-copy';
|
||||
const title = document.createElement('div');
|
||||
title.className = 'anomalous-recipe-inline-title-row';
|
||||
renderInlineTitle(title, owner, recipe);
|
||||
copy.appendChild(title);
|
||||
const notes = document.createElement('div');
|
||||
notes.className = 'anomalous-recipe-detail-notes';
|
||||
renderInlineNotes(notes, owner, recipe);
|
||||
copy.appendChild(notes);
|
||||
const tags = document.createElement('div');
|
||||
tags.className = 'anomalous-recipe-tags anomalous-recipe-detail-tags';
|
||||
renderInlineTags(tags, owner, recipe);
|
||||
copy.appendChild(tags);
|
||||
appendText(copy, 'small', `${t('recipeDetailUpdated')}: ${dateText(recipe.updated_timestamp || recipe.timestamp)}`, 'anomalous-recipe-detail-muted');
|
||||
|
||||
const overviewActions = document.createElement('div');
|
||||
overviewActions.className = 'anomalous-recipe-actions-primary';
|
||||
overviewActions.style.marginTop = '12px';
|
||||
const matchRecipe = button(overviewActions, '🔎 ' + t('recipeMatchRecipeModels'), 'anomalous-btn-ghost');
|
||||
matchRecipe.title = t('recipeMatchRecipeModelsDesc');
|
||||
const matchRecipeStatus = appendText(overviewActions, 'small', '', 'anomalous-recipe-header-status');
|
||||
matchRecipeStatus.setAttribute('aria-live', 'polite');
|
||||
matchRecipe.onclick = async () => {
|
||||
matchRecipe.disabled = true;
|
||||
matchRecipe.classList.add('is-busy');
|
||||
matchRecipe.textContent = t('recipeMatchingRecipeModels');
|
||||
try {
|
||||
const result = await matchRecipeModels(owner, references, matchRecipeStatus, () => {
|
||||
if (owner.recipeDetailActiveTab === 'overview') selectTab('overview');
|
||||
});
|
||||
matchRecipeStatus.textContent = result.total
|
||||
? t('recipeRecipeMatchSummary').replace('{found}', String(result.found)).replace('{total}', String(result.total))
|
||||
: t('recipeAllModelsMatched');
|
||||
} catch (error) {
|
||||
console.error('Could not match recipe models locally:', error);
|
||||
matchRecipeStatus.textContent = t('recipeLocalModelMatchError');
|
||||
} finally {
|
||||
matchRecipe.disabled = false;
|
||||
matchRecipe.classList.remove('is-busy');
|
||||
matchRecipe.textContent = '🔎 ' + t('recipeMatchRecipeModels');
|
||||
}
|
||||
};
|
||||
// Title + Scope Capsule
|
||||
const titleRow = document.createElement('div');
|
||||
titleRow.className = 'anomalous-recipe-inline-title-row';
|
||||
titleRow.style.display = 'flex';
|
||||
titleRow.style.alignItems = 'center';
|
||||
titleRow.style.gap = '8px';
|
||||
titleRow.style.flexWrap = 'wrap';
|
||||
renderInlineTitle(titleRow, owner, recipe);
|
||||
|
||||
const heroAppend = button(
|
||||
overviewActions,
|
||||
`${recipe?.workflow_scope === 'partial' ? '🧩' : '🚀'} ${recipeCanvasActionLabel(recipe)}`,
|
||||
'anomalous-recipe-btn-primary-action',
|
||||
);
|
||||
heroAppend.onclick = () => {
|
||||
void runRecipeAction(heroAppend, async () => {
|
||||
if (await applyRecipeToCanvas(owner, recipe)) finish('canvas');
|
||||
});
|
||||
};
|
||||
|
||||
const secondaryActions = document.createElement('div');
|
||||
secondaryActions.className = 'anomalous-recipe-actions-secondary';
|
||||
const heroEdit = button(secondaryActions, '✏️', 'anomalous-btn-icon anomalous-btn-edit');
|
||||
heroEdit.title = t('recipeEdit');
|
||||
heroEdit.onclick = () => finish('edit');
|
||||
overviewActions.appendChild(secondaryActions);
|
||||
copy.appendChild(overviewActions);
|
||||
|
||||
hero.appendChild(copy);
|
||||
overview.appendChild(hero);
|
||||
const scopePill = document.createElement('span');
|
||||
scopePill.className = 'anomalous-recipe-scope-pill';
|
||||
scopePill.textContent = recipe.workflow_scope === 'partial' ? t('recipeScopePartial') : t('recipeScopeComplete');
|
||||
titleRow.appendChild(scopePill);
|
||||
copy.appendChild(titleRow);
|
||||
|
||||
|
||||
// Intuitive environment readiness banner replacing technical identity stats
|
||||
renderReadinessBanner(overview, owner, recipe, references, finish, () => {
|
||||
// Readiness status banner inside Hero
|
||||
renderReadinessBanner(copy, owner, recipe, references, finish, () => {
|
||||
if (owner.recipeDetailActiveTab === 'overview') {
|
||||
content.replaceChildren();
|
||||
renderOverview(content, owner, recipe, references, finish);
|
||||
}
|
||||
});
|
||||
|
||||
// Primary action bar
|
||||
const overviewActions = document.createElement('div');
|
||||
overviewActions.className = 'anomalous-recipe-actions-primary';
|
||||
overviewActions.style.margin = '8px 0';
|
||||
overviewActions.style.display = 'flex';
|
||||
overviewActions.style.alignItems = 'center';
|
||||
overviewActions.style.gap = '8px';
|
||||
|
||||
const heroAppend = button(
|
||||
overviewActions,
|
||||
`${recipe?.workflow_scope === 'partial' ? '🧩' : '🚀'} ${recipeCanvasActionLabel(recipe)}`,
|
||||
'anomalous-recipe-btn-primary-action',
|
||||
);
|
||||
heroAppend.style.padding = '8px 16px';
|
||||
heroAppend.style.fontSize = '0.88rem';
|
||||
heroAppend.onclick = () => {
|
||||
void runRecipeAction(heroAppend, async () => {
|
||||
if (await applyRecipeToCanvas(owner, recipe)) finish('canvas');
|
||||
});
|
||||
};
|
||||
|
||||
const heroEdit = button(overviewActions, '✏️ ' + t('recipeEdit'), 'anomalous-btn-ghost');
|
||||
heroEdit.title = t('recipeEdit');
|
||||
heroEdit.onclick = () => finish('edit');
|
||||
|
||||
const heroExport = button(overviewActions, '📥 ' + t('recipeExport'), 'anomalous-btn-ghost');
|
||||
heroExport.title = t('recipeExport');
|
||||
heroExport.onclick = async () => {
|
||||
try {
|
||||
await exportRecipePackage(owner.recipeDetailFilename, recipe);
|
||||
} catch (error) {
|
||||
console.error('Could not export recipe package:', error);
|
||||
await anomalousAlert(t('recipeExportError'));
|
||||
}
|
||||
};
|
||||
|
||||
copy.appendChild(overviewActions);
|
||||
|
||||
// Studio Metrics Grid
|
||||
const params = recipe?.params || {};
|
||||
const resDisplay = formatRecipeResolution(params.resolution);
|
||||
if (params.steps || params.cfg || params.sampler_name || resDisplay) {
|
||||
const metrics = document.createElement('div');
|
||||
metrics.className = 'anomalous-recipe-studio-metrics';
|
||||
const addTile = (labelKey, val) => {
|
||||
if (val === undefined || val === null || val === '') return;
|
||||
const tile = document.createElement('div');
|
||||
tile.className = 'anomalous-recipe-studio-metric-tile';
|
||||
appendText(tile, 'span', t(labelKey), 'anomalous-recipe-studio-metric-label');
|
||||
appendText(tile, 'span', String(val), 'anomalous-recipe-studio-metric-val');
|
||||
metrics.appendChild(tile);
|
||||
};
|
||||
addTile('recipeDetailSteps', params.steps);
|
||||
addTile('recipeDetailCFG', params.cfg);
|
||||
addTile('recipeDetailSampler', params.sampler_name || params.samplers);
|
||||
addTile('recipeDetailResolution', resDisplay);
|
||||
copy.appendChild(metrics);
|
||||
}
|
||||
|
||||
// Notes & Tags
|
||||
const notes = document.createElement('div');
|
||||
notes.className = 'anomalous-recipe-detail-notes';
|
||||
renderInlineNotes(notes, owner, recipe);
|
||||
copy.appendChild(notes);
|
||||
|
||||
const tags = document.createElement('div');
|
||||
tags.className = 'anomalous-recipe-tags anomalous-recipe-detail-tags';
|
||||
renderInlineTags(tags, owner, recipe);
|
||||
copy.appendChild(tags);
|
||||
|
||||
appendText(copy, 'small', `${t('recipeDetailUpdated')}: ${dateText(recipe.updated_timestamp || recipe.timestamp)}`, 'anomalous-recipe-detail-muted');
|
||||
|
||||
hero.appendChild(copy);
|
||||
overview.appendChild(hero);
|
||||
|
||||
// Prompt Showcase Section
|
||||
renderPromptOverviewSection(overview, recipe);
|
||||
|
||||
// Technical details
|
||||
const advanced = document.createElement('details');
|
||||
advanced.className = 'anomalous-recipe-advanced-info';
|
||||
appendText(advanced, 'summary', t('recipeAdvancedInfo'));
|
||||
advanced.style.marginBottom = '14px';
|
||||
appendText(advanced, 'summary', `⚙️ ${t('recipeAdvancedInfo')}`);
|
||||
const fingerprint = document.createElement('div');
|
||||
fingerprint.className = 'anomalous-recipe-advanced-row';
|
||||
appendText(fingerprint, 'span', `${t('recipeDetailFingerprint')}:`);
|
||||
@@ -1040,29 +1124,16 @@ function renderOverview(content, owner, recipe, references, finish) {
|
||||
advanced.appendChild(fingerprint);
|
||||
overview.appendChild(advanced);
|
||||
|
||||
// Model Equipment Summary
|
||||
const summary = document.createElement('section');
|
||||
summary.className = 'anomalous-recipe-detail-section';
|
||||
appendText(summary, 'h4', t('recipeDetailSummary'));
|
||||
const summaryGrid = document.createElement('div');
|
||||
summaryGrid.className = 'anomalous-recipe-detail-summary-grid';
|
||||
const params = recipe.params || {};
|
||||
const modelComposition = document.createElement('div');
|
||||
modelComposition.className = 'anomalous-recipe-model-composition';
|
||||
summary.appendChild(modelComposition);
|
||||
renderModelComposition(modelComposition, owner, recipe, references, finish, params);
|
||||
overview.appendChild(summary);
|
||||
|
||||
const actions = document.createElement('div');
|
||||
actions.className = 'anomalous-recipe-actions anomalous-recipe-detail-actions';
|
||||
const edit = button(actions, t('recipeEdit'), 'anomalous-btn-success');
|
||||
edit.onclick = () => finish('edit');
|
||||
const append = button(actions, recipeCanvasActionLabel(recipe), 'anomalous-btn-primary');
|
||||
append.onclick = () => {
|
||||
void runRecipeAction(append, async () => {
|
||||
if (await applyRecipeToCanvas(owner, recipe)) finish('canvas');
|
||||
});
|
||||
};
|
||||
overview.appendChild(actions);
|
||||
content.appendChild(overview);
|
||||
}
|
||||
|
||||
@@ -2641,7 +2712,10 @@ export function showRecipeDetail(owner, { recipe, filename, history = [] }) {
|
||||
owner.recipeDetailPayload = { recipe, filename, history };
|
||||
owner.recipeDetailFilename = filename;
|
||||
owner.recipeListContainer.style.display = 'none';
|
||||
owner.recipeView.querySelector('.anomalous-recipe-actionbar').style.display = 'none';
|
||||
const actionbar = owner.recipeView?.querySelector('.anomalous-recipe-actionbar');
|
||||
if (actionbar) actionbar.style.display = 'none';
|
||||
const betaNotice = owner.recipeView?.querySelector('.anomalous-recipe-beta-notice');
|
||||
if (betaNotice) betaNotice.style.display = 'none';
|
||||
if (owner.recipeDetailView) owner.recipeDetailView.remove();
|
||||
|
||||
const view = document.createElement('div');
|
||||
@@ -2659,8 +2733,8 @@ export function showRecipeDetail(owner, { recipe, filename, history = [] }) {
|
||||
owner.recipeDetailView = null;
|
||||
if (!['canvas', 'append', 'model'].includes(mode)) {
|
||||
owner.recipeListContainer.style.display = '';
|
||||
const actionbar = owner.recipeView?.querySelector('.anomalous-recipe-actionbar');
|
||||
if (actionbar) actionbar.style.display = '';
|
||||
if (betaNotice) betaNotice.style.display = '';
|
||||
}
|
||||
if (owner.recipeDetailFinish === finish) owner.recipeDetailFinish = null;
|
||||
if (mode !== 'model') delete owner.recipeDetailPayload;
|
||||
|
||||
+324
-8
@@ -3901,12 +3901,328 @@ dialog.anomalous-gallery-viewer::backdrop {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
color: #cbd5e1;
|
||||
font-size: 0.82rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.anomalous-recipe-lazy-expand-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: #fff;
|
||||
gap: 4px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 999px;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.anomalous-recipe-readiness-pill.is-ready {
|
||||
background: rgba(16, 185, 129, 0.16);
|
||||
border-color: rgba(16, 185, 129, 0.45);
|
||||
color: #6ee7b7;
|
||||
}
|
||||
|
||||
.anomalous-recipe-readiness-pill.is-warning {
|
||||
background: rgba(245, 158, 11, 0.16);
|
||||
border-color: rgba(245, 158, 11, 0.45);
|
||||
color: #fcd34d;
|
||||
}
|
||||
|
||||
.anomalous-recipe-readiness-pill.is-missing {
|
||||
background: rgba(239, 68, 68, 0.16);
|
||||
border-color: rgba(239, 68, 68, 0.45);
|
||||
color: #fca5a5;
|
||||
}
|
||||
|
||||
.anomalous-recipe-card-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
margin-top: auto;
|
||||
padding-top: 8px;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.06);
|
||||
}
|
||||
|
||||
.anomalous-recipe-btn-primary-action {
|
||||
flex: 1;
|
||||
padding: 8px 12px;
|
||||
border-radius: 8px;
|
||||
background: linear-gradient(135deg, rgba(99, 102, 241, 0.85), rgba(79, 70, 229, 0.95));
|
||||
border: 1px solid rgba(129, 140, 248, 0.4);
|
||||
color: #ffffff;
|
||||
font-size: 0.82rem;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
box-shadow: 0 2px 8px rgba(99, 102, 241, 0.25);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.anomalous-recipe-btn-primary-action:hover {
|
||||
filter: brightness(1.15);
|
||||
box-shadow: 0 4px 14px rgba(99, 102, 241, 0.45);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.anomalous-recipe-card-mini-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.anomalous-recipe-card-mini-btn {
|
||||
padding: 6px 8px;
|
||||
border-radius: 6px;
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
color: #94a3b8;
|
||||
cursor: pointer;
|
||||
font-size: 0.85rem;
|
||||
line-height: 1;
|
||||
transition: all 0.15s ease;
|
||||
}
|
||||
|
||||
.anomalous-recipe-card-mini-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
color: #fff;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
/* Detail View: Readiness Banner */
|
||||
.anomalous-recipe-readiness-banner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
padding: 12px 16px;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 12px;
|
||||
font-size: 0.88rem;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.anomalous-recipe-readiness-banner.is-ready {
|
||||
background: linear-gradient(135deg, rgba(16, 185, 129, 0.15), rgba(5, 150, 105, 0.08));
|
||||
border: 1px solid rgba(16, 185, 129, 0.35);
|
||||
color: #a7f3d0;
|
||||
}
|
||||
|
||||
.anomalous-recipe-readiness-banner.is-warning {
|
||||
background: linear-gradient(135deg, rgba(245, 158, 11, 0.18), rgba(217, 119, 6, 0.08));
|
||||
border: 1px solid rgba(245, 158, 11, 0.4);
|
||||
color: #fde68a;
|
||||
}
|
||||
|
||||
.anomalous-recipe-readiness-banner.is-missing {
|
||||
background: linear-gradient(135deg, rgba(239, 68, 68, 0.18), rgba(185, 28, 28, 0.08));
|
||||
border: 1px solid rgba(239, 68, 68, 0.4);
|
||||
color: #fecaca;
|
||||
}
|
||||
|
||||
.anomalous-recipe-banner-btn {
|
||||
padding: 6px 14px;
|
||||
border-radius: 7px;
|
||||
font-size: 0.82rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
transition: all 0.2s ease;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.anomalous-recipe-banner-btn.is-match-all {
|
||||
background: #f59e0b;
|
||||
color: #1a1a1a;
|
||||
box-shadow: 0 2px 8px rgba(245, 158, 11, 0.3);
|
||||
}
|
||||
|
||||
.anomalous-recipe-banner-btn.is-match-all:hover {
|
||||
filter: brightness(1.1);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
/* Metric Cards for Sampling Parameters */
|
||||
.anomalous-recipe-metric-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
|
||||
gap: 10px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.anomalous-recipe-metric-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
padding: 10px 12px;
|
||||
border-radius: 8px;
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
border: 1px solid rgba(255, 255, 255, 0.07);
|
||||
}
|
||||
|
||||
.anomalous-recipe-metric-label {
|
||||
font-size: 0.74rem;
|
||||
color: #94a3b8;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.anomalous-recipe-metric-value {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
color: #f8fafc;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Lazy Loaded Raw Nodes Container */
|
||||
.anomalous-recipe-raw-nodes-summary {
|
||||
padding: 10px 14px;
|
||||
border-radius: 8px;
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
color: #93c5fd;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 500;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.anomalous-recipe-raw-nodes-summary:hover {
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
}
|
||||
|
||||
.anomalous-recipe-lazy-expand-btn {
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
padding: 9px;
|
||||
border-radius: 8px;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
color: #cbd5e1;
|
||||
font-size: 0.82rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.anomalous-recipe-lazy-expand-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Studio Layout Overhaul */
|
||||
.anomalous-recipe-detail-overview .anomalous-recipe-detail-hero {
|
||||
display: grid !important;
|
||||
grid-template-columns: 260px minmax(0, 1fr) !important;
|
||||
gap: 20px !important;
|
||||
align-items: start !important;
|
||||
padding: 16px !important;
|
||||
border-radius: 14px !important;
|
||||
background: linear-gradient(145deg, rgba(30, 32, 38, 0.7), rgba(18, 19, 23, 0.85)) !important;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08) !important;
|
||||
margin-bottom: 16px !important;
|
||||
backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
.anomalous-recipe-detail-hero-media {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 220px;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
background: #0d0e11;
|
||||
border: 1px solid rgba(255, 255, 255, 0.06);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.anomalous-recipe-detail-hero-media img,
|
||||
.anomalous-recipe-detail-hero-media video {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
max-height: none !important;
|
||||
object-fit: cover !important;
|
||||
border-radius: 9px;
|
||||
cursor: pointer;
|
||||
transition: transform 0.25s ease;
|
||||
}
|
||||
|
||||
.anomalous-recipe-detail-hero-media:hover img {
|
||||
transform: scale(1.02);
|
||||
}
|
||||
|
||||
.anomalous-recipe-studio-metrics {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
|
||||
gap: 8px;
|
||||
margin: 12px 0 8px 0;
|
||||
}
|
||||
|
||||
.anomalous-recipe-studio-metric-tile {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
padding: 8px 10px;
|
||||
border-radius: 8px;
|
||||
background: rgba(255, 255, 255, 0.035);
|
||||
border: 1px solid rgba(255, 255, 255, 0.06);
|
||||
}
|
||||
|
||||
.anomalous-recipe-studio-metric-label {
|
||||
font-size: 0.72rem;
|
||||
color: #94a3b8;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.3px;
|
||||
}
|
||||
|
||||
.anomalous-recipe-studio-metric-val {
|
||||
font-size: 0.96rem;
|
||||
font-weight: 600;
|
||||
color: #f1f5f9;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Prompt Showcase Boxes */
|
||||
.anomalous-recipe-prompt-box {
|
||||
position: relative;
|
||||
padding: 12px 14px;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 10px;
|
||||
font-size: 0.84rem;
|
||||
line-height: 1.55;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.anomalous-recipe-prompt-box.is-positive {
|
||||
background: rgba(16, 185, 129, 0.06);
|
||||
border: 1px solid rgba(16, 185, 129, 0.22);
|
||||
color: #ecfdf5;
|
||||
}
|
||||
|
||||
.anomalous-recipe-prompt-box.is-negative {
|
||||
background: rgba(244, 63, 94, 0.06);
|
||||
border: 1px solid rgba(244, 63, 94, 0.22);
|
||||
color: #fff1f2;
|
||||
}
|
||||
|
||||
.anomalous-recipe-prompt-copy-btn {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
padding: 3px 8px;
|
||||
border-radius: 6px;
|
||||
background: rgba(255, 255, 255, 0.07);
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
color: #cbd5e1;
|
||||
font-size: 0.72rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s;
|
||||
}
|
||||
|
||||
.anomalous-recipe-prompt-copy-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.18);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.anomalous-recipe-beta-notice[style*="display: none"] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user