Replace hardcoded zinc/white Tailwind colors with DaisyUI semantic
colors (base-content, base-200, etc.) that adapt to light/dark themes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
3-step vertical stepper with inline forms for Printify and Stripe,
real-time sync progress via PubSub, and celebration state on go-live.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fresh installs now redirect to /users/register instead of showing the
demo shop. Post-login redirect goes to /admin dashboard (with setup
checklist) instead of /admin/settings. Added 16 provider tests covering
index (list, delete, sync) and form (new, edit, test connection).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Dashboard at /admin shows setup progress (when not live), stat cards
(orders, revenue, products), and recent paid orders table. Replaces
the old AdminController redirect. Add Dashboard to sidebar nav as
first item, update admin bar and theme editor links to /admin.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Merge shop status, payments, products (Printify), account (email/password),
and advanced (dashboard/error tracker links) into /admin/settings. Simplify
Auth.Settings to a redirector for /users/settings and confirm-email tokens.
Remove Providers from sidebar nav. Update all redirects and tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- New admin root + child layouts with daisyUI drawer sidebar
- AdminLayoutHook tracks current path for active nav highlighting
- Split router into :admin, :admin_theme, :user_settings live_sessions
- Theme editor stays full-screen with back link to admin
- Admin bar on shop pages for logged-in users (mount_current_scope)
- Strip Layouts.app wrapper from admin LiveViews
- Remove nav from root.html.heex (now only serves auth pages)
- 9 new layout tests covering sidebar, active state, theme editor, admin bar
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Consolidates admin_live/, theme_live/, provider_live/ into admin/
(with theme/ and providers/ subdirs). Renames shop_live/ to shop/
and user_live/ to auth/. Updates all module names, router refs,
test files, CSS source paths, and dialyzer ignore.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Settings.site_live?/0 and set_site_live/1 for shop visibility control
- Accounts.has_admin?/0 to detect single-tenant admin existence
- Registration lockdown: /users/register redirects when admin exists
- Setup.setup_status/0 aggregates provider, product, and stripe checks
- Coming soon page at /coming-soon with themed styling
- ThemeHook :require_site_live gate on all public shop routes
- Site live → everyone through
- Authenticated → admin preview through
- No admin → fresh install demo through
- Otherwise → redirect to coming soon
- Go live / take offline toggle on /admin/settings
- 648 tests, 0 failures
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- collection filter bar: horizontal scroll on mobile instead of wrapping
across 3 rows, smaller pills at mobile sizes
- add sale collection filter at /collections/sale (filters on_sale products)
- hero :page variant: add consistent top padding (var(--space-2xl))
- contact page: remove redundant top padding (hero handles it now)
- error page: fix CSS path from /assets/app.css to /assets/css/app.css
(broken in production due to asset fingerprinting)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move increment/decrement handlers from Cart LiveView into CartHook so
they work from any page's drawer. Enable show_quantity_controls on the
drawer's cart_item_row. Scope cart tests to #main-content to avoid
duplicate button matches.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wire up +/− buttons with phx-click events and handle_event handlers,
clamp to 1–99, reset to 1 after add-to-cart. Trust badges now use a
single hero-check-circle icon and sentence case text.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add @source for shop_components/ directory in app-shop.css (Tailwind
wasn't scanning sub-modules after the refactor, dropping ~73 utilities)
- Remove overly aggressive .dockerignore rules that excluded mockup
image variants needed by the responsive_image component
- Seed default theme settings on first boot via Release.seed_defaults/0
in the supervision tree (seeds.exs doesn't run in releases)
- Fix PDP gallery images for mock data by appending -1200.webp to
bare mockup base paths
- Update fly.toml format from fly launch
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
on_mount hook assigns theme_settings, generated_css, logo_image,
header_image, and mode for all public shop LiveViews. Removes
~70 lines of identical boilerplate and 18 unused aliases across
7 LiveViews.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace verbose explicit attr passing with {assigns} spread for
home, contact, cart, product show and checkout success LiveViews.
Collection skipped (inline rendering, no template component).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace one-off ShopLive.About with generic ShopLive.Content that
handles all static content pages via live_action. Add delivery &
returns, privacy policy, and terms of service pages with sample
content. Update footer help links and theme editor preview.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Submit paid orders to Printify via provider API with idempotent
guards, Stripe address mapping, and error handling. Track fulfilment
status through submitted → processing → shipped → delivered via
webhook-driven updates (primary) and Oban Cron polling fallback.
- 9 fulfilment fields on orders (status, provider IDs, tracking, timestamps)
- OrderSubmissionWorker with retry logic, auto-enqueued after Stripe payment
- FulfilmentStatusWorker polls every 30 mins for missed webhook events
- Printify order webhook handlers (sent-to-production, shipment, delivered)
- Admin UI: fulfilment column in table, fulfilment card with tracking info,
submit/retry and refresh buttons on order detail
- Mox provider mocking for test isolation (Provider.for_type configurable)
- 33 new tests (555 total), verified against real Printify API
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Admin UI at /admin/orders to view, filter, and inspect orders.
Adds list_orders/1 and count_orders_by_status/0 to the Orders
context, status filter tabs, clickable order table with streams,
and a detail page showing items, totals, and shipping address.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Store API keys and secrets encrypted in the SQLite database via the
existing Vault module (AES-256-GCM). The only external dependency is
SECRET_KEY_BASE — everything else lives in the portable DB file.
- Add encrypted_value column to settings table with new "encrypted" type
- Add put_secret/get_secret/delete_setting/secret_hint to Settings context
- Add Secrets module to load encrypted config into Application env at startup
- Add Stripe.Setup module with connect/disconnect/verify_api_key flow
- Auto-creates webhook endpoints via Stripe API in production
- Detects localhost and shows Stripe CLI instructions for dev
- Add admin credentials page at /admin/settings with guided setup:
- Not configured: single Secret key input with dashboard link
- Connected (production): status display, webhook info, disconnect
- Connected (dev): Stripe CLI instructions, manual signing secret input
- Remove Stripe env vars from dev.exs and runtime.exs
- Fix CSSCache test startup crash (handle_continue instead of init)
- Add nav link for Credentials page
507 tests, 0 failures.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Stripe-hosted Checkout integration with full order lifecycle:
- stripity_stripe ~> 3.2 with sandbox/prod config via env vars
- Order and OrderItem schemas with price snapshots at purchase time
- CheckoutController creates pending order then redirects to Stripe
- StripeWebhookController verifies signatures and confirms payment
- Success page with real-time PubSub updates from webhook
- Shop flash messages for checkout error feedback
- Cart cleared after successful payment
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Cart context with pure functions for add/remove/update/hydrate
- Price formatting via ex_money (replaces all float division)
- CartHook on_mount with attach_hook for shared event handlers
(open/close drawer, remove item, PubSub sync)
- Accessible cart drawer with focus trap, scroll lock, aria-live
- Cart page with increment/decrement quantity controls
- Preview mode cart drawer support in theme editor
- Cart persistence to session via JS hook + API endpoint
- 19 tests covering all Cart pure functions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix Printify options parsing (Color/Size were swapped)
- Add extract_option_types/1 for frontend display with hex colors
- Filter option types to only published variants (not full catalog)
- Track selected variant in LiveView with price updates
- Color swatches for color-type options, text buttons for size
- Disable unavailable combinations
- Add startup recovery for stale sync status
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Downloads Printify CDN images via ImageDownloadWorker, processes
through Media pipeline (WebP conversion, AVIF/WebP variant generation),
and links to ProductImage via new image_id FK.
- Add image_id to product_images table
- ImageDownloadWorker downloads and processes external images
- sync_product_images preserves image_id when URL unchanged
- PreviewData uses local images for responsive <picture> elements
- VariantCache enqueues pending downloads on startup
- mix simpleshop.download_images backfill task
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
PreviewData now queries the Products context when real products exist,
falling back to mock data otherwise. Shop pages automatically display
synced Printify products.
Fixes:
- Printify image position was string ("front"), now uses index
- Category extraction improved to match more Printify tags
- ProductShow finds products by slug for real data
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add /admin/providers LiveView for connecting and managing POD providers
- Implement pagination for Printify API (handles all products, not just first page)
- Add parallel processing (5 concurrent) for faster product sync
- Add slug-based fallback matching when provider_product_id changes
- Add error recovery with try/rescue to prevent stuck sync status
- Add checksum-based change detection to skip unchanged products
- Add upsert tests covering race conditions and slug matching
- Add Printify provider tests
- Document Printify integration research (product identity, order risks,
open source vs managed hosting implications)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Create separate CSS bundles to reduce shop page load times:
- app-shop.css (45KB/7.8KB gzip): Shop pages only, no daisyUI
- app.css (139KB): Admin pages with daisyUI and theme editor
Key changes:
- Add app-shop.css with targeted @source paths for shop files only
- Move .preview-frame rules from theme-layer2-attributes.css to app.css
- Delete fonts.css (fonts now generated inline by CSSGenerator)
- Add inline all-fonts generation in theme editor for typography switching
- Configure separate Tailwind profiles and watchers for both bundles
Shop pages now load 54% less CSS by excluding:
- daisyUI components (admin only)
- .preview-frame theme switching rules (editor only)
- Admin-specific Tailwind utilities
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace cramped horizontal nav on mobile with a fixed bottom tab bar
for thumb-friendly navigation. The header nav is now hidden on mobile
(<768px) and the bottom nav provides Home, Shop, About, and Contact
links with icons.
- Add mobile_bottom_nav component with icon + label nav items
- Active page has accent-colored background highlight and larger icon
- Add shadow to lift nav visually off the page
- Update all page templates with bottom padding and bottom nav
- Remove CSS rule that was overriding Tailwind's hidden class
- Responsive header padding (tighter on mobile)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add sort functionality to /collections/:slug pages with 6 sort options
(featured, newest, price ascending/descending, name A-Z/Z-A). Sort
selection persists across category navigation via URL query params.
Refactor handle_params to be DRY using load_collection/1 helper.
Add comprehensive unit tests for PreviewData category functions and
LiveView tests for the Collection page sorting and navigation.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add ShopLive.Collection LiveView for collection pages
- Add products_by_category/1 and category_by_slug/1 to PreviewData
- Support /collections/all for all products view
- Remove /products route and ShopLive.Products (replaced by collections)
- Update all links to use /collections/all instead of /products
- Update category nav to link to /collections/:slug
- Update PDP breadcrumb to link to specific collection
URL structure now follows Shopify convention:
- /collections/all - All products
- /collections/art-prints - Art Prints collection
- /collections/apparel - Apparel collection
- etc.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add "← View Shop" link on admin/theme page for easy navigation
- Add collapsible sidebar with chevron toggle button
- Include proper ARIA attributes for accessibility (aria-label,
aria-expanded, aria-controls)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add ShopLive.Cart at /cart using shared PageTemplates
- Update ErrorHTML to render fully themed 404/500 pages
- Add dev-only error preview routes at /dev/errors/404 and /dev/errors/500
- Update error page tests for themed output
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add PDP (Product Detail Page) at /products/:id with full e-commerce
functionality including product gallery, variant selector, quantity
controls, reviews section, and related products.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create ShopLive.Products module and template
- Add /products route to public shop live session
- Shows product grid with category filters and sort dropdown
- Displays all 16 preview products with categories
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create ShopLive.Contact module and template
- Add /contact route to public shop live session
- Includes contact form, order tracking, info cards, social links
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create ShopLive.About module and template
- Add /about route to public shop live session
- Reuse shop_components for header, footer, hero, rich text
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add .themed class as shared selector for both shop and preview
- Move visual/behavioral styles from .preview-frame to .themed
- Keep .preview-frame only for CSS variable switching (editor live preview)
- Update CSSGenerator to target .themed instead of .shop-root
- Refactor CSS files to use native CSS nesting syntax
- Update tests to reflect new class structure
This improves maintainability by:
- Eliminating duplicate selectors (.shop-root + .preview-frame)
- Using modern CSS nesting (94%+ browser support)
- Clear separation: .preview-frame = vars, .themed = styles
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create LoadTheme plug for loading theme settings
- Add shop layout with inline CSS injection (~400 bytes vs 17KB full)
- Create ShopLive.Home at / using shared ShopComponents
- Wire up CSS cache invalidation when theme settings change
- Replace Phoenix welcome page with themed shop home page
The shop layout injects only the active theme CSS variables inline,
achieving a 97% reduction compared to the full variants file used
by the theme editor.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add reusable components for all page sections:
- category_nav: Category circles for homepage navigation
- featured_products_section: Product grid with title and view-all CTA
- image_text_section: Two-column image + text layout
- collection_header: Page header with title and product count
- filter_bar: Category pills and sort dropdown
- content_body: Long-form content wrapper for about page
- contact_form: Contact form card
- order_tracking_card: Order tracking input card
- info_card: Bullet-point info card
- contact_info_card: Email contact card with icon
- social_links: Social media icon links
- cart_item: Cart item row with quantity controls
- order_summary: Order totals and checkout card
- breadcrumb: Navigation breadcrumb trail
- related_products_section: Related products grid
All preview pages now compose entirely of reusable components,
making them easier to maintain and enabling future section-based
theme customization.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add variant support to hero_section component:
- :default - Standard hero with section wrapper (home, about)
- :page - Page header style with larger title, more spacing (contact)
- :error - Error page with pre-title (404), dual buttons (error)
Now used in: home, about, contact, error pages
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Create a centered hero section component with:
- Title (h1) and description (p)
- Optional CTA button with preview/live mode support
- Configurable background (:base or :sunken)
Used in: home page (with CTA), about page (without CTA)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Create a reusable product grid component that handles responsive
column layouts. Supports two modes:
- Theme-based columns: Uses theme_settings.grid_columns for lg breakpoint
- Fixed columns: Use columns={:fixed_4} for 2/4 column layouts
Used in: home (featured), collection, pdp (related), error (suggestions)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Create a reusable product card component with four variants:
- :default (collection page) - full details with category
- :featured (home page) - hover animation, badges
- :compact (pdp related) - smaller, no badges/delivery
- :minimal (error 404) - smallest, not clickable
Accessibility improvements:
- Use <a> for all clickable cards (keyboard nav, screen readers)
- Use <div> only for non-clickable decorative cards
Unified badge logic with priority: Sold out > New > Sale
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move the cart drawer component from ThemeLive.PreviewPages to the
shared ShopComponents module. The component now supports:
- mode attribute (:live for real stores, :preview for theme editor)
- subtotal attribute (default nil shows "£0.00")
- cart_items attribute (default empty list)
In preview mode, "View basket" navigates via LiveView JS commands.
In live mode, it links directly to /cart.
Preview pages now explicitly pass demo values:
<.cart_drawer cart_items={...} subtotal="£72.00" mode={:preview} />
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move the shop header component from ThemeLive.PreviewPages to the
shared ShopComponents module. The component now supports:
- mode attribute (:live for real stores, :preview for theme editor)
- cart_count attribute (default 0, preview pages pass 2)
- Navigation links render conditionally based on mode
Preview pages now call <.shop_header ... mode={:preview} cart_count={2} />
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>