- Add uload project with apps/web structure
- Reorganize from flat to monorepo structure
- Remove PocketBase binary and local data
- Update to pnpm and @uload/web namespace
- Add picture project to monorepo
- Remove embedded git repository
- Unify all package names to @{project}/{app} schema:
- @maerchenzauber/* (was @storyteller/*)
- @manacore/* (was manacore-*, manacore)
- @manadeck/* (was web, backend, manadeck)
- @memoro/* (was memoro-web, landing, memoro)
- @picture/* (already unified)
- @uload/web
- Add convenient dev scripts for all apps:
- pnpm dev:{project}:web
- pnpm dev:{project}:landing
- pnpm dev:{project}:mobile
- pnpm dev:{project}:backend
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
11 KiB
Gallery Collection - Complete Implementation Guide
Overview
The Gallery Collection displays AI-generated images from Picture's showcase. It's designed to inspire users, demonstrate model capabilities, and provide prompt examples.
Collection Structure
Schema Location
src/content/config.ts - galleryCollection
Type
type: 'data' - Gallery entries are JSON/YAML data files (not markdown)
Content Location
src/content/gallery/*.json
Schema Fields
Basic Information
title(string, required) - Image titleslug(string, required) - URL-friendly identifierimageUrl(string, required) - Path to image filedescription(string, optional) - SEO description
Generation Details
prompt(string, required) - The prompt usednegativePrompt(string, optional) - Negative prompt if usedmodel(string, required) - Model slug (e.g., "flux-dev")
Generation Settings (optional object)
seed(number)steps(number)guidanceScale(number)width(number)height(number)aspectRatio(string)
Categorization
category(enum, required) - One of:portrait,landscape,abstract,illustration,photography,product,architecture,character,concept-art,otherstyle(string[], default: []) - Style tags like["cinematic", "moody", "dark"]tags(string[], default: []) - General tags
Creator Info (optional object)
name(string)avatar(string)profileUrl(string)
Visibility & Status
featured(boolean, default: false) - Show on homepagetrending(boolean, default: false) - Trending badgestaffPick(boolean, default: false) - Staff pick badgepublished(boolean, default: true) - Published or draft
Engagement Metrics
likes(number, default: 0)downloads(number, default: 0)views(number, default: 0)
Quality & Moderation
qualityScore(number, 1-5, optional) - Quality ratingnsfw(boolean, default: false) - NSFW flagmoderationStatus(enum, default: "approved") -approved,pending,rejected
Related Content
relatedImages(string[], default: []) - Related image slugsrelatedTutorials(string[], default: []) - Tutorial slugsrelatedModels(string[], default: []) - Model slugs
SEO
seoKeywords(string[], default: [])
Metadata
createdAt(date, required)updatedAt(date, optional)language(enum, default: "en") -en,de,fr,it,es
Technical Metadata (optional)
fileSize(number) - File size in bytesdimensions(object) -{ width: number, height: number }
Example Entry
{
"title": "Cinematic Portrait in Golden Hour",
"slug": "cinematic-portrait-golden-hour",
"imageUrl": "/gallery/cinematic-portrait.jpg",
"prompt": "Cinematic portrait of a woman in golden hour light, shallow depth of field, professional photography",
"negativePrompt": "cartoon, illustration, oversaturated",
"model": "flux-1-1-pro",
"settings": {
"seed": 42,
"steps": 1,
"guidanceScale": 3.5,
"width": 1024,
"height": 1440,
"aspectRatio": "5:7"
},
"category": "portrait",
"style": ["cinematic", "moody", "warm"],
"tags": ["portrait", "golden-hour", "photography"],
"creator": {
"name": "Picture Gallery"
},
"featured": true,
"trending": true,
"staffPick": true,
"published": true,
"likes": 1247,
"downloads": 389,
"views": 5623,
"qualityScore": 5,
"nsfw": false,
"moderationStatus": "approved",
"relatedImages": ["professional-headshot", "sunset-portrait"],
"relatedTutorials": ["advanced-prompt-engineering"],
"relatedModels": ["flux-1-1-pro"],
"description": "A stunning cinematic portrait showcasing FLUX 1.1 Pro.",
"seoKeywords": ["cinematic portrait", "AI portrait"],
"createdAt": "2025-01-15T10:00:00.000Z",
"language": "en",
"fileSize": 2456789,
"dimensions": {
"width": 1024,
"height": 1440
}
}
Utility Functions
Location: src/utils/gallery.ts
Fetching Images
// All images
const images = await getAllGalleryImages();
// By language
const images = await getGalleryImagesByLanguage('en');
// Featured images
const featured = await getFeaturedGalleryImages();
// Trending images
const trending = await getTrendingGalleryImages();
// Staff picks
const staffPicks = await getStaffPickGalleryImages();
// By category
const portraits = await getGalleryImagesByCategory('portrait');
// By model
const fluxImages = await getGalleryImagesByModel('flux-dev');
// By style tag
const cinematic = await getGalleryImagesByStyle('cinematic');
// By tag
const landscapes = await getGalleryImagesByTag('landscape');
Sorting & Filtering
// Most liked
const mostLiked = await getMostLikedGalleryImages(12);
// Most downloaded
const mostDownloaded = await getMostDownloadedGalleryImages(12);
// Most viewed
const mostViewed = await getMostViewedGalleryImages(12);
// Recent images
const recent = await getRecentGalleryImages(12);
// Search
const results = await searchGalleryImages('fantasy landscape');
// Single image
const image = await getGalleryImageBySlug('cinematic-portrait-golden-hour');
Related Content
// Get related images (by category, model, style, tags)
const related = await getRelatedGalleryImages(currentImage, 6);
Statistics & Aggregations
// Categories with counts
const categories = await getGalleryCategories();
// => [{ category: 'portrait', count: 15 }, ...]
// Style tags with counts
const styles = await getGalleryStyles();
// => [{ style: 'cinematic', count: 8 }, ...]
// Tags with counts
const tags = await getGalleryTags();
// => [{ tag: 'landscape', count: 12 }, ...]
// Overall stats
const stats = await getGalleryStats();
// => { totalImages, totalLikes, totalDownloads, totalViews, averageLikes, ... }
Helper Functions
// Format file size
formatFileSize(2456789); // => "2.3 MB"
// Get aspect ratio display name
getAspectRatioDisplay("16:9"); // => "Landscape"
Pages
Index Page
Location: src/pages/gallery/index.astro
Features:
- Hero section with stats
- Featured images section
- Trending images section
- Staff picks section
- All images with filters
- CTA section
URL: /gallery
Detail Page
Location: src/pages/gallery/[slug].astro
Features:
- Full image display
- Engagement bar (likes, views, downloads)
- Creator information
- Prompt display with copy functionality
- Generation settings
- Model information
- Tags and categories
- Related images
- Action buttons (Try This Prompt, Share)
URL: /gallery/[slug]
Components
GalleryCard
Location: src/components/gallery/GalleryCard.astro
Props:
image(CollectionEntry<'gallery'>) - The gallery imageshowStats(boolean, default: true) - Show engagement stats
Features:
- Image with hover overlay showing prompt
- Badges (featured, trending, staff pick)
- Quality score
- Model badge
- Category badge
- Engagement stats
- Creator info
GalleryFilters
Location: src/components/gallery/GalleryFilters.astro
Props:
categories({ category: string, count: number }[]) - Available categories
Features:
- Search input
- Category filter buttons
- Sort dropdown (likes, views, downloads, recent, quality)
- View toggle (grid/list)
- Interactive filtering with JavaScript
GalleryGrid
Location: src/components/gallery/GalleryGrid.astro
Props:
images(CollectionEntry<'gallery'>[]) - Images to displaycolumns(2 | 3 | 4, default: 4) - Number of columnsshowStats(boolean, default: true) - Show stats on cards
Features:
- Responsive grid layout
- Empty state when no images
Usage Examples
Homepage - Featured Gallery
---
import { getFeaturedGalleryImages } from '../utils/gallery';
import GalleryCard from '../components/gallery/GalleryCard.astro';
const featured = await getFeaturedGalleryImages();
---
<section>
<h2>Featured Gallery</h2>
<div class="grid grid-cols-4 gap-6">
{featured.map(image => <GalleryCard image={image} />)}
</div>
</section>
Model Page - Example Images
---
import { getGalleryImagesByModel } from '../utils/gallery';
const modelImages = await getGalleryImagesByModel('flux-1-1-pro');
---
<section>
<h2>Example Images</h2>
<div class="grid grid-cols-3 gap-4">
{modelImages.slice(0, 6).map(image => (
<GalleryCard image={image} showStats={false} />
))}
</div>
</section>
Best Practices
Image Guidelines
- Quality First - Only showcase high-quality generations
- Diverse Content - Show variety of styles, categories, and models
- Real Prompts - Use actual prompts that work well
- Accurate Settings - Include working generation settings
SEO Optimization
- Descriptive Titles - Clear, searchable titles
- Keywords - Include relevant keywords in description and tags
- Alt Text - Image title serves as alt text
- Structured Data - Schema is ready for structured data implementation
Content Moderation
- NSFW Filtering - Use
nsfwflag andmoderationStatus - Quality Control - Use
qualityScoreto curate best content - Staff Picks - Highlight exceptional examples
Performance
- Lazy Loading - Images use
loading="lazy" - Optimized Images - Store multiple sizes if needed
- CDN - Consider CDN for image delivery
Multi-Language Support
Add language-specific entries:
{
"title": "Porträt in goldenem Licht",
"slug": "portraet-goldenes-licht",
"language": "de",
...
}
Filter by language:
const germanImages = await getGalleryImagesByLanguage('de');
Integration with Other Collections
Link to AI Models
<a href={`/ai-models/${image.data.model}`}>View Model</a>
Link to Tutorials
{image.data.relatedTutorials.map(slug => (
<a href={`/tutorials/${slug}`}>View Tutorial</a>
))}
Future Enhancements
- User Submissions - Allow users to submit their creations
- Collections/Albums - Group images into themed collections
- Image Editor Integration - "Edit This Image" button
- Prompt Variations - Show variations of same prompt
- Download Sizes - Offer multiple download sizes
- Social Sharing - Share to social media
- Favorites - User favorites/bookmarks
- Real-time Stats - Live engagement metrics
- Advanced Search - Faceted search with multiple filters
- Lightbox Modal - Full-screen image viewer
Troubleshooting
Images not appearing
- Check
published: true - Verify
imageUrlpath is correct - Ensure image files exist in public folder
Filters not working
- Check JavaScript is enabled
- Verify
data-categoryattributes on cards - Check browser console for errors
Related images not showing
- Verify slugs in
relatedImagesexist - Check at least some images share category/model/tags
Example Gallery Entries
See example files in src/content/gallery/:
cinematic-portrait.json- Portrait examplefantasy-landscape.json- Landscape examplelogo-design.json- Text rendering exampleproduct-shot.json- Product photography exampleabstract-art.json- Abstract art examplecharacter-design.json- Character concept art example
Support
For questions or issues with the Gallery Collection:
- Check this documentation
- Review example entries
- Check utility function implementations
- Verify schema in
config.ts