# Editor Panel Reorganisation

Status: Complete

## Problem

The current 3-tab editor panel (Page | Theme | Settings) has gaps and unintuitive organisation:

1. **Missing functionality** — can't edit announcement bar text, social links, header/footer nav, footer about text
2. **Scattered concerns** — shop name is in Theme (visual design) but it's business info; navigation settings are spread across multiple places
3. **Settings tab is underused** — on system/product pages it's essentially read-only with links elsewhere

## Vision

A user editing their shop should find everything in a logical place based on what they're trying to do:
- "I want to change what's on this page" → Page tab
- "I want to change how my site looks" → Theme tab
- "I want to change site-wide content" → Site tab

## Proposed Structure

### Page tab (content on this specific page)

**For all pages:**
- Block editor (add, reorder, duplicate, delete, edit)
- Undo/redo

**For custom CMS pages only (inline, not separate Settings tab):**
- Page title
- URL slug
- Meta description
- Published toggle
- Show in navigation toggle
- Navigation label & position (if show_in_nav)

**For system pages:**
- Block editor only (title/slug not editable)
- "Reset to defaults" for resettable pages

**For product/collection pages:**
- Read-only info with link to admin

### Theme tab (visual design — how it looks)

Keep existing structure but **remove** shop name and logo (move to Site tab):

**Quick settings:**
- Preset grid (8 themes)
- Accent colour, hover colour, sale colour

**Advanced (Customise accordion):**
- Typography: font style, size, heading weight
- Colours: mood (warm, neutral, cool, dark)
- Layout: grid columns, density, header layout, sticky header
- Shape: corners, shadows, button style
- Products: content width, image aspect, text alignment, hover image, show prices
- Product page: trust badges, reviews, related products

### Site tab (site-wide content — what appears everywhere)

New tab replacing "Settings". Contains everything that appears on every page:

**Branding:**
- Shop name
- Logo (upload, show/hide, size, recolour, colour)
- Favicon (upload)
- Header background image (upload, zoom, position)

**Announcement bar:**
- Show announcement bar (toggle)
- Announcement text (NEW — currently hardcoded)
- Announcement link URL (optional)
- Announcement style (info, sale, warning)

**Header navigation:**
- Editable list of nav items
- Each item: label, link (page picker or URL), position
- "Add nav item" button

**Footer:**
- About text (NEW — the footer blurb)
- Copyright text (NEW — currently auto-generated)
- Show newsletter signup (toggle)

**Footer navigation:**
- Editable list of footer nav items ("Help" section)
- Each item: label, link, position

**Social links:**
- Editable list of social links (NEW)
- Each link: platform (dropdown), URL
- Reorder via drag or arrows

## Data Model Changes

### New fields in Settings

```elixir
# Announcement bar
:announcement_text, :string, default: ""
:announcement_link, :string, default: ""
:announcement_style, :string, default: "info"  # info | sale | warning

# Footer content
:footer_about, :string, default: ""
:footer_copyright, :string, default: ""  # empty = auto-generate
:show_newsletter, :boolean, default: true
```

### New schema: SocialLink

```elixir
schema "social_links" do
  field :platform, :string  # instagram, bluesky, mastodon, twitter, youtube, tiktok, etc.
  field :url, :string
  field :position, :integer
  timestamps()
end
```

### New schema: NavItem

```elixir
schema "nav_items" do
  field :location, :string  # "header" | "footer"
  field :label, :string
  field :url, :string  # can be relative (/about) or absolute
  field :page_id, :binary_id  # optional, links to a Page
  field :position, :integer
  timestamps()
end
```

## Migration Path

### Phase 1: Data model + Site tab skeleton (3h)

1. Add new Settings fields (announcement_text, footer_about, etc.)
2. Create SocialLink schema and migration
3. Create NavItem schema and migration
4. Seed default nav items from current hardcoded values
5. Seed default social links from current hardcoded values
6. Create Site tab component (skeleton)

### Phase 2: Announcement bar (1.5h)

1. Add announcement text/link/style inputs to Site tab
2. Update shop header to read from Settings instead of hardcoded
3. Style variants for info/sale/warning

### Phase 3: Social links editor (2h)

1. Add social links editor to Site tab (list with add/remove/reorder)
2. Platform dropdown with icons
3. Update footer to read from SocialLink table
4. Delete hardcoded social links

