docs: reorganize documentation and add ROADMAP

- Rewrite README.md with proper project overview, setup, and structure
- Create ROADMAP.md capturing future improvements and known gaps
- Move reference docs to docs/ directory:
  - docs/spec.md (theme system specification)
  - docs/plans/sample-content.md (POD content refresh plan)
  - docs/plans/page-builder.md (existing)
  - docs/research/typography.md
  - docs/research/ux-patterns.md
- Delete obsolete planning files:
  - PLAN.md (work complete)
  - PHASE_9_PLAN.md (work complete)
  - PHASE_9_PROGRESS.md (stale tracker)
  - RECENT_CHANGES.md (stale)
- Keep AGENTS.md (Phoenix codegen guidelines)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jamey Greenwood 2026-01-17 22:39:37 +00:00
parent a2d655d302
commit 6b6c7cc148
10 changed files with 265 additions and 2392 deletions

View File

@ -1,923 +0,0 @@
# SimpleShop Theme - Phase 9 Implementation Plan
## Overview
This plan covers **Phase 9: Storefront Integration** - applying the theme system to the actual public-facing shop. Based on my analysis, Phases 1-8 are complete, with a fully functional theme editor at `/admin/theme`. Phase 9 will create the public storefront that uses the saved theme settings.
## Current State Summary
✅ **Completed (Phases 1-8):**
- Settings and Media contexts with SQLite storage
- CSS three-layer architecture (primitives, attributes, semantic)
- Theme editor LiveView with 8 presets
- All 7 preview pages (home, collection, pdp, cart, about, contact, error)
- Full customization controls (mood, typography, shape, density, colors, layout, toggles)
- Logo and header image uploads with BLOB storage
- SVG recoloring functionality
- CSS generation system
- Preview data system (mock products, testimonials, categories)
❌ **Not Started (Phase 9):**
- Public storefront routes
- Storefront LiveViews
- Theme CSS injection for public pages
- Plug to load theme settings
- CSS cache warming
- Real product integration
## Architecture Decisions
### 1. Routing Strategy
- **Public routes**: Use root-level paths (`/`, `/products/:slug`, `/cart`, etc.)
- **No shop slug**: Since this app IS the shop (not multi-tenant), no slug needed
- **Future-proof**: Structure allows adding multi-shop support later if needed
### 2. LiveView Structure
- **Reuse preview templates**: The preview pages are already production-ready
- **Extract to shared components**: Move reusable pieces from preview_pages/ to components/
- **Storefront-specific LiveViews**: Create dedicated LiveViews that handle real data
### 3. CSS Application
- **Same three-layer system**: Use identical CSS as theme editor
- **Root element**: Use `.shop-root` class with data attributes
- **Inline CSS injection**: Inject generated CSS into layout via assign
- **ETS caching**: Use CSSCache for production performance
- **Cache invalidation**: Invalidate on theme settings save
### 4. Data Handling
- **Smart degradation**: Show empty states when no products exist
- **Graceful fallback**: Use preview data patterns for missing content
- **Real products**: When Products context exists, use real data
## Implementation Steps
### Step 1: Extract Shared Components
**Goal**: Move reusable preview components to shared location for use in both admin and storefront
**Files to create:**
- `lib/simpleshop_theme_web/components/shop/announcement_bar.ex`
- `lib/simpleshop_theme_web/components/shop/header.ex`
- `lib/simpleshop_theme_web/components/shop/footer.ex`
- `lib/simpleshop_theme_web/components/shop/search_modal.ex`
- `lib/simpleshop_theme_web/components/shop/product_card.ex`
**Files to modify:**
- `lib/simpleshop_theme_web/live/theme_live/preview_pages.ex` - Import and use new components
- All preview templates - Update to use new component modules
**Actions:**
1. Create `lib/simpleshop_theme_web/components/shop/` directory
2. Extract `announcement_bar/1` from preview_pages.ex to `shop/announcement_bar.ex`
3. Extract `shop_header/1` to `shop/header.ex`
4. Extract `shop_footer/1` to `shop/footer.ex`
5. Extract `search_modal/1` to `shop/search_modal.ex`
6. Create new `product_card/1` component (used in multiple places)
7. Update preview_pages.ex to import and use new components
8. Update all 7 preview templates to use new component paths
9. Test theme editor still works correctly
**Validation:**
- Run `mix test test/simpleshop_theme_web/live/theme_live_test.exs`
- Visit `/admin/theme` and verify all 7 preview pages still render correctly
- No visual regressions
---
### Step 2: Create LoadTheme Plug
**Goal**: Create a plug that loads theme settings and generated CSS for every public request
**Files to create:**
- `lib/simpleshop_theme_web/plugs/load_theme.ex`
- `test/simpleshop_theme_web/plugs/load_theme_test.exs`
**Plug functionality:**
```elixir
defmodule SimpleshopThemeWeb.Plugs.LoadTheme do
import Plug.Conn
alias SimpleshopTheme.Settings
alias SimpleshopTheme.Theme.{CSSGenerator, CSSCache}
def init(opts), do: opts
def call(conn, _opts) do
# Try cache first
{theme_settings, generated_css} =
case CSSCache.get() do
{:ok, css} ->
{Settings.get_theme_settings(), css}
:miss ->
settings = Settings.get_theme_settings()
css = CSSGenerator.generate(settings)
CSSCache.put(css)
{settings, css}
end
conn
|> assign(:theme_settings, theme_settings)
|> assign(:generated_css, generated_css)
end
end
```
**Files to modify:**
- `lib/simpleshop_theme_web/router.ex` - Add plug to public pipeline
**Actions:**
1. Create plug file with init/1 and call/2 functions
2. Implement cache-first CSS loading strategy
3. Assign both `:theme_settings` and `:generated_css` to conn
4. Add plug to `:browser` pipeline in router (before routes)
5. Write tests for plug behavior
6. Test cache hit and cache miss scenarios
**Validation:**
- Run `mix test test/simpleshop_theme_web/plugs/load_theme_test.exs`
- Verify assigns are available in subsequent requests
- Verify CSS is cached and reused
---
### Step 3: Create Storefront Layout
**Goal**: Create a dedicated layout for the public storefront with theme CSS injection
**Files to create:**
- `lib/simpleshop_theme_web/components/layouts/shop.html.heex`
**Layout structure:**
```heex
<!DOCTYPE html>
<html lang="en" class="h-full">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="csrf-token" content={get_csrf_token()} />
<.live_title><%= assigns[:page_title] || @theme_settings.site_name %></.live_title>
<link phx-track-static rel="stylesheet" href={~p"/assets/app.css"} />
<script defer phx-track-static type="text/javascript" src={~p"/assets/app.js"}></script>
<!-- Inject theme CSS -->
<style id="theme-css">
<%= Phoenix.HTML.raw(@generated_css) %>
</style>
</head>
<body class="h-full">
<div class="shop-root h-full"
data-mood={@theme_settings.mood}
data-typography={@theme_settings.typography}
data-shape={@theme_settings.shape}
data-density={@theme_settings.density}
data-grid={@theme_settings.grid_columns}
data-header={@theme_settings.header_layout}
data-sticky={to_string(@theme_settings.sticky_header)}
data-layout={@theme_settings.layout_width}
data-shadow={@theme_settings.card_shadow}>
<%= @inner_content %>
</div>
</body>
</html>
```
**Files to modify:**
- `lib/simpleshop_theme_web/components/layouts.ex` - Add `shop/1` layout function
**Actions:**
1. Create new shop.html.heex layout file
2. Add `.shop-root` wrapper with all theme data attributes
3. Inject `@generated_css` into `<style>` tag
4. Use `@theme_settings.site_name` for page title default
5. Add shop layout function to layouts.ex module
6. Ensure Google Fonts are loaded (already in root.html.heex)
**Validation:**
- Inspect HTML output to verify data attributes present
- Verify CSS injection works
- Check that layout compiles without errors
---
### Step 4: Create Home Page LiveView
**Goal**: Create the public homepage LiveView using real/mock data
**Files to create:**
- `lib/simpleshop_theme_web/live/shop_live/home.ex`
- `lib/simpleshop_theme_web/live/shop_live/home.html.heex`
- `test/simpleshop_theme_web/live/shop_live/home_test.exs`
**LiveView structure:**
```elixir
defmodule SimpleshopThemeWeb.ShopLive.Home do
use SimpleshopThemeWeb, :live_view
alias SimpleshopTheme.Theme.PreviewData
def mount(_params, _session, socket) do
# Use real products when available, else preview data
products = PreviewData.products()
categories = PreviewData.categories()
testimonials = PreviewData.testimonials()
{:ok, assign(socket,
page_title: "Home",
products: products,
categories: categories,
testimonials: testimonials
)}
end
end
```
**Template approach:**
- Copy structure from `preview_pages/home.html.heex`
- Use new shared components (header, footer, announcement_bar)
- Remove preview-specific wrapper divs
- Ensure data-driven rendering from assigns
**Files to modify:**
- `lib/simpleshop_theme_web/router.ex` - Add home route
**Actions:**
1. Create home LiveView module with mount function
2. Load preview data (real products when available)
3. Create home template based on preview version
4. Use shared components for header, footer, announcement bar
5. Add route: `live "/", ShopLive.Home, :index` in public scope
6. Set layout to `:shop` for route
7. Write tests for home page rendering
8. Test with and without products
**Router changes:**
```elixir
# Public storefront
scope "/", SimpleshopThemeWeb do
pipe_through :browser
live_session :public_shop, layout: {SimpleshopThemeWeb.Layouts, :shop} do
live "/", ShopLive.Home, :index
end
end
```
**Validation:**
- Visit `/` and verify homepage renders
- Check theme styles are applied
- Test announcement bar toggle works
- Verify header layout variations work
- Test sticky header toggle
- Confirm products display (mock data)
---
### Step 5: Create Collection Page LiveView
**Goal**: Create product collection/grid page
**Files to create:**
- `lib/simpleshop_theme_web/live/shop_live/collection.ex`
- `lib/simpleshop_theme_web/live/shop_live/collection.html.heex`
- `test/simpleshop_theme_web/live/shop_live/collection_test.exs`
**LiveView structure:**
```elixir
defmodule SimpleshopThemeWeb.ShopLive.Collection do
use SimpleshopThemeWeb, :live_view
alias SimpleshopTheme.Theme.PreviewData
def mount(%{"slug" => slug}, _session, socket) do
# Future: Load real collection by slug
# For now: Use preview products filtered by category
products = PreviewData.products()
{:ok, assign(socket,
page_title: "Shop All Products",
collection_name: "All Products",
products: products,
filter: nil,
sort: "featured"
)}
end
def handle_event("filter", %{"category" => category}, socket) do
# Filter products by category
{:noreply, assign(socket, filter: category)}
end
def handle_event("sort", %{"by" => sort_by}, socket) do
# Sort products
{:noreply, assign(socket, sort: sort_by)}
end
end
```
**Template approach:**
- Copy from `preview_pages/collection.html.heex`
- Implement filter sidebar (responds to filter events)
- Implement sort dropdown (price, name, featured)
- Use product_card component
- Respect grid_columns setting (2/3/4)
**Files to modify:**
- `lib/simpleshop_theme_web/router.ex` - Add collection route
**Actions:**
1. Create collection LiveView module
2. Implement filtering and sorting logic
3. Create collection template based on preview
4. Add route: `live "/collections/:slug", ShopLive.Collection, :show`
5. Handle empty state (no products)
6. Write tests for filtering and sorting
7. Test grid columns respect theme setting
**Router changes:**
```elixir
live "/collections/:slug", ShopLive.Collection, :show
live "/collections", ShopLive.Collection, :index # "All Products"
```
**Validation:**
- Visit `/collections` and `/collections/tshirts`
- Test filter sidebar works
- Test sort dropdown changes order
- Verify grid columns (2, 3, 4) work correctly
- Check card shadow setting is respected
- Test hover image toggle works
---
### Step 6: Create Product Detail Page (PDP) LiveView
**Goal**: Create individual product page with gallery, details, add to cart
**Files to create:**
- `lib/simpleshop_theme_web/live/shop_live/product.ex`
- `lib/simpleshop_theme_web/live/shop_live/product.html.heex`
- `test/simpleshop_theme_web/live/shop_live/product_test.exs`
**LiveView structure:**
```elixir
defmodule SimpleshopThemeWeb.ShopLive.Product do
use SimpleshopThemeWeb, :live_view
alias SimpleshopTheme.Theme.PreviewData
def mount(%{"slug" => slug}, _session, socket) do
# Future: Load real product by slug
# For now: Use first preview product
[product | _] = PreviewData.products()
{:ok, assign(socket,
page_title: product.name,
product: product,
selected_variant: nil,
quantity: 1,
selected_image: 0
)}
end
def handle_event("select_variant", %{"variant_id" => id}, socket) do
{:noreply, assign(socket, selected_variant: id)}
end
def handle_event("select_image", %{"index" => index}, socket) do
{:noreply, assign(socket, selected_image: String.to_integer(index))}
end
def handle_event("add_to_cart", _params, socket) do
# Future: Add to cart functionality
{:noreply, put_flash(socket, :info, "Added to cart")}
end
end
```
**Template approach:**
- Copy from `preview_pages/pdp.html.heex`
- Image gallery with thumbnails
- Variant selector (size, color)
- Quantity selector
- Add to cart button
- Respect toggle settings: `pdp_trust_badges`, `pdp_reviews`, `pdp_related_products`
- Gallery position: left/right based on `gallery_position` setting
**Files to modify:**
- `lib/simpleshop_theme_web/router.ex` - Add product route
**Actions:**
1. Create product LiveView module
2. Implement variant selection logic
3. Implement image gallery navigation
4. Create product template based on preview
5. Add route: `live "/products/:slug", ShopLive.Product, :show`
6. Handle toggle features (reviews, badges, related)
7. Write tests for variant selection and cart add
8. Test gallery position setting
**Router changes:**
```elixir
live "/products/:slug", ShopLive.Product, :show
```
**Validation:**
- Visit `/products/example-tshirt`
- Test variant selection updates UI
- Test image gallery thumbnail clicks
- Verify trust badges show/hide based on setting
- Verify reviews show/hide based on setting
- Verify related products show/hide based on setting
- Test "Add to cart" button (shows flash for now)
- Test gallery position (left/right) setting
---
### Step 7: Create Cart Page LiveView
**Goal**: Create shopping cart page with line items and checkout
**Files to create:**
- `lib/simpleshop_theme_web/live/shop_live/cart.ex`
- `lib/simpleshop_theme_web/live/shop_live/cart.html.heex`
- `test/simpleshop_theme_web/live/shop_live/cart_test.exs`
**LiveView structure:**
```elixir
defmodule SimpleshopThemeWeb.ShopLive.Cart do
use SimpleshopThemeWeb, :live_view
alias SimpleshopTheme.Theme.PreviewData
def mount(_params, _session, socket) do
# Future: Load real cart from session
# For now: Use preview cart items
cart_items = PreviewData.cart_items()
{:ok, assign(socket,
page_title: "Shopping Cart",
cart_items: cart_items,
subtotal: calculate_subtotal(cart_items),
shipping: 0,
tax: 0
)}
end
def handle_event("update_quantity", %{"id" => id, "quantity" => qty}, socket) do
# Update item quantity
{:noreply, socket}
end
def handle_event("remove_item", %{"id" => id}, socket) do
# Remove item from cart
{:noreply, socket}
end
def handle_event("checkout", _params, socket) do
# Future: Proceed to checkout
{:noreply, put_flash(socket, :info, "Checkout coming soon")}
end
defp calculate_subtotal(items) do
Enum.reduce(items, 0, fn item, acc ->
acc + (item.price * item.quantity)
end)
end
end
```
**Template approach:**
- Copy from `preview_pages/cart.html.heex`
- Line items with product image, name, variant, price, quantity
- Quantity update controls
- Remove item button
- Cart summary (subtotal, shipping, tax, total)
- Checkout button
- Empty cart state
**Files to modify:**
- `lib/simpleshop_theme_web/router.ex` - Add cart route
**Actions:**
1. Create cart LiveView module
2. Implement quantity update logic
3. Implement remove item logic
4. Create cart template based on preview
5. Add route: `live "/cart", ShopLive.Cart, :show`
6. Handle empty cart state
7. Write tests for cart operations
8. Test price calculations
**Router changes:**
```elixir
live "/cart", ShopLive.Cart, :show
```
**Validation:**
- Visit `/cart`
- Test quantity update buttons
- Test remove item button
- Verify price calculations correct
- Test empty cart state
- Verify checkout button shows flash
- Check button style setting is respected
---
### Step 8: Create Static Pages (About, Contact, Error)
**Goal**: Create remaining static pages
**Files to create:**
- `lib/simpleshop_theme_web/live/shop_live/about.ex`
- `lib/simpleshop_theme_web/live/shop_live/about.html.heex`
- `lib/simpleshop_theme_web/live/shop_live/contact.ex`
- `lib/simpleshop_theme_web/live/shop_live/contact.html.heex`
- `lib/simpleshop_theme_web/controllers/error_html/404.html.heex`
- `test/simpleshop_theme_web/live/shop_live/about_test.exs`
- `test/simpleshop_theme_web/live/shop_live/contact_test.exs`
**About Page:**
```elixir
defmodule SimpleshopThemeWeb.ShopLive.About do
use SimpleshopThemeWeb, :live_view
def mount(_params, _session, socket) do
{:ok, assign(socket, page_title: "About Us")}
end
end
```
**Contact Page:**
```elixir
defmodule SimpleshopThemeWeb.ShopLive.Contact do
use SimpleshopThemeWeb, :live_view
def mount(_params, _session, socket) do
{:ok, assign(socket,
page_title: "Contact Us",
form: to_form(%{})
)}
end
def handle_event("submit_contact", %{"contact" => params}, socket) do
# Future: Send contact email
{:noreply, put_flash(socket, :info, "Message sent successfully")}
end
end
```
**Files to modify:**
- `lib/simpleshop_theme_web/router.ex` - Add routes
- `lib/simpleshop_theme_web/controllers/error_html.ex` - Add 404 template
**Actions:**
1. Create about LiveView and template (copy from preview)
2. Create contact LiveView and template (copy from preview)
3. Add contact form submission handler
4. Create 404 error template (copy from preview_pages/error.html.heex)
5. Add routes: `live "/about"` and `live "/contact"`
6. Write tests for static pages
7. Test contact form submission
**Router changes:**
```elixir
live "/about", ShopLive.About, :show
live "/contact", ShopLive.Contact, :show
```
**Validation:**
- Visit `/about` and verify page renders
- Visit `/contact` and test form submission
- Visit invalid URL and verify 404 page shows with theme
- Check all pages respect theme settings
---
### Step 9: Wire Up CSS Cache Invalidation
**Goal**: Ensure CSS cache is invalidated when theme settings are saved
**Files to modify:**
- `lib/simpleshop_theme/settings.ex` - Add cache invalidation to update_theme_settings/1
- `lib/simpleshop_theme_web/live/theme_live/index.ex` - Ensure save_theme calls invalidation
**Actions:**
1. Update `Settings.update_theme_settings/1` to call `CSSCache.invalidate()` after save
2. Update `ThemeLive.Index.handle_event("save_theme")` to trigger cache refresh
3. Optionally warm cache after invalidation for first request performance
4. Test cache invalidation works correctly
**Code changes in Settings context:**
```elixir
def update_theme_settings(attrs) do
current = get_theme_settings()
changeset = ThemeSettings.changeset(current, attrs)
case changeset.valid? do
true ->
updated = Ecto.Changeset.apply_changes(changeset)
put_setting("theme_settings", updated, :json)
# Invalidate CSS cache
SimpleshopTheme.Theme.CSSCache.invalidate()
# Optionally warm cache immediately
css = SimpleshopTheme.Theme.CSSGenerator.generate(updated)
SimpleshopTheme.Theme.CSSCache.put(css)
{:ok, updated}
false ->
{:error, changeset}
end
end
```
**Validation:**
- Change theme settings in admin
- Save theme
- Visit public storefront
- Verify changes are reflected immediately
- Check cache is being used (add logging if needed)
---
### Step 10: Add Cache Warming on Application Start
**Goal**: Pre-generate and cache theme CSS when application starts
**Files to modify:**
- `lib/simpleshop_theme/application.ex` - Add cache warming after supervisor start
**Actions:**
1. Add cache warming function to Application module
2. Call after supervisor starts successfully
3. Handle case where no theme settings exist yet
4. Add logging for cache warming
**Code changes:**
```elixir
defmodule SimpleshopTheme.Application do
def start(_type, _args) do
children = [
# ... existing children ...
SimpleshopTheme.Theme.CSSCache,
# ... more children ...
]
opts = [strategy: :one_for_one, name: SimpleshopTheme.Supervisor]
result = Supervisor.start_link(children, opts)
# Warm CSS cache on startup
Task.start(fn -> warm_theme_cache() end)
result
end
defp warm_theme_cache do
try do
settings = SimpleshopTheme.Settings.get_theme_settings()
css = SimpleshopTheme.Theme.CSSGenerator.generate(settings)
SimpleshopTheme.Theme.CSSCache.put(css)
Logger.info("Theme CSS cache warmed successfully")
rescue
e -> Logger.warning("Failed to warm theme cache: #{inspect(e)}")
end
end
end
```
**Validation:**
- Restart application
- Check logs for "Theme CSS cache warmed successfully"
- Visit storefront immediately (should be fast)
- Verify no database queries for CSS generation on first request
---
### Step 11: Update Navigation Links
**Goal**: Connect theme editor to storefront and vice versa
**Files to modify:**
- `lib/simpleshop_theme_web/components/shop/header.ex` - Add admin link when authenticated
- `lib/simpleshop_theme_web/live/theme_live/index.html.heex` - Add "View Shop" link
**Actions:**
1. In shop header component, add conditional admin link for authenticated users
2. In theme editor, add "View Shop" button in controls area
3. Ensure links use proper route helpers
4. Test navigation between admin and storefront
**Shop header changes:**
```heex
<%= if @current_user do %>
<a href={~p"/admin/theme"} class="admin-link">
Edit Theme
</a>
<% end %>
```
**Theme editor changes (add near "Save Theme" button):**
```heex
<a href={~p"/"} target="_blank" class="btn btn-outline">
View Shop
</a>
```
**Validation:**
- When logged in on storefront, verify "Edit Theme" link appears
- Click link and verify navigates to theme editor
- In theme editor, click "View Shop" link
- Verify opens storefront in new tab
---
### Step 12: Testing and Polish
**Goal**: Comprehensive testing and UX improvements
**Files to modify:**
- All test files - Add comprehensive coverage
- Various LiveViews - Add loading states, error handling
**Actions:**
1. **Write comprehensive tests:**
- Test all storefront LiveViews
- Test plug behavior
- Test cache invalidation flow
- Test theme application across all pages
- Test responsive behavior
2. **Add loading states:**
- Product loading skeletons
- Cart update feedback
- Form submission states
3. **Error handling:**
- Handle missing products gracefully
- Handle invalid routes
- Handle network errors
4. **Performance optimization:**
- Verify CSS cache is working
- Check database query counts
- Test with many products (when available)
5. **Accessibility:**
- Check color contrast ratios
- Verify keyboard navigation
- Add ARIA labels where needed
6. **Mobile testing:**
- Test all pages on mobile viewport
- Verify touch interactions work
- Check responsive grid layouts
7. **Cross-browser testing:**
- Test in Chrome, Firefox, Safari
- Verify CSS variables work correctly
- Check font loading
**Validation:**
- Run full test suite: `mix test`
- All tests pass
- No console errors
- Good Lighthouse scores
- Responsive on all devices
---
## Summary of Files
### Files to Create (23 files)
**Shared Components (5 files):**
- `lib/simpleshop_theme_web/components/shop/announcement_bar.ex`
- `lib/simpleshop_theme_web/components/shop/header.ex`
- `lib/simpleshop_theme_web/components/shop/footer.ex`
- `lib/simpleshop_theme_web/components/shop/search_modal.ex`
- `lib/simpleshop_theme_web/components/shop/product_card.ex`
**Infrastructure (2 files):**
- `lib/simpleshop_theme_web/plugs/load_theme.ex`
- `lib/simpleshop_theme_web/components/layouts/shop.html.heex`
**Storefront LiveViews (10 files):**
- `lib/simpleshop_theme_web/live/shop_live/home.ex`
- `lib/simpleshop_theme_web/live/shop_live/home.html.heex`
- `lib/simpleshop_theme_web/live/shop_live/collection.ex`
- `lib/simpleshop_theme_web/live/shop_live/collection.html.heex`
- `lib/simpleshop_theme_web/live/shop_live/product.ex`
- `lib/simpleshop_theme_web/live/shop_live/product.html.heex`
- `lib/simpleshop_theme_web/live/shop_live/cart.ex`
- `lib/simpleshop_theme_web/live/shop_live/cart.html.heex`
- `lib/simpleshop_theme_web/live/shop_live/about.ex`
- `lib/simpleshop_theme_web/live/shop_live/about.html.heex`
- `lib/simpleshop_theme_web/live/shop_live/contact.ex`
- `lib/simpleshop_theme_web/live/shop_live/contact.html.heex`
**Error Pages (1 file):**
- `lib/simpleshop_theme_web/controllers/error_html/404.html.heex`
**Tests (6 files):**
- `test/simpleshop_theme_web/plugs/load_theme_test.exs`
- `test/simpleshop_theme_web/live/shop_live/home_test.exs`
- `test/simpleshop_theme_web/live/shop_live/collection_test.exs`
- `test/simpleshop_theme_web/live/shop_live/product_test.exs`
- `test/simpleshop_theme_web/live/shop_live/cart_test.exs`
- `test/simpleshop_theme_web/live/shop_live/about_test.exs`
### Files to Modify (9 files)
- `lib/simpleshop_theme_web/router.ex` - Add plug, public routes, shop layout
- `lib/simpleshop_theme_web/components/layouts.ex` - Add shop layout function
- `lib/simpleshop_theme/settings.ex` - Add cache invalidation
- `lib/simpleshop_theme/application.ex` - Add cache warming
- `lib/simpleshop_theme_web/live/theme_live/index.ex` - Add "View Shop" link
- `lib/simpleshop_theme_web/live/theme_live/index.html.heex` - Update to use shared components
- `lib/simpleshop_theme_web/live/theme_live/preview_pages.ex` - Remove extracted components
- All 7 preview page templates - Update component paths
- `lib/simpleshop_theme_web/components/shop/header.ex` - Add admin link
## Key Patterns to Follow
1. **CSS Application**: Always use `.shop-root` class with data attributes on root element
2. **Component Reuse**: Use shared components from `components/shop/` directory
3. **Preview Data**: Use `PreviewData` module for mock content until real Products context exists
4. **Cache Strategy**: Always check `CSSCache` before generating CSS
5. **Theme Settings**: Access via `@theme_settings` assign (provided by LoadTheme plug)
6. **Layout**: Use `:shop` layout for all public pages
7. **Testing**: Write tests alongside each LiveView
8. **Validation**: Test each step before moving to next
## Success Criteria
✅ Public storefront accessible at `/`
✅ All pages (home, collection, product, cart, about, contact) render correctly
✅ Theme settings from admin are applied to storefront
✅ CSS is cached for performance
✅ Cache invalidates when theme is saved
✅ Data attributes drive theme styling
✅ All toggle features work (announcement bar, sticky header, etc.)
✅ Grid columns, layout width, and other layout settings work
✅ Logo and header image display correctly
✅ Navigation between admin and storefront works
✅ Empty states handle gracefully (no products)
✅ All tests pass
✅ Mobile responsive
✅ No console errors
## Future Enhancements (After Phase 9)
1. **Products Context** - Add real product management
2. **Orders & Checkout** - Implement cart persistence and checkout flow
3. **Custom Domain Support** - Allow users to use their own domain
4. **SEO Optimization** - Meta tags, structured data, sitemaps
5. **Analytics Integration** - Track visitor behavior
6. **Email Templates** - Order confirmations, shipping notifications
7. **Multi-currency Support** - International selling
8. **Advanced Shipping** - Shipping rates, zones, carriers
9. **Discount Codes** - Promotional codes and sales
10. **Customer Accounts** - Registration, order history, wishlists
## Notes
- This implementation maintains perfect parity with the theme editor preview
- No JavaScript required for theming - purely CSS-based
- Self-contained in SQLite database (no external dependencies)
- Performance optimized with ETS caching
- Ready for multi-shop support in future (architecture supports it)
- Follows Phoenix/LiveView best practices throughout
- Mobile-first, accessible, performant
## Estimated Complexity
- **Step 1** (Extract Components): Medium - Refactoring existing code
- **Step 2** (LoadTheme Plug): Easy - Simple plug implementation
- **Step 3** (Storefront Layout): Easy - Template creation
- **Step 4** (Home Page): Medium - First full LiveView
- **Step 5** (Collection Page): Medium - Filtering/sorting logic
- **Step 6** (Product Page): Medium - Variant selection, gallery
- **Step 7** (Cart Page): Medium - Cart operations
- **Step 8** (Static Pages): Easy - Simple templates
- **Step 9** (Cache Invalidation): Easy - Add function calls
- **Step 10** (Cache Warming): Easy - Application startup hook
- **Step 11** (Navigation Links): Easy - Add links
- **Step 12** (Testing & Polish): Large - Comprehensive testing
**Total Effort**: ~2-3 days for experienced Phoenix developer
## Risk Assessment
**Low Risk:**
- CSS system is proven in preview pages
- No database schema changes needed
- No breaking changes to existing code
- Can test each step independently
**Medium Risk:**
- Component extraction might miss edge cases
- Cache invalidation timing could cause brief inconsistencies
**Mitigation:**
- Comprehensive testing after each step
- Keep preview pages working during refactor
- Add logging for cache operations
- Test cache invalidation thoroughly

