# Unified On-Site Editing Mode Status: Planned Replace the separate admin theme editor (`/admin/theme`) with an on-site editing experience. When the admin clicks "Theme" or "Edit page", they're taken to the actual shop where a sliding panel allows them to edit either page content or theme settings — seeing changes live on the real site. ## Current Architecture The codebase already has a robust pattern for on-site editing via the **PageEditorHook**: - `PageEditorHook` attaches to all shop pages, initializing ~15 editor-related assigns - `editor_sheet` component in `ShopComponents.Layout` renders a FAB + sliding panel - `PageRenderer` conditionally renders editor UI when `@is_admin` is true - Changes preview instantly; state persists across the session The theme editor currently lives at `/admin/theme` with its own LiveView and fake preview. ## Approach **Extend the existing editor infrastructure** to support both page editing and theme editing: 1. Add theme editing state to the existing hook system 2. Add a tab switcher to the editor panel (Page | Theme | Settings) 3. Extract theme editor UI into a reusable component 4. Route `/admin/theme` to shop homepage with `?edit=theme` param ## User Flow 1. Admin clicks "Theme" in admin sidebar → redirects to `/?edit=theme` 2. Shop homepage loads with theme editing panel open 3. Admin can switch between "Page", "Theme", and "Settings" tabs 4. Admin can navigate to other shop pages while keeping editor open 5. "Done" or "×" button returns to admin or closes panel ## Files to Modify | File | Change | |------|--------| | `lib/berrypod_web/page_editor_hook.ex` | Add theme/settings editing assigns, tab state, event handlers | | `lib/berrypod_web/page_renderer.ex` | Add tab UI to editor_sheet, dispatch to theme/page/settings content | | `lib/berrypod_web/components/shop_components/layout.ex` | Update editor_sheet for 3-tab support, add new keys to layout_keys | | `lib/berrypod_web/components/shop_components/theme_editor.ex` | **New** - Extracted theme editor panel component | | `lib/berrypod_web/components/shop_components/settings_editor.ex` | **New** - Page/shop settings panel component | | `lib/berrypod_web/router.ex` | Redirect /admin/theme to /?edit=theme | | `assets/css/shop/editor.css` | **New** - Editor panel styling (extract from admin) | | `assets/js/hooks/theme_editor.js` | **New** - ColorSync and other theme editor hooks | ## Implementation ### Phase 1: Theme Editor Hook Integration Add theme editing state to `PageEditorHook`: ```elixir # New assigns in on_mount :theme_editing -> false :theme_settings -> nil (loaded when theme_editing activates) :theme_active_preset -> nil :theme_logo_image -> nil :theme_header_image -> nil :theme_icon_image -> nil :theme_contrast_warning -> :ok :theme_customise_open -> false # New event handlers "theme_*" events -> handled by attach_hook similar to editor_* events ``` ### Phase 2: Editor Panel Tabs Add three tabs to the editor panel: | Tab | Content | When available | |-----|---------|----------------| | **Page** | Block editor for custom pages | Only on editable pages (home, about, custom CMS pages) | | **Theme** | Global styles, mood, typography, branding | Always | | **Settings** | Page-specific settings (SEO, slug) or global shop settings | Always (content varies by page) | Update `editor_sheet` component: ```heex
<%= case @editor_active_tab do %> <% :page -> %> <.editor_sheet_content ... /> <% :theme -> %> <.theme_editor_content ... /> <% :settings -> %> <.settings_editor_content ... /> <% end %> ``` **Settings tab content varies by context:** - On custom CMS pages: Page title, slug, SEO (meta title, description) - On product pages: Read-only product info, link to admin product editor - On collection pages: Collection settings, link to admin - Global fallback: Shop name, description, favicon settings ### Phase 3: Extract Theme Editor Component Create `lib/berrypod_web/components/shop_components/theme_editor.ex`: - Extract the sidebar content from current `/admin/theme` template - Reuse same event names (`update_setting`, `toggle_setting`, `apply_preset`, etc.) - Support image uploads via `allow_upload` passed from hook Key sections to extract: - Presets grid - Mood/typography/shape/density selectors - Logo upload + settings - Header background upload + settings - Accent color pickers - Customise accordion (advanced settings) ### Phase 3b: Create Settings Editor Component Create `lib/berrypod_web/components/shop_components/settings_editor.ex`: **Content varies by page type:** | Page type | Settings shown | |-----------|---------------| | Custom CMS page | Page title, slug, visibility, SEO meta | | Home page | Shop name, description, SEO defaults | | Product page | Read-only product name, link to admin product editor | | Collection page | Read-only collection name, link to admin | | Cart/checkout | Shop policies, checkout settings link | **Common sections:** - Page SEO (meta title, description, social image) - Favicon settings (short name, icon upload) - Shop identity (name, description) ### Phase 4: Image Upload Handling Image uploads need special handling since we're in a hook, not a LiveView: Option A: **Delegate to the parent LiveView** - Pass `@uploads` from the LiveView through assigns - Hook events trigger upload handling in the LiveView - Cleanest approach, matches existing pattern Option B: **Use a LiveComponent for uploads** - Wrap upload sections in a stateful LiveComponent - Component handles its own uploads - More isolated but adds complexity **Recommended: Option A** — follow the pattern the page editor already uses. ### Phase 5: URL-Based Mode Activation Handle `?edit=theme` query param: ```elixir # In PageEditorHook handle_params hook defp handle_params_hook(params, _uri, socket) do socket = case params["edit"] do "theme" -> enter_theme_edit_mode(socket) "page" -> enter_page_edit_mode(socket) _ -> socket end {:cont, socket} end ``` ### Phase 6: Admin Routing Update router to redirect theme link: ```elixir # In admin scope, redirect /admin/theme to shop get "/theme", Plug.Redirect, to: "/?edit=theme" ``` Or keep the admin theme page as a fallback/redirect: ```elixir live "/theme", Admin.Theme.Redirect # Simple LiveView that redirects ``` ## State Management **Theme editing state persists across navigation** via hook attach: - `attach_hook(:theme_params, :handle_params, &handle_params_hook/3)` tracks URL - Theme settings stored in socket assigns - CSS regenerated and assigned to `@generated_css` on each change - ThemeHook already loads CSS; we just update the assign **Dirty tracking:** - Theme changes save immediately (current behavior) OR - Add "unsaved" state like page editor (better UX but more work) **Recommendation:** Keep immediate save for now (it's the existing behavior and simpler). ## CSS Considerations The editor panel uses admin CSS classes. Options: 1. **Extract shared styles** into `shop/editor.css` loaded on all shop pages 2. **Namespace admin styles** so they work in shop context 3. **Use inline styles** (not recommended) **Recommended:** Create `assets/css/shop/editor.css` with editor panel styles, include it in shop layout when `@is_admin`. ## What Happens to /admin/theme? Options: 1. **Remove it entirely** — redirects to `/?edit=theme` 2. **Keep as fallback** — simple page that redirects or links to on-site editor 3. **Keep for non-visual settings** — things like favicon short name, SEO defaults **Recommended:** Redirect to `/?edit=theme` for now. Can always add back a minimal settings page later if needed. ## Verification 1. Click "Theme" in admin → lands on shop homepage with theme panel open 2. Change mood → see colors update instantly on real site 3. Upload logo → appears in real header immediately 4. Navigate to product page → theme panel stays open 5. Switch to "Page" tab on homepage → shows page block editor 6. Switch to "Page" tab on product page → tab disabled (no editable blocks) 7. Click "Done" → returns to admin dashboard 8. Mobile: panel slides up from bottom, fully usable ## Phased Rollout ### MVP (Phases 1-3) - Theme editing works on-site - Basic tab UI (Page | Theme | Settings) - All current theme settings functional - No image uploads yet (use existing images) ### Full Feature (Phases 4-6) - Image uploads working - URL-based mode activation - Admin redirect in place - Polish and edge cases ## Future Enhancements (Not in Scope) - Undo/redo for theme changes - "Preview without saving" mode - Theme presets preview before applying - Multi-page preview from single location