### Phase 4: Navigation editors (3h)

1. Add header nav editor to Site tab
2. Add footer nav editor to Site tab
3. Page picker component (dropdown of published pages)
4. Update header/footer to read from NavItem table
5. Delete hardcoded nav arrays

### Phase 5: Footer content (1h)

1. Add footer about text input
2. Add copyright text input (with placeholder showing auto-generated)
3. Add newsletter toggle
4. Update footer component to use these values

### Phase 6: Move branding from Theme to Site (1.5h)

1. Move shop name input to Site tab
2. Move logo settings to Site tab
3. Move favicon settings to Site tab
4. Move header background settings to Site tab
5. Update Theme tab to remove these sections
6. Ensure Theme tab still feels complete (may need UI polish)

### Phase 7: Merge Settings into Page (1h)

1. For custom pages: move title/slug/meta/published/nav settings inline into Page tab
2. Remove Settings tab entirely
3. Update tab switching logic

### Phase 8: Polish and testing (2h)

1. Responsive design for Site tab
2. Empty states
3. Validation and error handling
4. Test all combinations (custom page, system page, product page, collection)
5. Update onboarding/help text if needed

## Task Breakdown

| # | Task | Depends | Est | Status |
|---|------|---------|-----|--------|
| 1 | Data model: new Settings fields + migrations | — | 1h | done |
| 2 | Data model: SocialLink schema + seed defaults | 1 | 45m | done |
| 3 | Data model: NavItem schema + seed defaults | 1 | 45m | done |
| 4 | Site tab skeleton component | 1 | 30m | done |
| 5 | Announcement bar: editor UI | 4 | 45m | done |
| 6 | Announcement bar: read from Settings | 5 | 30m | done |
| 7 | Announcement bar: style variants | 6 | 15m | done |
| 8 | Social links: editor UI (list, add, remove, reorder) | 4 | 1.5h | done |
| 9 | Social links: read from database | 8 | 30m | done |
| 10 | Header nav: editor UI | 4 | 1h | done |
| 11 | Header nav: page picker component | 10 | 30m | done |
| 12 | Header nav: read from database | 11 | 30m | done |
| 13 | Footer nav: editor UI | 10 | 30m | done |
| 14 | Footer nav: read from database | 13 | 30m | done |
| 15 | Footer content: about, copyright, newsletter toggle | 4 | 45m | done |
| 16 | Footer: read new fields | 15 | 30m | done |
| 17 | Move branding settings from Theme to Site | 4 | 1h | done |
| 18 | Theme tab: remove branding, polish remaining | 17 | 30m | done |
| 19 | Merge page settings into Page tab | — | 45m | done |
| 20 | Remove Settings tab | 19 | 15m | done |
| 21 | Polish: responsive, empty states, validation | 1-20 | 1.5h | done |
| 22 | Testing: all page types, edge cases | 21 | 30m | done |

**Total estimate: ~15h**

## Implementation Notes

### Completed: Social Links (Tasks 8-9)

The social links feature supports 40+ platforms grouped into 9 categories:
- Social (Instagram, Threads, TikTok, Facebook, Twitter, Snapchat, LinkedIn)
- Video & streaming (YouTube, Twitch, Vimeo, Kick, Rumble)
- Music & podcasts (Spotify, SoundCloud, Bandcamp, Apple Podcasts)
- Creative (Pinterest, Behance, Dribbble, Tumblr, Medium)
- Support & sales (Patreon, Ko-fi, Etsy, Gumroad, Substack)
- Federated (Mastodon, Pixelfed, Bluesky, PeerTube, Lemmy, Matrix)
- Developer (GitHub, GitLab, Codeberg, SourceHut, Reddit)
- Messaging (Discord, Telegram, Signal, WhatsApp)
- Other (Linktree, RSS, Website, Custom)

**URL handling:**
- `normalize_url/1` trims whitespace and adds `https://` to bare domains
- Preserves existing protocols (`http://`, `https://`, app deep links like `tg://`, `spotify:`)
- Preserves other URI schemes (`mailto:`, `tel:`, `rss://`)

**Platform detection:**
- `detect_platform/1` auto-detects platform from pasted URLs
- Works with scheme-based detection (e.g., `tg://` → telegram, `spotify:` → spotify)
- Works with host-based detection (e.g., `github.com` → github, `bsky.app` → bluesky)
- Handles subdomain patterns (e.g., `artist.bandcamp.com` → bandcamp)
- Returns "custom" for unknown domains

