Gallery Layout Refactor: Remove buttons and modernize grid
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
- **Node Cards & Smart Expansion**: Each node's parameters are wrapped in a styled card (`.anomalous-recipe-detail-parameter-node`). The inner widgets use a responsive grid layout to eliminate vertical cramming. Overly long nodes automatically collapse to a maximum height (`is-collapsed`) with a smooth gradient mask and a bottom expand button.
|
||||
- **Hero Image Gallery (Plan B)**: Replaced the bottom inline gallery section with a prominent Hero Section (`.anomalous-recipe-detail-hero`) at the top. The first generated image acts as a large cover banner.
|
||||
- **Modal Gallery Viewer**: If a recipe has multiple generated images, a sleek glassmorphism button overlay appears on the hero image (e.g., `🖼️ 图库 (5)`). Clicking it opens a native HTML `<dialog>` containing the full gallery grid, preventing the parameter view from bloating vertically while keeping the core browsing experience focused.
|
||||
- **Gallery Grid Refactor**: Removed the cluttered action buttons ("Set Cover", "Compare", "View Image") from all gallery cards across the application. Gallery grids now use a sleek, uniform responsive layout (`aspect-ratio: 1`, `object-fit: cover`) with a subtle hover zoom effect, relying on a direct click to view the original image.
|
||||
|
||||
**Validation**
|
||||
|
||||
|
||||
@@ -1806,15 +1806,8 @@ function renderRecipeParameters(content, owner, recipe, gallery, refreshGallery,
|
||||
const image = document.createElement('img');
|
||||
image.src = url;
|
||||
image.loading = 'lazy';
|
||||
image.onclick = () => { void showGalleryComparison(card, owner, sourceImage); };
|
||||
image.onclick = () => owner.showGalleryViewer?.(url);
|
||||
card.appendChild(image);
|
||||
const actions = document.createElement('div');
|
||||
actions.className = 'anomalous-recipe-gallery-card-actions';
|
||||
const viewBtn = button(actions, t('recipeGalleryOpenImage'), 'anomalous-btn-ghost');
|
||||
viewBtn.onclick = () => owner.showGalleryViewer?.(url);
|
||||
const compareBtn = button(actions, t('recipeGalleryCompare'), 'anomalous-btn-ghost');
|
||||
compareBtn.onclick = () => { void showGalleryComparison(card, owner, sourceImage); };
|
||||
card.appendChild(actions);
|
||||
grid.appendChild(card);
|
||||
}
|
||||
dialog.appendChild(grid);
|
||||
@@ -2008,46 +2001,8 @@ function renderRecipeGallery(content, owner, recipe, gallery, refresh) {
|
||||
image.src = url;
|
||||
image.alt = t('recipeGalleryOpenImage');
|
||||
image.loading = 'lazy';
|
||||
image.onclick = () => { void showGalleryComparison(card, owner, sourceImage); };
|
||||
image.onclick = () => owner.showGalleryViewer?.(url);
|
||||
card.appendChild(image);
|
||||
const actions = document.createElement('div');
|
||||
actions.className = 'anomalous-recipe-gallery-card-actions';
|
||||
const viewImage = button(actions, t('recipeGalleryOpenImage'), 'anomalous-btn-ghost');
|
||||
viewImage.onclick = (event) => {
|
||||
event.stopPropagation();
|
||||
owner.showGalleryViewer?.(url);
|
||||
};
|
||||
const compare = button(actions, t('recipeGalleryCompare'), 'anomalous-btn-ghost');
|
||||
compare.onclick = (event) => {
|
||||
event.stopPropagation();
|
||||
void showGalleryComparison(card, owner, sourceImage);
|
||||
};
|
||||
const setCover = button(actions, t('recipeGallerySetCover'), 'anomalous-btn-primary');
|
||||
setCover.onclick = (event) => {
|
||||
event.stopPropagation();
|
||||
void runRecipeAction(setCover, async () => {
|
||||
const response = await fetch('/anomalous/set_recipe_gallery_cover', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ filename: owner.recipeDetailFilename, source_image: sourceImage }),
|
||||
});
|
||||
if (!response.ok) throw new Error('recipe gallery cover update failed');
|
||||
const payload = await response.json();
|
||||
recipe.source_image = payload.source_image || sourceImage;
|
||||
recipe.thumbnail = null;
|
||||
recipe.presentation = {
|
||||
...(recipe.presentation || {}),
|
||||
cover_asset_id: payload.cover?.asset_id,
|
||||
};
|
||||
if (payload.workflow_fingerprint) recipe.workflow_fingerprint = payload.workflow_fingerprint;
|
||||
await owner.refreshRecipes();
|
||||
setCover.textContent = t('recipeGalleryCoverSaved');
|
||||
}).catch(async (error) => {
|
||||
console.error('Could not set recipe gallery cover:', error);
|
||||
await anomalousAlert(t('recipeGalleryCoverError'));
|
||||
});
|
||||
};
|
||||
card.appendChild(actions);
|
||||
grid.appendChild(card);
|
||||
}
|
||||
section.appendChild(grid);
|
||||
|
||||
@@ -3127,3 +3127,38 @@
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Gallery Grid Refactor */
|
||||
.anomalous-recipe-gallery-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||
gap: 16px;
|
||||
padding: 16px 0;
|
||||
}
|
||||
|
||||
.anomalous-recipe-gallery-card {
|
||||
position: relative;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
aspect-ratio: 1;
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.anomalous-recipe-gallery-card:hover {
|
||||
transform: scale(1.03);
|
||||
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.4);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.anomalous-recipe-gallery-card img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.anomalous-recipe-gallery-card-actions {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user