add unified on-site editing mode plan
All checks were successful
deploy / deploy (push) Successful in 46s
All checks were successful
deploy / deploy (push) Successful in 46s
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
476da8121a
commit
74ab6411f7
26
PROGRESS.md
26
PROGRESS.md
@ -81,23 +81,20 @@ Replaced floating toast/flash messages with inline feedback and persistent top b
|
|||||||
| 6 | Migrate setup wizard notifications | 1h | done |
|
| 6 | Migrate setup wizard notifications | 1h | done |
|
||||||
| 7 | Remove old flash/toast CSS and JS | 30m | done |
|
| 7 | Remove old flash/toast CSS and JS | 30m | done |
|
||||||
|
|
||||||
### Live site editor ([plan](docs/plans/live-site-editor.md))
|
### Unified on-site editing ([plan](docs/plans/unified-editing-mode.md))
|
||||||
|
|
||||||
On-site editing overlay for admins: browse the real shop with a sidebar for theme and page editing. Inline contenteditable for text, live CSS variable injection for theme changes. Responsive layout (split view on desktop, overlay on mobile).
|
Extend the existing page editor (PageEditorHook + editor_sheet) to include theme editing. Admin clicks "Theme" → taken to actual shop with a 3-tab panel (Page | Theme | Settings). See changes live on the real site instead of a fake preview.
|
||||||
|
|
||||||
| Phase | Description | Est | Status |
|
| Phase | Description | Est | Status |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| 1 | Design: sketch approaches, pick one | 2h | planned |
|
| 1 | Add theme editing state to PageEditorHook | 2h | planned |
|
||||||
| 2 | Extract shared components from theme editor and page editor | 4h | planned |
|
| 2 | Add 3-tab UI to editor panel (Page/Theme/Settings) | 2h | planned |
|
||||||
| 3 | Build editor wrapper LiveView with sidebar shell | 3h | planned |
|
| 3 | Extract theme editor into reusable component | 3h | planned |
|
||||||
| 4 | Theme editing in sidebar (re-use theme controls, live CSS vars) | 3h | planned |
|
| 3b | Create settings editor component | 2h | planned |
|
||||||
| 5 | Block list and block settings in sidebar | 3h | planned |
|
| 4 | Image upload handling in hook context | 2h | planned |
|
||||||
| 6 | Block selection: click-to-select with highlight on page | 2h | planned |
|
| 5 | URL-based mode activation (?edit=theme) | 1h | planned |
|
||||||
| 7 | Inline text editing with contenteditable + phx-hook | 4h | planned |
|
| 6 | Admin routing redirect | 30m | planned |
|
||||||
| 8 | Responsive layout (split view / overlay) | 2h | planned |
|
| 7 | Polish and testing | 2h | planned |
|
||||||
| 9 | Save/discard/undo flow | 2h | planned |
|
|
||||||
| 10 | Edit mode toggle (floating button for admins on shop pages) | 1h | planned |
|
|
||||||
| 11 | Polish and testing | 4h | planned |
|
|
||||||
|
|
||||||
### Quick fixes (from usability testing)
|
### Quick fixes (from usability testing)
|
||||||
|
|
||||||
@ -149,6 +146,7 @@ All plans in [docs/plans/](docs/plans/). Completed plans are kept as architectur
|
|||||||
| [url-redirects.md](docs/plans/url-redirects.md) | Complete |
|
| [url-redirects.md](docs/plans/url-redirects.md) | Complete |
|
||||||
| [onboarding-ux.md](docs/plans/onboarding-ux.md) | Planned (v2) |
|
| [onboarding-ux.md](docs/plans/onboarding-ux.md) | Planned (v2) |
|
||||||
| [notification-overhaul.md](docs/plans/notification-overhaul.md) | Planned |
|
| [notification-overhaul.md](docs/plans/notification-overhaul.md) | Planned |
|
||||||
| [live-site-editor.md](docs/plans/live-site-editor.md) | Design exploration |
|
| [live-site-editor.md](docs/plans/live-site-editor.md) | Superseded by unified-editing-mode |
|
||||||
|
| [unified-editing-mode.md](docs/plans/unified-editing-mode.md) | Planned |
|
||||||
| [profit-aware-pricing.md](docs/plans/profit-aware-pricing.md) | Planned |
|
| [profit-aware-pricing.md](docs/plans/profit-aware-pricing.md) | Planned |
|
||||||
| [security-hardening.md](docs/plans/security-hardening.md) | Planned |
|
| [security-hardening.md](docs/plans/security-hardening.md) | Planned |
|
||||||
|
|||||||
270
docs/plans/unified-editing-mode.md
Normal file
270
docs/plans/unified-editing-mode.md
Normal file
@ -0,0 +1,270 @@
|
|||||||
|
# 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
|
||||||
|
<div class="editor-tabs">
|
||||||
|
<button
|
||||||
|
class={["editor-tab", @editor_active_tab == :page && "active"]}
|
||||||
|
phx-click="editor_set_tab"
|
||||||
|
phx-value-tab="page"
|
||||||
|
disabled={!@page}
|
||||||
|
>
|
||||||
|
Page
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class={["editor-tab", @editor_active_tab == :theme && "active"]}
|
||||||
|
phx-click="editor_set_tab"
|
||||||
|
phx-value-tab="theme"
|
||||||
|
>
|
||||||
|
Theme
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class={["editor-tab", @editor_active_tab == :settings && "active"]}
|
||||||
|
phx-click="editor_set_tab"
|
||||||
|
phx-value-tab="settings"
|
||||||
|
>
|
||||||
|
Settings
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%= 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
|
||||||
Loading…
Reference in New Issue
Block a user