**Data flow:**
- Database → `Site.list_social_links/0` → raw structs loaded into original and current state
- Shop display → `Site.social_links_for_shop/0` → filtered (no empty URLs), formatted maps
- Editor preview → `format_social_links_for_shop/1` in layout.ex → same filtering
- Social links card block now uses database data via `assigns[:social_links]`
- Changes preview immediately, persist on Save button via `sync_social_links/2`

**Files:**
- `lib/berrypod/site.ex` - Site context with social links CRUD
- `lib/berrypod/site/social_link.ex` - Schema, URL normalization, platform detection
- `lib/berrypod_web/components/shop_components/site_editor.ex` - Editor UI
- `lib/berrypod_web/page_editor_hook.ex` - Event handlers
- `test/berrypod/site_test.exs` - 35 tests covering all functionality

### Completed: Navigation Editors (Tasks 10-14)

Header and footer navigation items are managed through a unified `nav_editor` component.

**Features:**
- Add/edit/delete/reorder nav items
- Label input with live preview
- Link type selector: Page (dropdown) or Custom URL (text input)
- Page picker shows linkable system pages (home, about, delivery, privacy, terms, contact) and published custom pages
- Move up/down buttons with disabled state at boundaries
- Changes preview immediately, persist on Save button

**Event handlers:**
- `site_add_nav_item` - Creates temporary item in local state
- `site_update_nav_item` - Updates label, URL, or page selection in local state based on `_target`
- `site_remove_nav_item` - Removes item from local state
- `site_move_nav_item` - Reorders items in local state

**Save/revert behavior:**
- All nav item and social link changes participate in the unified dirty state system
- `compute_site_dirty/1` compares current state against original state loaded at editor open
- On Save: `sync_nav_items/2` and `sync_social_links/2` diff current vs original and create/update/delete as needed
- On Discard: reverts to original state from `site_editor_original`
- Navigation warning modal appears when navigating with unsaved changes

**Data flow:**
- Database → `Site.list_nav_items/1` → raw structs loaded into original and current state
- Shop display → `Site.nav_items_for_shop/1` → formatted maps with computed href/slug
- Header/footer components already wired to use `@header_nav_items`/`@footer_nav_items`

**Files:**
- `lib/berrypod/site.ex` - NavItem CRUD and reorder functions
- `lib/berrypod/site/nav_item.ex` - Schema with location, label, url, page_id, position
- `lib/berrypod_web/components/shop_components/site_editor.ex` - `nav_editor` component
- `lib/berrypod_web/page_editor_hook.ex` - Event handlers, sync functions, dirty state
- `assets/css/admin/components.css` - Styles for nav editor

### Completed: Branding Migration (Tasks 17-18)

Moved branding settings from Theme tab to Site tab.

**What moved:**
- Shop name input
- Show shop name / Show logo toggles
- Logo upload (file picker, size slider, recolor toggle, color picker)
- Header background toggle
- Header image upload (file picker, zoom slider, position sliders)

**Event routing:**
- Site tab branding events use `site_` prefix (e.g., `site_update_branding`, `site_toggle_branding`)
- These route to the same underlying theme state (`theme_editor_settings`, `theme_editor_logo_image`, etc.)
- Logo/header uploads still use `theme_logo_upload` and `theme_header_upload` (shared with theme save flow)
- `site_remove_logo` and `site_remove_header` delegate to theme action handlers

**Files modified:**
- `lib/berrypod_web/page_renderer.ex` - Pass branding props to site_editor
- `lib/berrypod_web/components/shop_components/site_editor.ex` - Add `branding_editor` component with logo/header upload sections
- `lib/berrypod_web/page_editor_hook.ex` - Add `site_update_branding`, `site_toggle_branding`, `site_update_color`, `site_remove_logo`, `site_remove_header` handlers
- `lib/berrypod_web/components/shop_components/theme_editor.ex` - Remove `shop_name_input`, `branding_section`, logo/header upload sections

**Theme tab now contains:**
- Preset grid (8 themes)
- Accent, hover, sale colours
- Customise accordion with typography, colours, layout, shape, products, product page groups

### Completed: Page Settings Migration (Tasks 19-20)