View File

@ -1,419 +0,0 @@
# Phase 9: Storefront Integration - Progress Tracker
**Last Updated:** 2026-01-01
**Status:** Not Started
**Current Step:** Step 0 (Preparation)
## Quick Reference
- **Detailed Plan:** `.claude/plans/snuggly-forging-cat.md`
- **Main Plan:** `PLAN.md` (lines 643-690)
- **Spec:** `SPEC.md`
## Progress Overview
- [ ] Step 1: Extract Shared Components
- [ ] Step 2: Create LoadTheme Plug
- [ ] Step 3: Create Storefront Layout
- [ ] Step 4: Create Home Page LiveView
- [ ] Step 5: Create Collection Page LiveView
- [ ] Step 6: Create Product Detail Page (PDP) LiveView
- [ ] Step 7: Create Cart Page LiveView
- [ ] Step 8: Create Static Pages (About, Contact, Error)
- [ ] Step 9: Wire Up CSS Cache Invalidation
- [ ] Step 10: Add Cache Warming on Application Start
- [ ] Step 11: Update Navigation Links
- [ ] Step 12: Testing and Polish
**Completion:** 0/12 steps (0%)
---
## Step-by-Step Progress
### Step 1: Extract Shared Components
**Status:** ❌ Not Started
**Git Commit:** `refactor: extract shared shop components from preview pages`
**Goal:** Move reusable preview components to `components/shop/` for use in both admin and storefront
**Files to Create (5):**
- [ ] `lib/simpleshop_theme_web/components/shop/announcement_bar.ex`
- [ ] `lib/simpleshop_theme_web/components/shop/header.ex`
- [ ] `lib/simpleshop_theme_web/components/shop/footer.ex`
- [ ] `lib/simpleshop_theme_web/components/shop/search_modal.ex`
- [ ] `lib/simpleshop_theme_web/components/shop/product_card.ex`
**Files to Modify (8):**
- [ ] `lib/simpleshop_theme_web/live/theme_live/preview_pages.ex` - Import new components
- [ ] `lib/simpleshop_theme_web/live/theme_live/preview_pages/home.html.heex`
- [ ] `lib/simpleshop_theme_web/live/theme_live/preview_pages/collection.html.heex`
- [ ] `lib/simpleshop_theme_web/live/theme_live/preview_pages/pdp.html.heex`
- [ ] `lib/simpleshop_theme_web/live/theme_live/preview_pages/cart.html.heex`
- [ ] `lib/simpleshop_theme_web/live/theme_live/preview_pages/about.html.heex`
- [ ] `lib/simpleshop_theme_web/live/theme_live/preview_pages/contact.html.heex`
- [ ] `lib/simpleshop_theme_web/live/theme_live/preview_pages/error.html.heex`
**Validation:**
- [ ] Run `mix test test/simpleshop_theme_web/live/theme_live_test.exs`
- [ ] Visit `/admin/theme` - verify all 7 preview pages still render
- [ ] No visual regressions
**Notes:**
---
### Step 2: Create LoadTheme Plug
**Status:** ❌ Not Started
**Git Commit:** `feat: add LoadTheme plug for public storefront`
**Goal:** Create plug that loads theme settings and CSS for every public request
**Files to Create (2):**
- [ ] `lib/simpleshop_theme_web/plugs/load_theme.ex`
- [ ] `test/simpleshop_theme_web/plugs/load_theme_test.exs`
**Files to Modify (1):**
- [ ] `lib/simpleshop_theme_web/router.ex` - Add plug to `:browser` pipeline
**Validation:**
- [ ] Run `mix test test/simpleshop_theme_web/plugs/load_theme_test.exs`
- [ ] Verify assigns available in requests
- [ ] Verify CSS cached and reused
**Notes:**
---
### Step 3: Create Storefront Layout
**Status:** ❌ Not Started
**Git Commit:** `feat: add shop layout with theme CSS injection`
**Goal:** Create dedicated layout for public storefront with theme CSS injection
**Files to Create (1):**
- [ ] `lib/simpleshop_theme_web/components/layouts/shop.html.heex`
**Files to Modify (1):**
- [ ] `lib/simpleshop_theme_web/components/layouts.ex` - Add `shop/1` function
**Validation:**
- [ ] Inspect HTML - verify data attributes present
- [ ] Verify CSS injection works
- [ ] Layout compiles without errors
**Notes:**
---
### Step 4: Create Home Page LiveView
**Status:** ❌ Not Started
**Git Commit:** `feat: add public home page with theme support`
**Goal:** Create public homepage LiveView using real/mock data
**Files to Create (3):**
- [ ] `lib/simpleshop_theme_web/live/shop_live/home.ex`
- [ ] `lib/simpleshop_theme_web/live/shop_live/home.html.heex`
- [ ] `test/simpleshop_theme_web/live/shop_live/home_test.exs`
**Files to Modify (1):**
- [ ] `lib/simpleshop_theme_web/router.ex` - Add route: `live "/", ShopLive.Home, :index`
**Validation:**
- [ ] Visit `/` - verify homepage renders
- [ ] Theme styles applied correctly
- [ ] Announcement bar toggle works
- [ ] Header layout variations work
- [ ] Sticky header toggle works
- [ ] Products display (mock data)
**Notes:**
---
### Step 5: Create Collection Page LiveView
**Status:** ❌ Not Started
**Git Commit:** `feat: add collection/product grid page with filtering`
**Goal:** Create product collection/grid page with filtering and sorting
**Files to Create (3):**
- [ ] `lib/simpleshop_theme_web/live/shop_live/collection.ex`
- [ ] `lib/simpleshop_theme_web/live/shop_live/collection.html.heex`
- [ ] `test/simpleshop_theme_web/live/shop_live/collection_test.exs`
**Files to Modify (1):**
- [ ] `lib/simpleshop_theme_web/router.ex` - Add routes for collections
**Validation:**
- [ ] Visit `/collections` and `/collections/:slug`
- [ ] Filter sidebar works
- [ ] Sort dropdown works
- [ ] Grid columns (2, 3, 4) work
- [ ] Card shadow setting respected
- [ ] Hover image toggle works
**Notes:**
---
### Step 6: Create Product Detail Page (PDP) LiveView
**Status:** ❌ Not Started
**Git Commit:** `feat: add product detail page with gallery and variants`
**Goal:** Create individual product page with gallery, details, add to cart
**Files to Create (3):**
- [ ] `lib/simpleshop_theme_web/live/shop_live/product.ex`
- [ ] `lib/simpleshop_theme_web/live/shop_live/product.html.heex`
- [ ] `test/simpleshop_theme_web/live/shop_live/product_test.exs`
**Files to Modify (1):**
- [ ] `lib/simpleshop_theme_web/router.ex` - Add route: `live "/products/:slug"`
**Validation:**
- [ ] Visit `/products/:slug`
- [ ] Variant selection works
- [ ] Image gallery works
- [ ] Trust badges show/hide based on setting
- [ ] Reviews show/hide based on setting
- [ ] Related products show/hide based on setting
- [ ] Add to cart shows flash
- [ ] Gallery position (left/right) works
**Notes:**
---
### Step 7: Create Cart Page LiveView
**Status:** ❌ Not Started
**Git Commit:** `feat: add shopping cart page with line items`
**Goal:** Create shopping cart page with line items and checkout
**Files to Create (3):**
- [ ] `lib/simpleshop_theme_web/live/shop_live/cart.ex`
- [ ] `lib/simpleshop_theme_web/live/shop_live/cart.html.heex`
- [ ] `test/simpleshop_theme_web/live/shop_live/cart_test.exs`
**Files to Modify (1):**
- [ ] `lib/simpleshop_theme_web/router.ex` - Add route: `live "/cart"`
**Validation:**
- [ ] Visit `/cart`
- [ ] Quantity update works
- [ ] Remove item works
- [ ] Price calculations correct
- [ ] Empty cart state works
- [ ] Checkout button shows flash
- [ ] Button style setting respected
**Notes:**
---
### Step 8: Create Static Pages (About, Contact, Error)
**Status:** ❌ Not Started
**Git Commit:** `feat: add static pages (about, contact, 404) with theme support`
**Goal:** Create remaining static pages
**Files to Create (6):**
- [ ] `lib/simpleshop_theme_web/live/shop_live/about.ex`
- [ ] `lib/simpleshop_theme_web/live/shop_live/about.html.heex`
- [ ] `lib/simpleshop_theme_web/live/shop_live/contact.ex`
- [ ] `lib/simpleshop_theme_web/live/shop_live/contact.html.heex`
- [ ] `test/simpleshop_theme_web/live/shop_live/about_test.exs`
- [ ] `test/simpleshop_theme_web/live/shop_live/contact_test.exs`
**Files to Modify (2):**
- [ ] `lib/simpleshop_theme_web/router.ex` - Add routes
- [ ] `lib/simpleshop_theme_web/controllers/error_html.ex` - Add 404 template (or create if missing)
**Validation:**
- [ ] Visit `/about` - page renders
- [ ] Visit `/contact` - form works
- [ ] Visit invalid URL - 404 shows with theme
- [ ] All pages respect theme settings
**Notes:**
---
### Step 9: Wire Up CSS Cache Invalidation
**Status:** ❌ Not Started
**Git Commit:** `feat: add CSS cache invalidation on theme save`
**Goal:** Ensure CSS cache invalidates when theme settings saved
**Files to Modify (2):**
- [ ] `lib/simpleshop_theme/settings.ex` - Add cache invalidation to `update_theme_settings/1`
- [ ] `lib/simpleshop_theme_web/live/theme_live/index.ex` - Ensure save triggers invalidation
**Validation:**
- [ ] Change theme in admin
- [ ] Save theme
- [ ] Visit storefront
- [ ] Verify changes reflected immediately
- [ ] Check cache being used
**Notes:**
---
### Step 10: Add Cache Warming on Application Start
**Status:** ❌ Not Started
**Git Commit:** `feat: add CSS cache warming on application startup`
**Goal:** Pre-generate and cache theme CSS when app starts
**Files to Modify (1):**
- [ ] `lib/simpleshop_theme/application.ex` - Add cache warming after supervisor start
**Validation:**
- [ ] Restart application
- [ ] Check logs for "Theme CSS cache warmed successfully"
- [ ] Visit storefront immediately (should be fast)
- [ ] No DB queries for CSS on first request
**Notes:**
---
### Step 11: Update Navigation Links
**Status:** ❌ Not Started
**Git Commit:** `feat: add navigation between admin and storefront`
**Goal:** Connect theme editor to storefront and vice versa
**Files to Modify (2):**
- [ ] `lib/simpleshop_theme_web/components/shop/header.ex` - Add admin link when authenticated
- [ ] `lib/simpleshop_theme_web/live/theme_live/index.html.heex` - Add "View Shop" link
**Validation:**
- [ ] When logged in on storefront, "Edit Theme" link appears
- [ ] Click link - navigates to theme editor
- [ ] In theme editor, click "View Shop" link
- [ ] Opens storefront in new tab
**Notes:**
---
### Step 12: Testing and Polish
**Status:** ❌ Not Started
**Git Commit:** `test: add comprehensive tests and polish for Phase 9`
**Goal:** Comprehensive testing and UX improvements
**Testing Areas:**
- [ ] All storefront LiveViews tested
- [ ] Plug behavior tested
- [ ] Cache invalidation flow tested
- [ ] Theme application across all pages tested
- [ ] Responsive behavior tested
**Polish Areas:**
- [ ] Loading states added
- [ ] Error handling complete
- [ ] Performance optimized
- [ ] Accessibility checked
- [ ] Mobile tested
- [ ] Cross-browser tested
**Validation:**
- [ ] Run `mix test` - all tests pass
- [ ] No console errors
- [ ] Good Lighthouse scores
- [ ] Responsive on all devices
**Notes:**
---
## Git Commit Log
Track all commits made during Phase 9 implementation:
```
# Commits will be added here as we progress
# Format: [YYYY-MM-DD HH:MM] <commit-hash> <commit-message>
```
---
## Issues / Blockers
Track any issues encountered:
- None yet
---
## Future Enhancements (Post-Phase 9)
1. Products Context - Add real product management
2. Orders & Checkout - Cart persistence and checkout flow
3. Custom Domain Support
4. SEO Optimization
5. Analytics Integration
6. Email Templates
7. Multi-currency Support
8. Advanced Shipping
9. Discount Codes
10. Customer Accounts
---
## Context Preservation
**Key Architectural Decisions:**
- CSS applied via `.shop-root` class with data attributes
- Same three-layer CSS system as theme editor
- LoadTheme plug provides `@theme_settings` and `@generated_css` assigns
- CSS cached in ETS via `CSSCache` GenServer
- Preview data used until real Products context exists
- Shared components in `components/shop/` directory
**Critical Files:**
- Theme editor: `lib/simpleshop_theme_web/live/theme_live/index.ex`
- CSS generator: `lib/simpleshop_theme/theme/css_generator.ex`
- Settings context: `lib/simpleshop_theme/settings.ex`
- Preview data: `lib/simpleshop_theme/theme/preview_data.ex`
**Current State (as of last update):**
- Theme editor fully functional at `/admin/theme`
- 8 presets working with real-time preview
- All customization options implemented
- Logo/header uploads with BLOB storage working
- SVG recoloring functional
- No public storefront routes yet (Phase 9 not started)
---
## How to Use This File
1. **Starting a new step:** Update the step status to "🚧 In Progress"
2. **Completing files:** Check off files as created/modified
3. **Finishing a step:**
- Mark step as "✅ Complete"
- Update completion percentage
- Make git commit with specified message
- Add commit to Git Commit Log section
4. **Encountering issues:** Add to Issues/Blockers section
5. **Taking notes:** Add to Notes field for each step
**For new conversations:** Read this file first to understand current progress and context.

