diff --git a/docs/branding-preview-feature.md b/docs/branding-preview-feature.md new file mode 100644 index 0000000..24be53a --- /dev/null +++ b/docs/branding-preview-feature.md @@ -0,0 +1,194 @@ +# Project Branding Preview Enhancement + +## Overview +Add a live, reactive preview unit to the Branding tab showing how the project header will appear on the public site, with visibility toggles for individual branding elements. + +--- + +## Phase 1: Database & Type Updates + +### 1.1 Database Schema Changes +**File**: Prisma schema +- Add new optional boolean fields to Project model: + - `showFeaturedImageInHeader` (default: true) + - `showBackgroundColorInHeader` (default: true) + - `showLogoInHeader` (default: true) + +### 1.2 Type Definition Updates +**File**: `/src/lib/types/project.ts` +- Add new fields to `Project` interface +- Add new fields to `ProjectFormData` interface +- Update `defaultProjectFormData` with default values (all true) + +--- + +## Phase 2: Create Preview Component + +### 2.1 New Component: ProjectBrandingPreview.svelte +**Location**: `/src/lib/components/admin/ProjectBrandingPreview.svelte` + +**Features**: +- Full-width container (respects parent padding) +- 300px height (matches public project header) +- Responsive height (250px on tablet, 200px on mobile) +- Display priority: featuredImage > backgroundColor > fallback gray (#f5f5f5) +- Logo centered vertically and horizontally (85px x 85px) +- Fallback placeholder logo when no logo provided +- Reactive to all formData changes (featuredImage, backgroundColor, logoUrl) +- Conditional rendering based on visibility toggles +- Corner radius matching public site ($card-corner-radius) +- Subtle mouse-tracking animation on logo (optional, matches public site) + +**Props**: +```typescript +interface Props { + featuredImage: string | null + backgroundColor: string + logoUrl: string + showFeaturedImage: boolean + showBackgroundColor: boolean + showLogo: boolean +} +``` + +### 2.2 Visual States to Handle: +1. **No data**: Gray background + placeholder icon +2. **Logo only**: Show logo on fallback background +3. **Color only**: Show color background without logo +4. **Featured image only**: Show image without logo +5. **All elements**: Featured image (or color) + logo +6. **Featured image + color**: Featured image takes priority, color ignored +7. **Visibility toggles**: Respect all toggle states + +--- + +## Phase 3: Update ProjectBrandingForm + +### 3.1 Form Restructure +**File**: `/src/lib/components/admin/ProjectBrandingForm.svelte` + +**New Layout Order**: +1. **Preview Section** (top, unlabeled) + - ProjectBrandingPreview component + - Bound to all reactive form data + +2. **Background Section** + - Featured Image uploader (keep existing) + - Background Color picker (keep existing) + - Toggle: "Show featured image in header" + - Toggle: "Show background color in header" (only visible if no featured image, or featured image toggle is off) + - Help text: "Featured image takes priority over background color" + +3. **Logo Section** + - Logo uploader (keep existing) + - Toggle: "Show logo in header" + - Help text: "Upload an SVG logo that appears centered over the header background" + +4. **Colors Section** + - Highlight Color picker (keep existing) + +### 3.2 Toggle Component Pattern +Use existing toggle pattern from AlbumForm.svelte: +```svelte + +``` + +### 3.3 Bind FormData Fields +- Add bindings for new toggle fields +- Ensure auto-save triggers on toggle changes + +--- + +## Phase 4: Additional Enhancements (Suggestions) + +### 4.1 Preview Mode Selector +Add segmented control to preview component header: +- **Header View** (default): 300px tall, logo centered +- **Card View**: 80px tall, matches ProjectItem card style +- Shows how branding appears in different contexts + +### 4.2 Background Priority Explanation +Add info callout: +- "When both featured image and background color are provided, the featured image will be used in the header" +- Consider adding radio buttons for explicit priority selection + +### 4.3 Logo Adjustments +Add additional controls (future enhancement): +- Logo size slider (small/medium/large) +- Logo position selector (center/top-left/top-right/bottom-center) +- Logo background blur/darken overlay toggle (for better logo visibility) + +### 4.4 Smart Defaults +- Auto-enable toggles when user uploads/adds content +- Auto-disable toggles when user removes content +- Show warning if logo would be invisible (e.g., white logo on white background) + +### 4.5 Accessibility Improvements +- Add alt text field for featured image in preview +- Logo contrast checker against background +- ARIA labels for preview container + +### 4.6 Layout Improvements +Add section dividers with subtle borders between: +- Preview (unlabeled, visual-only) +- Background settings +- Logo settings +- Color settings + +--- + +## Implementation Checklist + +### Database & Types +- [ ] Add schema fields: `showFeaturedImageInHeader`, `showBackgroundColorInHeader`, `showLogoInHeader` +- [ ] Run migration +- [ ] Update Project type interface +- [ ] Update ProjectFormData type interface +- [ ] Update defaultProjectFormData with defaults + +### Components +- [ ] Create ProjectBrandingPreview.svelte component +- [ ] Add preview rendering logic (image vs color priority) +- [ ] Add fallback states (no data, partial data) +- [ ] Style preview to match public header dimensions +- [ ] Add reactive binding to all branding props + +### Form Updates +- [ ] Import ProjectBrandingPreview into ProjectBrandingForm +- [ ] Add preview at top of form (full-width, unlabeled) +- [ ] Add toggle for "Show featured image in header" +- [ ] Add toggle for "Show background color in header" +- [ ] Add toggle for "Show logo in header" +- [ ] Bind toggles to formData +- [ ] Add helpful descriptions to each toggle +- [ ] Copy toggle styles from AlbumForm +- [ ] Test auto-save with toggle changes + +### Public Site Updates +- [ ] Update project detail page to respect visibility toggles +- [ ] Update ProjectItem cards to respect visibility toggles (if applicable) +- [ ] Ensure backward compatibility (default to showing all elements) + +### Testing +- [ ] Test all preview states (no data, partial data, full data) +- [ ] Test toggle interactions +- [ ] Test auto-save with changes +- [ ] Test on different viewport sizes +- [ ] Test with real project data + +--- + +## Technical Notes + +- **Reactivity**: Use Svelte 5 runes ($derived, $state) for reactive preview +- **Performance**: Preview should update without lag during typing/color picking +- **Autosave**: All toggle changes should trigger autosave +- **Validation**: Consider warning if header would be blank (all toggles off) +- **Migration**: Existing projects should default all visibility toggles to `true` diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 1e52383..323d158 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -25,11 +25,14 @@ model Project { publishedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt - backgroundColor String? @db.VarChar(50) - highlightColor String? @db.VarChar(50) - logoUrl String? @db.VarChar(500) - password String? @db.VarChar(255) - projectType String @default("work") @db.VarChar(50) + backgroundColor String? @db.VarChar(50) + highlightColor String? @db.VarChar(50) + logoUrl String? @db.VarChar(500) + password String? @db.VarChar(255) + projectType String @default("work") @db.VarChar(50) + showFeaturedImageInHeader Boolean @default(true) + showBackgroundColorInHeader Boolean @default(true) + showLogoInHeader Boolean @default(true) @@index([slug]) @@index([status]) diff --git a/src/lib/components/admin/ProjectBrandingPreview.svelte b/src/lib/components/admin/ProjectBrandingPreview.svelte new file mode 100644 index 0000000..105a4b3 --- /dev/null +++ b/src/lib/components/admin/ProjectBrandingPreview.svelte @@ -0,0 +1,140 @@ + + +
+ {#if shouldShowLogo} + + {:else if showLogo} + +
+ {@html placeholderIcon} +
+ {/if} +
+ + diff --git a/src/lib/stores/project-form.svelte.ts b/src/lib/stores/project-form.svelte.ts index 9fe924d..9fe8505 100644 --- a/src/lib/stores/project-form.svelte.ts +++ b/src/lib/stores/project-form.svelte.ts @@ -37,7 +37,10 @@ export function createProjectFormStore(initialProject?: Project | null) { caseStudyContent: project.caseStudyContent || { type: 'doc', content: [{ type: 'paragraph' }] - } + }, + showFeaturedImageInHeader: project.showFeaturedImageInHeader ?? true, + showBackgroundColorInHeader: project.showBackgroundColorInHeader ?? true, + showLogoInHeader: project.showLogoInHeader ?? true } original = { ...fields } } @@ -104,7 +107,10 @@ export function createProjectFormStore(initialProject?: Project | null) { fields.caseStudyContent.content && fields.caseStudyContent.content.length > 0 ? fields.caseStudyContent - : null + : null, + showFeaturedImageInHeader: fields.showFeaturedImageInHeader, + showBackgroundColorInHeader: fields.showBackgroundColorInHeader, + showLogoInHeader: fields.showLogoInHeader } } } diff --git a/src/lib/types/project.ts b/src/lib/types/project.ts index 8b4553f..720f66b 100644 --- a/src/lib/types/project.ts +++ b/src/lib/types/project.ts @@ -20,6 +20,9 @@ export interface Project { displayOrder: number status: ProjectStatus password: string | null + showFeaturedImageInHeader: boolean + showBackgroundColorInHeader: boolean + showLogoInHeader: boolean createdAt?: string updatedAt?: string publishedAt?: string | null @@ -41,6 +44,9 @@ export interface ProjectFormData { status: ProjectStatus password: string caseStudyContent: any + showFeaturedImageInHeader: boolean + showBackgroundColorInHeader: boolean + showLogoInHeader: boolean } export const defaultProjectFormData: ProjectFormData = { @@ -61,5 +67,8 @@ export const defaultProjectFormData: ProjectFormData = { caseStudyContent: { type: 'doc', content: [{ type: 'paragraph' }] - } + }, + showFeaturedImageInHeader: true, + showBackgroundColorInHeader: true, + showLogoInHeader: true } diff --git a/src/routes/work/[slug]/+page.svelte b/src/routes/work/[slug]/+page.svelte index c9113eb..efb82f8 100644 --- a/src/routes/work/[slug]/+page.svelte +++ b/src/routes/work/[slug]/+page.svelte @@ -148,13 +148,21 @@