Merged custom page settings inline into Page tab and removed Settings tab.

**What changed:**
- Custom pages show a collapsible "Page settings" section at the top of the Page tab
- Contains: title, URL slug, meta description, published toggle, show in nav toggle, nav label, nav position
- System pages, product pages, and collection pages no longer show settings (editing done elsewhere)
- Settings tab button was already removed from UI; dead code removed from page_renderer.ex
- Deleted `settings_editor.ex` component entirely

**Files modified:**
- `lib/berrypod_web/page_renderer.ex` - Added `page_settings_section` component inline in `editor_sheet_content`
- `lib/berrypod_web/components/shop_components.ex` - Removed SettingsEditor import
- `assets/css/admin/components.css` - Added `.page-settings-*` styles, removed old `.settings-*` styles

**Files deleted:**
- `lib/berrypod_web/components/shop_components/settings_editor.ex`

## UI Wireframes

### Site tab layout

```
┌─────────────────────────────────────┐
│ [Page] [Theme] [Site]               │  ← tabs
├─────────────────────────────────────┤
│                                     │
│ ▼ Branding                          │  ← collapsible section
│   Shop name: [____________]         │
│   Logo: [Upload] [Remove]           │
│   □ Show logo  □ Show shop name     │
│   Logo size: ●────────○ 48px        │
│   □ Recolour logo                   │
│   Favicon: [Upload]                 │
│                                     │
│ ▼ Announcement bar                  │
│   □ Show announcement bar           │
│   Text: [Free shipping over £50___] │
│   Link: [/delivery______________]   │
│   Style: ○ Info  ● Sale  ○ Warning  │
│                                     │
│ ▼ Header navigation                 │
│   ┌─────────────────────────────┐   │
│   │ Shop        /products    ↕ │   │
│   │ About       /about       ↕ │   │
│   │ Contact     /contact     ↕ │   │
│   └─────────────────────────────┘   │
│   [+ Add nav item]                  │
│                                     │
│ ▼ Footer                            │
│   About text:                       │
│   [Handmade with love in London___] │
│   [_______________________________] │
│   Copyright: [________________]     │
│   (Leave blank for "© 2026 Shop")   │
│   □ Show newsletter signup          │
│                                     │
│ ▼ Footer navigation                 │
│   ┌─────────────────────────────┐   │
│   │ Delivery    /delivery    ↕ │   │
│   │ Returns     /returns     ↕ │   │
│   │ Privacy     /privacy     ↕ │   │
│   └─────────────────────────────┘   │
│   [+ Add nav item]                  │
│                                     │
│ ▼ Social links                      │
│   ┌─────────────────────────────┐   │
│   │ 📷 Instagram  @myshop    ↕ │   │
│   │ 🦋 Bluesky    @my.bsky   ↕ │   │
│   │ ☕ Ko-fi      /myshop    ↕ │   │
│   └─────────────────────────────┘   │
│   [+ Add social link]               │
│                                     │
└─────────────────────────────────────┘
```

### Page tab with inline settings (custom page)

```
┌─────────────────────────────────────┐
│ [Page] [Theme] [Site]               │
├─────────────────────────────────────┤
│                                     │
│ ▼ Page settings                     │  ← new section for custom pages
│   Title: [About Us_______________]  │
│   URL: berrypod.com/[about_______]  │
│   Meta description:                 │
│   [Learn about our story...______]  │
│   □ Published                       │
│   □ Show in navigation              │
│                                     │
│ ▼ Content blocks                    │
│   [Hero block]              [↑][↓][×]│
│   [Text block]              [↑][↓][×]│
│   [Image block]             [↑][↓][×]│
│   [+ Add block]                     │
│                                     │
│   [↩ Undo] [↪ Redo]                 │
│                                     │
└─────────────────────────────────────┘
```

## Open Questions

1. **Should header/footer nav support nested items (dropdowns)?** — Probably not for v1, keep it flat.

2. **Should social links include "custom" option?** — Yes, allow custom label + URL for platforms we don't have icons for.

3. **What happens to existing hardcoded nav when we migrate?** — Seed the database with current values, delete hardcoded arrays.

4. **Should announcement bar support scheduling?** — Defer to profit-aware-pricing plan (task 71) which already includes this.

5. **Should we keep the Settings tab for "advanced" page settings?** — No, inline is simpler. Power users can use admin pages panel.