964
PLAN.md
View File

@ -1,964 +0,0 @@
# SimpleShop Theme - Implementation Plan
## Overview
Integrate the complete theme feature from `theme-demo-v28.html` into the Phoenix LiveView application. The system will provide 9 curated presets and extensive customization options with real-time preview. All data (including uploaded images) will be stored in a single SQLite database file.
**Key Concept:** This codebase IS the shop (like WordPress is one site). Multiple users can manage it, but there's only one shop/site per deployment.
## Core Architectural Decisions
### 1. Database Storage Strategy
- **Images as BLOBs in SQLite** - Complete self-containment in single database file
- **Application-level settings** - NO Shop model, just Settings tables for the site
- **Multiple admin users** - Any authenticated user can manage theme (no ownership model)
- **SVG stored as both BLOB and TEXT** - Enable recoloring feature
### 2. CSS Architecture
- **Three-layer CSS system** using Custom Properties:
- Layer 1: Primitives (static) - spacing, fonts, radii
- Layer 2: Theme tokens (dynamic) - generated from settings
- Layer 3: Semantic aliases (static) - friendly variable names
- **Inline `<style>` generation** in LiveView for instant preview
- **ETS cache** for storefront CSS (invalidate on save)
### 3. LiveView Structure
- **Single LiveView** (`ThemeLive.Index`) with nested function components
- **No iframe** - Direct preview in same LiveView using data attributes
- **Smart preview data** - Mock data initially, switch to real products when available
- **Optimistic UI** - Update preview immediately, persist on "Save" button
- **Idiomatic Phoenix/LiveView** - Use Tailwind utilities where possible, CSS variables for dynamic theming
### 4. Development Workflow
- **Semantic git commits** - Commit each logical step for easy rollback
- **Test-driven** - Write Phoenix tests alongside implementation (ExUnit, ConnCase, LiveViewTest)
- **Manual verification** - Test in browser after each phase
- **Progressive enhancement** - Each commit should leave app in working state
## Database Schema
**Philosophy:** No Shop model - this app IS the shop. Settings are site-wide, managed by any admin user.
### Migration 1: Create Settings Table
**File:** `priv/repo/migrations/YYYYMMDDHHMMSS_create_settings.exs`
```elixir
defmodule SimpleshopTheme.Repo.Migrations.CreateSettings do
use Ecto.Migration
def change do
create table(:settings, primary_key: false) do
add :id, :binary_id, primary_key: true
add :key, :string, null: false # e.g., "site_name", "theme_settings"
add :value, :text, null: false # JSON or plain text
add :value_type, :string, null: false, default: "string" # string, json, integer, boolean
timestamps(type: :utc_datetime)
end
create unique_index(:settings, [:key])
end
end
```
### Migration 2: Create Images Table
**File:** `priv/repo/migrations/YYYYMMDDHHMMSS_create_images.exs`
```elixir
defmodule SimpleshopTheme.Repo.Migrations.CreateImages do
use Ecto.Migration
def change do
create table(:images, primary_key: false) do
add :id, :binary_id, primary_key: true
add :image_type, :string, null: false # "logo" | "header" | "product"
add :filename, :string, null: false
add :content_type, :string, null: false
add :file_size, :integer, null: false
# BLOB storage
add :data, :binary, null: false
# SVG support
add :is_svg, :boolean, default: false
add :svg_content, :text # For recoloring
# Optional: thumbnail for admin UI performance
add :thumbnail_data, :binary
timestamps(type: :utc_datetime)
end
create index(:images, [:image_type])
end
end
```
## File Structure
### New Contexts and Schemas
```
lib/simpleshop_theme/
├── settings/
│ ├── setting.ex # Setting schema (key-value store)
│ └── theme_settings.ex # Embedded schema for theme settings
├── settings.ex # Settings context (site-wide config API)
├── media/
│ ├── image.ex # Image schema (replaces ShopImage)
│ └── svg_recolorer.ex # Recolor SVG logos
├── media.ex # Media context (image uploads/serving)
└── theme/
├── presets.ex # Preset definitions (9 presets)
├── css_generator.ex # Generate CSS from settings
├── css_cache.ex # ETS cache GenServer
└── preview_data.ex # Smart preview (mock → real products)
```
### LiveView Components
```
lib/simpleshop_theme_web/live/theme_live/
├── index.ex # Main LiveView
├── index.html.heex # Template
├── preset_selector.ex # 9 preset buttons (function component)
├── branding_section.ex # Logo/header uploads
├── customization_panel.ex # Accordion with all options
├── preview_frame.ex # Preview area with page switcher
└── preview_pages/
├── home.html.heex # Preview homepage
├── collection.html.heex # Preview product grid
├── pdp.html.heex # Preview product detail page
├── cart.html.heex # Preview cart
├── about.html.heex # Preview about page
├── contact.html.heex # Preview contact page
└── error.html.heex # Preview 404 page
```
### Controllers
```
lib/simpleshop_theme_web/controllers/
└── image_controller.ex # Serve images from BLOBs
```
### Static Assets & Tests
```
priv/static/css/
├── theme-primitives.css # Layer 1: Fixed CSS variables
└── theme-semantic.css # Layer 3: Semantic aliases
assets/css/
└── app.css # Import theme CSS here
test/simpleshop_theme/
├── settings_test.exs # Settings context tests
├── media_test.exs # Media context tests
└── theme/
├── css_generator_test.exs # CSS generation tests
├── presets_test.exs # Preset validation tests
└── preview_data_test.exs # Preview data tests
test/simpleshop_theme_web/
├── controllers/
│ └── image_controller_test.exs
└── live/
└── theme_live_test.exs # LiveView integration tests
```
## Implementation Status
### Completed Phases (1-8): ✅
- ✅ Phase 1: Database Foundation
- ✅ Phase 2: CSS Architecture
- ✅ Phase 3: Smart Preview Data
- ✅ Phase 4: Theme LiveView (Basic)
- ✅ Phase 5: Preview Pages
- ✅ Phase 6: Customization Options
- ✅ Phase 6.5: Fix Theme Visual Application
- ✅ Phase 7: File Uploads (Logo & Header)
- ✅ Phase 8: Persistence & Polish
### Current Phase: Phase 9 - Storefront Integration 🚧
**See detailed Phase 9 plan at:** `.claude/plans/snuggly-forging-cat.md`
**Phase 9 Goal:** Apply the theme system to the actual public-facing storefront
**Key deliverables:**
- Public storefront routes (`/`, `/products/:slug`, `/collections`, `/cart`, etc.)
- Storefront LiveViews using real/mock data
- LoadTheme plug to inject theme settings and CSS
- CSS cache integration for performance
- Navigation between admin theme editor and public shop
- All 7 pages working on storefront (home, collection, product, cart, about, contact, error)
---
## Implementation Phases (Details)
### Phase 1: Database Foundation ✅
**Goal:** Set up Settings and Media models for site-wide configuration
**Steps:**
1. Create migrations for `settings` and `images` tables
2. Run migrations
3. Create `lib/simpleshop_theme/settings/setting.ex` schema
4. Create `lib/simpleshop_theme/settings/theme_settings.ex` embedded schema
5. Create `lib/simpleshop_theme/settings.ex` context with:
- `get_setting/2` - Get setting by key with default
- `put_setting/3` - Set a setting value
- `get_theme_settings/0` - Get theme settings as struct
- `update_theme_settings/1` - Update theme settings
6. Create `lib/simpleshop_theme/media/image.ex` schema
7. Create `lib/simpleshop_theme/media.ex` context with:
- `upload_image/2` - Upload image with type
- `get_image/1` - Get image by ID
- `delete_image/1` - Delete image
8. Create `lib/simpleshop_theme/theme/presets.ex` with all 9 preset definitions
9. Create seed data in `priv/repo/seeds.exs` for default theme settings
10. Write tests:
- `test/simpleshop_theme/settings_test.exs`
- `test/simpleshop_theme/media_test.exs`
**Files to create:**
- `priv/repo/migrations/*_create_settings.exs`
- `priv/repo/migrations/*_create_images.exs`
- `lib/simpleshop_theme/settings/setting.ex`
- `lib/simpleshop_theme/settings/theme_settings.ex`
- `lib/simpleshop_theme/settings.ex`
- `lib/simpleshop_theme/media/image.ex`
- `lib/simpleshop_theme/media.ex`
- `lib/simpleshop_theme/theme/presets.ex`
- `test/simpleshop_theme/settings_test.exs`
- `test/simpleshop_theme/media_test.exs`
**Files to modify:**
- `priv/repo/seeds.exs` - Add default theme settings
**Git commit:** `feat: add Settings and Media contexts with theme settings schema`
**Validation:**
- Run tests: `mix test`
- Run `iex -S mix` and test Settings API
- Run seeds: `mix run priv/repo/seeds.exs`
---
### Phase 2: CSS Architecture ✓
**Goal:** Set up CSS generation system using Phoenix/Tailwind best practices
**Steps:**
1. Create `priv/static/css/theme-primitives.css` with primitive CSS variables from demo
2. Create `priv/static/css/theme-semantic.css` with semantic aliases
3. Update `assets/css/app.css` to import theme CSS files
4. Create `lib/simpleshop_theme/theme/css_generator.ex` module:
- `generate/1` - Takes ThemeSettings, returns CSS custom properties string
- Helper functions for each theme token (mood, typography, shape, density)
- `hex_to_hsl/1` for accent color conversion
- Use Tailwind-friendly approach (CSS variables that Tailwind can reference)
5. Create `lib/simpleshop_theme/theme/css_cache.ex` GenServer with ETS table
6. Add `CSSCache` to supervision tree in `lib/simpleshop_theme/application.ex`
7. Write tests:
- `test/simpleshop_theme/theme/css_generator_test.exs`
- `test/simpleshop_theme/theme/presets_test.exs`
**Files to create:**
- `priv/static/css/theme-primitives.css`
- `priv/static/css/theme-semantic.css`
- `lib/simpleshop_theme/theme/css_generator.ex`
- `lib/simpleshop_theme/theme/css_cache.ex`
- `test/simpleshop_theme/theme/css_generator_test.exs`
- `test/simpleshop_theme/theme/presets_test.exs`
**Files to modify:**
- `assets/css/app.css`
- `lib/simpleshop_theme/application.ex`
**Git commit:** `feat: add CSS generation system with custom properties and ETS cache`
**Validation:**
- Run tests: `mix test test/simpleshop_theme/theme/`
- Generate CSS for each preset in IEx, verify output
- Check CSS variables work with Tailwind
---
### Phase 3: Smart Preview Data ✓
**Goal:** Create preview data system that uses real data when available, falls back to mock
**Steps:**
1. Create `lib/simpleshop_theme/theme/preview_data.ex` with:
- `products/0` - Real products if exist, else mock products
- `cart_items/0` - Mock cart contents
- `testimonials/0` - Mock testimonials for homepage
- `categories/0` - Mock product categories
- `has_real_products?/0` - Check if shop has products
- Mock data uses placeholder images from `https://placehold.co/`
2. Write tests:
- `test/simpleshop_theme/theme/preview_data_test.exs`
**Files to create:**
- `lib/simpleshop_theme/theme/preview_data.ex`
- `test/simpleshop_theme/theme/preview_data_test.exs`
**Git commit:** `feat: add smart preview data system with mock fallback`
**Validation:**
- Run tests: `mix test test/simpleshop_theme/theme/preview_data_test.exs`
- Call functions in IEx, verify data structure
- Verify falls back to mock when no products exist
---
### Phase 4: Theme LiveView (Basic) ✓
**Goal:** Get basic theme editor working with preset switching
**Steps:**
1. Create `lib/simpleshop_theme_web/live/theme_live/index.ex`:
- Mount: Load theme settings from Settings context
- Assign: `:theme_settings`, `:preview_page`, `:generated_css`
- Event handlers: `apply_preset`, `change_preview_page`, `save_theme`
2. Create `lib/simpleshop_theme_web/live/theme_live/index.html.heex`:
- Two-column layout (controls sidebar + preview area)
- Render preset buttons using Tailwind/daisyUI components
- Render preview frame with generated CSS in `<style>` tag
- Use Phoenix.Component for reusable pieces
3. Add route to `lib/simpleshop_theme_web/router.ex`:
- `live "/admin/theme", ThemeLive.Index` (authenticated)
4. Add "Theme" link to user menu/navigation
5. Write tests:
- `test/simpleshop_theme_web/live/theme_live_test.exs`
**Files to create:**
- `lib/simpleshop_theme_web/live/theme_live/index.ex`
- `lib/simpleshop_theme_web/live/theme_live/index.html.heex`
- `test/simpleshop_theme_web/live/theme_live_test.exs`
**Files to modify:**
- `lib/simpleshop_theme_web/router.ex`
- `lib/simpleshop_theme_web/components/layouts.ex` (add nav link)
**Git commit:** `feat: add Theme LiveView with preset switching`
**Validation:**
- Run tests: `mix test test/simpleshop_theme_web/live/theme_live_test.exs`
- Visit `/admin/theme`, click presets, verify CSS changes
- Test authentication requirement
---
### Phase 5: Preview Pages ✓
**Goal:** Create all 7 preview page templates
**Steps:**
1. Create preview page templates by porting HTML from `theme-demo-v28.html`:
- `lib/simpleshop_theme_web/live/theme_studio_live/preview_pages/home.html.heex`
- `lib/simpleshop_theme_web/live/theme_studio_live/preview_pages/collection.html.heex`
- `lib/simpleshop_theme_web/live/theme_studio_live/preview_pages/pdp.html.heex`
- `lib/simpleshop_theme_web/live/theme_studio_live/preview_pages/cart.html.heex`
- `lib/simpleshop_theme_web/live/theme_studio_live/preview_pages/about.html.heex`
- `lib/simpleshop_theme_web/live/theme_studio_live/preview_pages/contact.html.heex`
- `lib/simpleshop_theme_web/live/theme_studio_live/preview_pages/error.html.heex`
2. Port CSS from demo to theme CSS files (primitives, semantic)
3. Wire up mock data in templates
4. Implement page switcher buttons in preview frame
5. Add data attributes system (`data-mood`, `data-typography`, etc.) to preview container
**Files to create:**
- 7 preview page `.html.heex` files in `preview_pages/` directory
**Files to modify:**
- `lib/simpleshop_theme_web/live/theme_studio_live/index.html.heex` - Add page switcher
- CSS files - Port all styles from demo
**Git commit:** `feat: add preview page templates with theme styling`
**Validation:**
- Run tests: `mix test test/simpleshop_theme_web/live/theme_live_test.exs`
- Switch between all 7 pages, verify they render correctly
- Verify preview data shows (mock or real)
---
### Phase 6: Customization Options ✓
**Goal:** Add all customization controls beyond presets
**Steps:**
1. Create option group components in `index.html.heex`:
- Mood selector (4 options: neutral, warm, cool, dark)
- Typography selector (7 options: clean, editorial, modern, classic, friendly, minimal, impulse)
- Shape selector (4 options: sharp, soft, round, pill)
- Density selector (3 options: spacious, balanced, compact)
- Grid columns selector (3 options: 2, 3, 4)
- Header layout selector (3 options: standard, centered, minimal)
2. Add color pickers:
- Accent color (with live preview)
- Secondary accent color
- Sale color
3. Add advanced options accordion:
- Font size (small, medium, large)
- Heading weight (light, regular, bold)
- Layout width (contained, wide, full)
- Button style (filled, outline, soft)
- Card shadow (none, subtle, pronounced)
- Product text align (left, center)
- Image aspect ratio (square, portrait, landscape)
4. Add feature toggles:
- Announcement bar
- Sticky header
- Hover image
- Quick add button
- Show prices
- PDP trust badges
- PDP reviews
- PDP related products
5. Implement `update_setting` event handler in LiveView
6. Wire all controls to update theme settings and regenerate CSS
**Files to modify:**
- `lib/simpleshop_theme_web/live/theme_live/index.ex` - Add `update_setting` handler
- `lib/simpleshop_theme_web/live/theme_live/index.html.heex` - Add all controls
- `test/simpleshop_theme_web/live/theme_live_test.exs` - Add tests for customization
**Git commit:** `feat: add full customization controls with real-time preview`
**Validation:**
- Run tests: `mix test test/simpleshop_theme_web/live/theme_live_test.exs`
- Change each option, verify preview updates instantly
- Test all toggles work correctly
---
### Phase 6.5: Fix Theme Visual Application 🔧
**Goal:** Fix the theme controls so they actually visually affect the preview pages
**Problem:** Theme controls update the database but don't visually change the preview. The Phoenix implementation is missing the data-attribute-based CSS system that the demo uses.
**Root Cause Analysis:**
The demo HTML uses data attributes (`data-mood="warm"`, `data-typography="editorial"`, etc.) on the `.preview-frame` element, and the CSS uses attribute selectors like `.preview-frame[data-mood="warm"] { ... }` to apply styles. The Phoenix LiveView implementation is missing these data attributes entirely.
**Discovered Issues:**
| Issue | Status | Root Cause |
|-------|--------|------------|
| Fonts don't change | ❌ Broken | 1. Google Fonts not loaded<br>2. No data attributes on preview-frame |
| Mood/colors don't work (except dark) | ❌ Broken | No data attributes on preview-frame |
| Shape doesn't work | ❌ Broken | No data attributes on preview-frame |
| Density doesn't work | ❌ Broken | No data attributes on preview-frame |
| Grid columns 4 shows as 2 | ❌ Broken | Tailwind can't process dynamic class interpolation |
| Accent color doesn't update | ⚠️ Partial | CSS generated but may be overridden |
| Header layout has no component | ❌ Missing | No header component in preview pages |
**Steps:**
1. **Add Google Fonts to root layout** (`lib/simpleshop_theme_web/components/layouts/root.html.heex`):
```heex
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,400;9..144,500;9..144,600;9..144,700&family=Inter:wght@400;500;600;700&family=Libre+Baskerville:wght@400;700&family=Nunito:wght@400;600;700&family=Nunito+Sans:opsz,wght@6..12,300;6..12,400;6..12,500;6..12,600&family=Outfit:wght@300;400;500;600&family=Source+Sans+3:wght@400;500;600&family=Space+Grotesk:wght@400;500;600&display=swap" rel="stylesheet">
```
2. **Add data attributes to preview frame** (`lib/simpleshop_theme_web/live/theme_live/index.html.heex:205`):
```heex
<div class="preview-frame bg-white overflow-auto"
data-mood={@theme_settings.mood}
data-typography={@theme_settings.typography}
data-shape={@theme_settings.shape}
data-density={@theme_settings.density}
data-grid={@theme_settings.grid_columns}
data-header={@theme_settings.header_layout}
style="min-height: 600px; max-height: calc(100vh - 200px);">
```
3. **Copy CSS from demo file** (`theme-demo-v28.html` lines 81-217) to create `priv/static/css/theme-layer2-attributes.css`:
- All the `.preview-frame[data-mood="..."]` rules
- All the `.preview-frame[data-typography="..."]` rules
- All the `.preview-frame[data-shape="..."]` rules
- All the `.preview-frame[data-density="..."]` rules
- All the `.preview-frame[data-grid="..."]` rules
- All the `.preview-frame[data-header="..."]` rules
4. **Import the new CSS file** in `assets/css/app.css`:
```css
@import "../priv/static/css/theme-primitives.css";
@import "../priv/static/css/theme-layer2-attributes.css";
@import "../priv/static/css/theme-semantic.css";
```
5. **Fix grid columns dynamic classes** - Replace string interpolation with conditional logic in all preview pages:
```heex
<!-- BEFORE (broken): -->
<div class={"grid gap-6 grid-cols-1 sm:grid-cols-2 lg:grid-cols-#{@theme_settings.grid_columns}"}>
<!-- AFTER (working): -->
<div class={["grid gap-6 grid-cols-1 sm:grid-cols-2",
case @theme_settings.grid_columns do
"2" -> "lg:grid-cols-2"
"3" -> "lg:grid-cols-3"
"4" -> "lg:grid-cols-4"
_ -> "lg:grid-cols-3"
end]}>
```
6. **Add header component** to preview pages - Create a header section that responds to `data-header` attribute:
```heex
<header class="theme-header" style="background-color: var(--t-surface-raised); border-bottom: 1px solid var(--t-border-subtle);">
<!-- Header content that adapts based on data-header="standard|centered|minimal" -->
</header>
```
7. **Update CSSGenerator** to work alongside attribute-based CSS:
- Keep generating accent color HSL variables (these are used by all themes)
- Remove mood/typography/shape/density generation (now handled by attribute CSS)
- Focus on dynamic values like accent_color, secondary_accent_color, sale_color
8. **Test all controls** in browser to verify visual changes work
**Files to create:**
- `priv/static/css/theme-layer2-attributes.css` - Attribute-based theme CSS from demo
**Files to modify:**
- `lib/simpleshop_theme_web/components/layouts/root.html.heex` - Add Google Fonts
- `lib/simpleshop_theme_web/live/theme_live/index.html.heex` - Add data attributes to preview-frame
- `assets/css/app.css` - Import new CSS file
- `lib/simpleshop_theme/theme/css_generator.ex` - Simplify to focus on color variables
- All preview page files - Fix grid columns dynamic classes
- All preview page files - Add header component
**Git commit:** `fix: add data attributes and attribute-based CSS to make theme controls work visually`
**Validation:**
- Change mood - verify background colors change
- Change typography - verify fonts change
- Change shape - verify button/card border radius changes
- Change density - verify spacing changes
- Change grid columns - verify all 3 options (2, 3, 4) work correctly
- Change accent color - verify primary buttons change color
- Change header layout - verify header structure changes
---
### Phase 7: File Uploads (Logo & Header) ✓
**Goal:** Enable logo and header image uploads with database storage
**Steps:**
1. Add dependency to `mix.exs`: `{:image, "~> 0.54"}` for thumbnail generation
2. Implement SVG detection and text storage in `image.ex` changeset
3. Add Media context functions for logo/header:
- Update `upload_image/2` to handle thumbnails
- Add `get_logo/0`, `get_header/0` convenience functions
4. Create `lib/simpleshop_theme_web/controllers/image_controller.ex`:
- `show/2` - Serve image BLOB with proper content-type and caching
- `recolored_svg/2` - Serve recolored SVG
5. Create `lib/simpleshop_theme/media/svg_recolorer.ex` for SVG color manipulation
6. Add routes for image serving in router
7. Configure LiveView uploads in `index.ex`:
- `:logo_upload` - Accept PNG, JPG, WebP, SVG (max 2MB)
- `:header_upload` - Accept PNG, JPG, WebP (max 5MB)
8. Add upload controls to branding section in template using daisyUI components:
- Logo mode selector (text-only, logo+text, logo-only, header-image, logo+header)
- Logo upload with preview
- Logo size slider (24-120px)
- SVG recolor toggle + color picker
- Header image upload with preview
- Header zoom slider (100-200%)
- Header position sliders (X and Y: 0-100%)
9. Implement upload event handlers
10. Display uploaded images in preview
11. Write tests:
- `test/simpleshop_theme_web/controllers/image_controller_test.exs`
- `test/simpleshop_theme/media/svg_recolorer_test.exs`
**Files to create:**
- `lib/simpleshop_theme_web/controllers/image_controller.ex`
- `lib/simpleshop_theme/media/svg_recolorer.ex`
- `test/simpleshop_theme_web/controllers/image_controller_test.exs`
- `test/simpleshop_theme/media/svg_recolorer_test.exs`
**Files to modify:**
- `lib/simpleshop_theme/media.ex` - Add logo/header helpers
- `lib/simpleshop_theme/media/image.ex` - SVG handling
- `lib/simpleshop_theme_web/live/theme_live/index.ex` - Upload config and handlers
- `lib/simpleshop_theme_web/live/theme_live/index.html.heex` - Branding section UI
- `lib/simpleshop_theme_web/router.ex` - Image serving routes
- `mix.exs` - Add `:image` dependency
- `test/simpleshop_theme_web/live/theme_live_test.exs` - Add upload tests
**Git commit:** `feat: add image uploads with BLOB storage and SVG recoloring`
**Validation:**
- Run tests: `mix test`
- Upload logo and header images
- Verify BLOB storage in database
- Test SVG recoloring works
- Verify images display in preview
- Test image serving with proper cache headers
---
### Phase 8: Persistence & Polish ✓
**Goal:** Complete save functionality and UX polish
**Steps:**
1. Implement "Save Theme" button and handler:
- Show loading state during save
- Flash success/error message
- Invalidate CSS cache
2. Add "Reset to Preset" functionality
3. Implement unsaved changes warning
4. Add keyboard shortcuts (Cmd+S to save)
5. Debounce color picker inputs (300ms) to avoid excessive renders
6. Add loading skeletons for preview
7. Handle edge cases:
- File too large error
- Invalid file type error
- Network errors
8. Add client-side validation
9. Improve mobile responsiveness of editor
10. Add tooltips/help text for complex options
**Files to modify:**
- `lib/simpleshop_theme_web/live/theme_live/index.ex` - Save logic, debouncing
- `lib/simpleshop_theme_web/live/theme_live/index.html.heex` - UI polish
- JavaScript hooks for keyboard shortcuts (if needed)
- `test/simpleshop_theme_web/live/theme_live_test.exs` - Test persistence
**Git commit:** `feat: add theme persistence with UX polish and validation`
**Validation:**
- Run tests: `mix test`
- Save theme, reload page, verify settings persist
- Test unsaved changes warning
- Test keyboard shortcuts
- Verify error handling for edge cases
- Test mobile responsiveness
---
### Phase 9: Storefront Integration 🚧
**Goal:** Apply theme to actual public-facing shop
**Status:** Ready to implement - See detailed plan in `.claude/plans/snuggly-forging-cat.md`
**High-level overview:**
1. Extract shared components from preview pages (header, footer, product card, etc.)
2. Create LoadTheme plug to inject theme settings and CSS into all public requests
3. Create dedicated shop layout with `.shop-root` class and data attributes
4. Build storefront LiveViews for all pages:
- Home (`/`)
- Collection (`/collections/:slug`)
- Product Detail (`/products/:slug`)
- Cart (`/cart`)
- About (`/about`)
- Contact (`/contact`)
- Error (404 page)
5. Wire up CSS cache invalidation when theme is saved
6. Add cache warming on application startup
7. Add navigation links between admin and storefront
8. Comprehensive testing and polish
**Key files to create (23 files):**
- 5 shared component modules in `components/shop/`
- 1 LoadTheme plug
- 1 shop layout template
- 6 storefront LiveView modules + templates
- 1 error page template
- 6 test files
**Key files to modify (9 files):**
- Router (add public routes and plug)
- Settings context (add cache invalidation)
- Application (add cache warming)
- Theme editor (add "View Shop" link)
- Preview pages (use shared components)
**Detailed implementation plan:** See `.claude/plans/snuggly-forging-cat.md` for 12-step implementation guide with code examples, validation steps, and architectural decisions.
**Git commit strategy:** Commit after each major step (components extraction, plug creation, each LiveView, etc.)
**Validation approach:**
- Test theme editor still works after component extraction
- Test each storefront page individually as built
- Verify CSS cache invalidation flow
- Test navigation between admin and storefront
- Comprehensive testing in Step 12
---
## Technical Implementation Details
### CSS Generation Example
```elixir
# lib/simpleshop_theme/theme/css_generator.ex
defmodule SimpleshopTheme.Theme.CSSGenerator do
alias SimpleshopTheme.Settings.ThemeSettings
def generate(%ThemeSettings{} = settings) do
"""
.preview-frame, .shop-root {
#{generate_accent(settings.accent_color)}
#{generate_mood(settings.mood)}
#{generate_typography(settings.typography)}
#{generate_shape(settings.shape)}
#{generate_density(settings.density)}
}
"""
end
defp generate_accent(hex) do
{h, s, l} = hex_to_hsl(hex)
"""
--t-accent-h: #{h};
--t-accent-s: #{s}%;
--t-accent-l: #{l}%;
--t-accent: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
"""
end
defp hex_to_hsl("#" <> hex), do: hex_to_hsl(hex)
defp hex_to_hsl(hex) when byte_size(hex) == 6 do
{r, ""} = Integer.parse(String.slice(hex, 0..1), 16)
{g, ""} = Integer.parse(String.slice(hex, 2..3), 16)
{b, ""} = Integer.parse(String.slice(hex, 4..5), 16)
r = r / 255
g = g / 255
b = b / 255
max = Enum.max([r, g, b])
min = Enum.min([r, g, b])
l = (max + min) / 2
if max == min do
{0, 0, round(l * 100)}
else
d = max - min
s = if l > 0.5, do: d / (2 - max - min), else: d / (max + min)
h = cond do
max == r -> (g - b) / d + (if g < b, do: 6, else: 0)
max == g -> (b - r) / d + 2
max == b -> (r - g) / d + 4
end
{round(h * 60), round(s * 100), round(l * 100)}
end
end
defp generate_mood("neutral"), do: """
--t-surface-base: #ffffff;
--t-surface-raised: #ffffff;
--t-text-primary: #171717;
--t-border-default: #e5e5e5;
"""
defp generate_mood("warm"), do: """
--t-surface-base: #fdf8f3;
--t-surface-raised: #fffcf8;
--t-text-primary: #1c1917;
--t-border-default: #e7e0d8;
"""
defp generate_mood("cool"), do: """
--t-surface-base: #f4f7fb;
--t-surface-raised: #f8fafc;
--t-text-primary: #0f172a;
--t-border-default: #d4dce8;
"""
defp generate_mood("dark"), do: """
--t-surface-base: #0a0a0a;
--t-surface-raised: #171717;
--t-text-primary: #fafafa;
--t-border-default: #262626;
--p-shadow-strength: 0.25;
"""
# Similar for typography, shape, density...
end
```
### LiveView Upload Configuration
```elixir
# In mount/3
socket =
socket
|> allow_upload(:logo_upload,
accept: ~w(.png .jpg .jpeg .webp .svg),
max_entries: 1,
max_file_size: 2_000_000,
auto_upload: true
)
|> allow_upload(:header_upload,
accept: ~w(.png .jpg .jpeg .webp),
max_entries: 1,
max_file_size: 5_000_000,
auto_upload: true
)
# Handle upload completion
def handle_event("logo_uploaded", _params, socket) do
uploaded_files =
consume_uploaded_entries(socket, :logo_upload, fn %{path: path}, entry ->
file_binary = File.read!(path)
{:ok, image} = Media.upload_image(%{
image_type: "logo",
filename: entry.client_name,
content_type: entry.client_type,
file_size: entry.client_size,
data: file_binary
})
{:ok, image}
end)
case uploaded_files do
[image | _] ->
# Update theme settings to reference this image
settings = socket.assigns.theme_settings
{:ok, _} = Settings.update_theme_settings(%{settings | logo_image_id: image.id})
{:noreply, assign(socket, :logo_image, image)}
[] ->
{:noreply, socket}
end
end
```
### Image Controller Serving
```elixir
defmodule SimpleshopThemeWeb.ImageController do
use SimpleshopThemeWeb, :controller
alias SimpleshopTheme.Media
def show(conn, %{"id" => id}) do
case Media.get_image(id) do
nil ->
send_resp(conn, 404, "Image not found")
image ->
conn
|> put_resp_content_type(image.content_type)
|> put_resp_header("cache-control", "public, max-age=31536000, immutable")
|> put_resp_header("etag", "\"#{image.id}\"")
|> send_resp(200, image.data)
end
end
def recolored_svg(conn, %{"id" => id, "color" => color}) do
with %{is_svg: true, svg_content: svg} <- Media.get_image(id),
clean_color <- String.trim_leading(color, "#"),
recolored <- SimpleshopTheme.Media.SVGRecolorer.recolor(svg, "##{clean_color}") do
conn
|> put_resp_content_type("image/svg+xml")
|> put_resp_header("cache-control", "public, max-age=3600")
|> send_resp(200, recolored)
else
_ -> send_resp(conn, 400, "Invalid request")
end
end
end
```
## Key Dependencies to Add
```elixir
# mix.exs
{:image, "~> 0.54"} # Thumbnail generation (uses libvips)
{:fast_sanitize, "~> 0.2"} # SVG sanitization (security)
```
## Router Updates
```elixir
# lib/simpleshop_theme_web/router.ex
# Theme editor (authenticated)
scope "/admin", SimpleshopThemeWeb do
pipe_through [:browser, :require_authenticated_user]
live_session :theme_editor,
on_mount: [{SimpleshopThemeWeb.UserAuth, :require_authenticated}] do
live "/theme", ThemeLive.Index, :index
end
end
# Image serving (public)
scope "/", SimpleshopThemeWeb do
pipe_through :browser
get "/images/:id", ImageController, :show
get "/images/:id/recolored/:color", ImageController, :recolored_svg
end
# Public storefront (future - Phase 9)
# scope "/", SimpleshopThemeWeb do
# pipe_through :browser
# live "/", ShopLive.Home, :index
# live "/products/:slug", ShopLive.Product, :show
# end
```
## Critical Files Reference
### To Create
- `lib/simpleshop_theme/settings.ex` - Settings context
- `lib/simpleshop_theme/settings/setting.ex` - Setting schema (key-value)
- `lib/simpleshop_theme/settings/theme_settings.ex` - Embedded theme settings
- `lib/simpleshop_theme/media.ex` - Media context
- `lib/simpleshop_theme/media/image.ex` - Image schema
- `lib/simpleshop_theme/media/svg_recolorer.ex` - SVG manipulation
- `lib/simpleshop_theme/theme/presets.ex` - 9 preset definitions
- `lib/simpleshop_theme/theme/css_generator.ex` - CSS generation
- `lib/simpleshop_theme/theme/css_cache.ex` - ETS caching
- `lib/simpleshop_theme/theme/preview_data.ex` - Smart preview data
- `lib/simpleshop_theme_web/live/theme_live/index.ex` - Main LiveView
- `lib/simpleshop_theme_web/controllers/image_controller.ex` - Image serving
- `priv/static/css/theme-primitives.css` - CSS Layer 1
- `priv/static/css/theme-semantic.css` - CSS Layer 3
- Comprehensive test files for all contexts and LiveViews
### To Modify
- `lib/simpleshop_theme/application.ex` - Add CSS cache to supervision tree
- `lib/simpleshop_theme_web/router.ex` - Add theme and image routes
- `lib/simpleshop_theme_web/components/layouts.ex` - Add theme nav link
- `assets/css/app.css` - Import theme CSS
- `priv/repo/seeds.exs` - Add default theme settings
- `mix.exs` - Add dependencies
### Reference Files
- `SIMPLESHOP_THEME_STUDIO_SPEC.md` - Complete specification
- `theme-demo-v28.html` - Working prototype (CSS, HTML structure, JavaScript logic)
## Success Criteria
✅ User can access theme studio at `/admin/theme`
✅ All 9 presets work with real-time preview
✅ All customization options update preview instantly
✅ Logo and header images upload and store as BLOBs
✅ SVG recoloring works correctly
✅ Preview shows all 7 mock pages
✅ Settings persist to database
✅ "Save" button works with success feedback
✅ Images served efficiently from database
✅ CSS cached in ETS for performance
✅ Everything self-contained in SQLite file
## Next Steps After Implementation
1. **Add Products Context** - So users can add real products
2. **Build Storefront** - Public-facing shop pages using saved theme
3. **Add Orders/Cart** - E-commerce functionality
4. **Multi-admin Support** - Invite additional users to manage shop
5. **Custom Domains** - Allow users to point their own domain
6. **Theme Export/Import** - Share themes between shops
7. **Advanced Features** - Custom CSS, code injection, etc.

136
README.md
View File

@ -1,18 +1,132 @@
# SimpleshopTheme # SimpleshopTheme
To start your Phoenix server: A customisable e-commerce theme system built with Phoenix LiveView. Designed for print-on-demand sellers who want beautiful, professional shops without design expertise.
* Run `mix setup` to install and setup dependencies ## Features
* Start Phoenix endpoint with `mix phx.server` or inside IEx with `iex -S mix phx.server`
Now you can visit [`localhost:4000`](http://localhost:4000) from your browser. ### Theme Editor (`/admin/theme`)
- **8 curated presets** - Gallery, Studio, Boutique, Bold, Playful, Minimal, Night, Classic
- **Real-time preview** - See changes instantly across 7 page types
- **Comprehensive customisation**:
- Mood (Neutral, Warm, Cool, Dark)
- Typography (Clean, Editorial, Modern, Classic, Friendly, Minimal)
- Shape (Sharp, Soft, Round, Pill)
- Density (Compact, Balanced, Spacious)
- Accent colours with automatic contrast
- Layout options (grid columns, header style, width)
- Feature toggles (announcement bar, sticky header, etc.)
- **Logo upload** with optional SVG recolouring
- **Header image** with zoom and position controls
Ready to run in production? Please [check our deployment guides](https://hexdocs.pm/phoenix/deployment.html). ### Public Storefront
- Home page with hero, categories, featured products, testimonials
- Products listing with grid layout
- Product detail pages with image gallery
- Shopping cart page
- About and Contact pages
- Themed 404/500 error pages
## Learn more ### Technical Highlights
- CSS custom properties for instant theme switching
- Three-layer CSS architecture (primitives → attributes → semantic)
- ETS-based CSS caching for performance
- SQLite database with BLOB storage for images
- Shared PageTemplates between preview and live shop
* Official website: https://www.phoenixframework.org/ ## Getting Started
* Guides: https://hexdocs.pm/phoenix/overview.html
* Docs: https://hexdocs.pm/phoenix ### Prerequisites
* Forum: https://elixirforum.com/c/phoenix-forum - Elixir 1.17+
* Source: https://github.com/phoenixframework/phoenix - Erlang 27+
- Node.js 20+ (for assets)
### Setup
```bash
# Clone the repository
git clone <repo-url>
cd simpleshop_theme
# Install dependencies
mix setup
# Start the server
mix phx.server
```
Visit:
- **Shop**: http://localhost:4000
- **Theme Editor**: http://localhost:4000/admin/theme
### Running Tests
```bash
mix test
```
## Project Structure
```
lib/
├── simpleshop_theme/ # Core business logic
│ ├── settings.ex # Theme settings context
│ ├── settings/
│ │ └── theme_settings.ex # Theme settings schema
│ ├── media.ex # Image upload handling
│ └── theme/
│ ├── css_generator.ex # Generates CSS from settings
│ ├── css_cache.ex # ETS cache for generated CSS
│ ├── presets.ex # 8 theme presets
│ └── preview_data.ex # Mock data for previews
├── simpleshop_theme_web/ # Web layer
│ ├── components/
│ │ ├── layouts/ # App and shop layouts
│ │ ├── page_templates/ # Shared page templates (*.heex)
│ │ ├── page_templates.ex # PageTemplates module
│ │ └── shop_components.ex # Reusable shop UI components
│ ├── live/
│ │ ├── theme_live/ # Theme editor LiveView
│ │ └── shop_live/ # Public shop LiveViews
│ └── controllers/
│ └── error_html.ex # Themed error pages
assets/css/
├── app.css # Main stylesheet
├── theme-layer1-primitives.css # Design tokens
├── theme-layer2-attributes.css # Theme-specific values
└── theme-layer3-semantic.css # Component styles
```
## Routes
| Path | Description |
|------|-------------|
| `/` | Shop home page |
| `/products` | Products listing |
| `/products/:id` | Product detail page |
| `/cart` | Shopping cart |
| `/about` | About page |
| `/contact` | Contact page |
| `/admin/theme` | Theme editor (requires auth) |
| `/dev/errors/404` | Preview 404 page (dev only) |
| `/dev/errors/500` | Preview 500 page (dev only) |
## Documentation
- [ROADMAP.md](ROADMAP.md) - Future features and improvements
- [docs/spec.md](docs/spec.md) - Theme system specification
- [docs/plans/](docs/plans/) - Feature plans
- [docs/research/](docs/research/) - Design research and guidelines
## Design Philosophy
1. **"One theme, infinite variations"** - Rather than multiple themes, one solid foundation with curated customisation
2. **Constrained creativity** - Limit choices to prevent poor design outcomes
3. **No professional photography required** - Works with product mockups
4. **Mobile-first** - All features work on touch devices
5. **Ethical design** - No dark patterns or fake urgency
## License
MIT

View File

@ -1,75 +0,0 @@
Summary of Improvements
I've successfully implemented all four requested improvements to make the SimpleShop Theme Studio more aligned with the demo file and UK-centric:
1. ✅ Made all links and buttons functional
Updated components:
Header navigation (preview_pages.ex): Home, Shop, About, and Contact links now trigger page navigation
Product cards (home.html.heex, collection.html.heex): Clicking any product card navigates to the PDP page
Footer links (preview_pages.ex): All footer navigation links are now functional
CTA buttons (home.html.heex): "Shop the collection" and "View all products" buttons navigate to collection page
About link (home.html.heex): "Learn more about the studio" link navigates to about page
All links now use phx-click="change_preview_page" with phx-value-page to switch between the 7 preview pages seamlessly.
2. ✅ Implemented floating cart drawer/sidebar
New component added (preview_pages.ex:229-320):
Created cart_drawer/1 function component matching the demo's design exactly
Includes cart header with "Your basket" title
Displays cart items with images, names, variants, and prices
Shows subtotal (£72.00)
Checkout button and "View basket" link
Close button and overlay with click-to-close functionality
Smooth slide-in animation from the right
Added to all 7 preview pages (home, collection, pdp, cart, about, contact, error)
Cart drawer data (preview_data.ex:34-49):
Added cart_drawer_items/0 function with UK-themed products:
Autumn Fern (A4 / Unframed) - £24.00
Wild Roses (A3 / Oak frame) - £48.00
3. ✅ Added cart count badge to cart icon
Updated header (preview_pages.ex:98-112):
Added circular badge showing "2" items
Badge styled with accent color background
Positioned at top-right of cart icon
Font size: 11px, white text, rounded pill shape
Matches the demo implementation exactly
Cart button functionality:
Clicking the cart icon now opens the cart drawer
Uses Phoenix.LiveView.JS.add_class to toggle visibility
4. ✅ Updated all content to UK English and currency
Language changes:
"Shopping Cart" → "Your basket"
"Add to Cart" → "Add to basket"
"Free Shipping" → "Free Delivery"
"Shipping" (in fees) → "Delivery"
"You May Also Like" → "You might also like"
Footer: "Shipping" → "Delivery"
Currency changes:
All product prices: $ → £ (across all 7 preview pages)
Announcement bar: "$50" → "£40"
Free delivery threshold: "$50" → "£40"
Cart delivery fee: "$10.00" → "£8.00"
Cart tax: "$8.50" (Tax) → "£7.20" (VAT 20%)
Cart drawer subtotal: "$72.00" → "£72.00"
Files modified:
lib/simpleshop_theme_web/live/theme_live/preview_pages.ex - Header, footer, announcement bar, new cart drawer component
lib/simpleshop_theme/theme/preview_data.ex - Added cart drawer items function
All 7 preview page files (home, collection, pdp, cart, about, contact, error) - Currency symbols and cart drawer component
The implementation now closely matches the demo.html file functionality while being fully localized for the UK market with British English tone and £ currency throughout.

140
ROADMAP.md Normal file
View File

@ -0,0 +1,140 @@
# SimpleshopTheme Roadmap
This document tracks future improvements, features, and known gaps.
## Quick Wins (Low Effort)
### CSS Cache Warming on Startup
**Status:** Not implemented
**Effort:** Small
Currently the CSS cache (ETS) is created on startup but not pre-warmed. The first request after server restart generates CSS on-demand.
**Implementation:**
Add cache warming to `lib/simpleshop_theme/application.ex`:
```elixir
# After supervisor starts
Task.start(fn ->
settings = SimpleshopTheme.Settings.get_theme_settings()
css = SimpleshopTheme.Theme.CSSGenerator.generate(settings)
SimpleshopTheme.Theme.CSSCache.put(css)
end)
```
### Navigation Links Between Admin and Shop
**Status:** Not implemented
**Effort:** Small
No links exist to navigate between the theme editor (`/admin/theme`) and the public shop (`/`).
**Implementation:**
- Add "View Shop" button in theme editor header
- Add "Edit Theme" link in shop header (when authenticated)
### Collection Slug Routes
**Status:** Partial
**Effort:** Small
Currently we have `/products` but the original plan included `/collections/:slug` for filtered views by category.
---
## Medium Features
### Sample Content Refresh ("Wildprint Studio")
**Status:** Planned (see `docs/plans/sample-content.md`)
**Effort:** Medium
Replace current preview data with POD-focused content:
- 16 products across 5 categories (Art Prints, Apparel, Homewares, Stationery, Accessories)
- Nature/botanical primary theme with variety
- UK-focused (prices in £)
- Printify API integration for automated mockup generation
### Page Builder (Database-Driven Pages)
**Status:** Planned (see `docs/plans/page-builder.md`)
**Effort:** Large
Allow shop owners to build custom pages by combining pre-built sections:
- Hero, Featured Products, Testimonials, Newsletter, etc.
- Drag-and-drop section ordering
- Per-section configuration
- Database-backed page storage
---
## Future Features (Large Scope)
### Products Context
Real product management instead of preview data:
- Product CRUD
- Variant support (size, colour)
- Inventory tracking
- Image galleries
### Orders & Cart Functionality
Currently cart is display-only with mock data:
- Session-based cart persistence
- Add to cart functionality
- Checkout flow
- Order creation and history
### Multi-Admin Support
Currently single-user authentication:
- Multiple admin users
- Role-based permissions
- Audit logging
### Custom Domains
Allow shops to use their own domain:
- Domain verification
- SSL certificate provisioning
- DNS configuration guidance
### Theme Export/Import
Backup and restore theme settings:
- JSON export of all settings
- Import with validation
- Preset sharing between shops
### Advanced Theme Features
- Custom CSS injection
- Custom JavaScript snippets
- Code-level overrides for developers
---
## Technical Debt
### Test Coverage
Phase 9 testing is basic. Areas needing better coverage:
- Shop LiveView integration tests
- CSS cache invalidation flow
- Theme application across all pages
- Responsive behaviour
- Accessibility validation
### Error Handling
- Better error states for missing products
- Graceful degradation when theme settings are invalid
- Network error handling in LiveView
---
## Completed (For Reference)
### Phase 1-8: Theme Editor ✅
- Theme settings schema and persistence
- CSS three-layer architecture
- 8 theme presets
- All customisation controls
- Logo/header image uploads
- SVG recolouring
- Preview system with 7 pages
### Phase 9: Storefront Integration ✅
- Public shop routes (/, /products, /products/:id, /cart, /about, /contact)
- Shared PageTemplates for shop and preview
- CSS injection via shop layout
- Themed error pages (404/500)
- Dev routes for error page preview