- add ?edit=page/theme/settings param when opening editor or switching tabs
- remove ?edit param when closing editor
- restore .themed class on shop_root for editor panel background tokens
- collapse editor when navigating back to URL without ?edit param
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
All 7 phases done. Admins can now edit theme and page content directly
on the live shop via /?edit=theme, /?edit=page, or /?edit=settings.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The shop_root.html.heex had duplicate .themed element with data-mood etc
attributes that were static (rendered once at page load). This prevented
live theme changes from visually updating since CSS matched the outer
stale element.
Fix: Remove data attributes from shop_root.html.heex, keeping only the
live-updated .shop-container.themed element inside the LiveView.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Phase 5 was already implemented (URL mode activation via ?edit param)
- Phase 6: Add RedirectController to redirect /admin/theme → /?edit=theme
- Update admin sidebar and dashboard links to point directly to /?edit=theme
- Delete old Admin.Theme.Index LiveView and template (no longer needed)
- Update tests for new redirect behavior
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 4 of unified editing: image upload handling in hook context.
- Configure uploads in Shop.Page mount for logo, header, icon
- Add upload UI components to theme_editor compact_editor
- Pass uploads through page_renderer to theme editor
- Add cancel_upload handler to PageEditorHook
Also fixes scroll position not resetting on patch navigation:
- Push scroll-top event when path changes in handle_params
- JS listener scrolls window to top instantly
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When navigating between page types in the unified shop LiveView,
assigns from the previous page could persist and cause stale data
to appear or template errors. Now explicitly nils them out.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The provider_label function was accessing product.provider_type but
that field is on the provider_connection association, not the product
itself. Handle the case where the association may not be preloaded.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Phase 3b of unified editing mode. The Settings tab now shows
context-specific forms: custom pages get editable title, slug,
meta, visibility and nav options; system pages get read-only info
with links to admin; product/collection pages show provider info.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace individual shop LiveViews with a single Shop.Page that dispatches
to page modules based on live_action. This enables patch navigation between
pages, preserving socket state (including editor state) across transitions.
Changes:
- Add Shop.Page unified LiveView with handle_params dispatch
- Extract page logic into Shop.Pages.* modules (Home, Product, Collection, etc.)
- Update router to use Shop.Page with live_action for all shop routes
- Change navigate= to patch= in shop component links
- Add maybe_sync_editing_blocks to reload editor state when page changes
- Track editor_page_slug to detect cross-page navigation while editing
- Fix picture element height when hover image disabled
- Extract ThemeEditor components for shared use
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Plan for auto-saving drafts with explicit publish. Visitors always see
published version, admins see their drafts while editing. Removes need
for beforeunload warnings since work is never lost.
Planned to follow unified-editing-mode completion.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fly.io internal health checks are made over HTTP, so they get redirected
to HTTPS with a 301 which fails the health check. Exclude /health path
from SSL enforcement.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Remove global margin-left: auto from .shop-actions since it conflicts
with justify-content: space-between in the standard header layout.
Keep margin-left: auto only for the left layout variant where it's
needed. Also fix .shop-cart → .shop-actions selector in layer2.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
force_ssl must be set at compile time (in prod.exs), not runtime.
Phoenix validates compile-time config at boot and was crashing
because the value differed between compile and runtime.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add theme editing to the existing PageEditorHook, enabling on-site
theme customisation alongside page editing. The editor panel now has
three tabs (Page, Theme, Settings) and can be collapsed while
keeping editing state intact.
- Add theme editing state and event handlers to PageEditorHook
- Add 3-tab UI with tab switching logic
- Add transparent overlay for click-outside dismiss
- Add mobile drag-to-resize with height persistence
- Fix animation replay on drag release (has-dragged class)
- Preserve panel height across LiveView re-renders
- Default to Page tab on editable pages, Theme otherwise
- Show unsaved changes indicator on FAB when panel collapsed
- Fix handle_event grouping warning in admin theme
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- extract dominant colors from header images during optimization
- calculate WCAG contrast ratios against theme text color
- show warning in theme editor when text may be hard to read
- prevent hiding shop name when no logo is uploaded
- auto-enable shop name when logo is deleted
- fix image cache invalidation on delete
- add missing .hidden utility class
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create dedicated /admin/account page for user account management
- Move email, password, and 2FA settings from /admin/settings
- Add Account link to top of admin sidebar navigation
- Add TOTP-based two-factor authentication with NimbleTOTP
- Add TOTP verification LiveView for login flow
- Add AccountController for TOTP session management
- Remove Advanced section from settings (duplicated in dev tools)
- Remove user email from sidebar footer (replaced by Account link)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Hammer library for rate limiting with ETS backend
- Rate limit login (5/min), magic link (3/min), newsletter (10/min), API (60/min)
- Add themed 429 error page using bare shop styling
- Enable HSTS in production with rewrite_on for Fly proxy
- Add security hardening plan to docs
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Rewrote planning doc as a reference guide with:
- decision tree for choosing feedback type
- implementation patterns with code examples
- accessibility requirements
- common mistakes to avoid
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- use role="status" for info messages, role="alert" for errors
- add aria-live attribute (polite for info, assertive for errors)
- move phx-click to close button for better keyboard navigation
- add close buttons to shop flash messages
- add aria-hidden to decorative icons
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace put_flash with inline feedback for form saves:
- Media library: metadata save shows "Saved" checkmark
- Product show: storefront controls save shows "Saved" checkmark
- Newsletter campaign form: draft save shows "Saved" checkmark
Page-level outcomes (uploads, deletes, async operations) remain as
flash/banner messages — these are the correct pattern for non-form
actions.
Completes Task 4 of notification overhaul.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Progressive enhancement: provider form now works without JavaScript.
Forms POST to ProvidersController (create/update), which handles
validation and redirects with flash messages.
With JS: LiveView phx-submit handles save, navigates with flash.
Without JS: Form POSTs to controller, redirects with flash.
Completes Task 3 of notification overhaul (admin forms migration).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace put_flash calls with inline feedback for form saves:
- Email settings: "Now send a test email" after saving
- Settings: from address and signing secret saves
- Page editor: save button shows "Saved" checkmark
Inline feedback appears next to save buttons and auto-clears after
3 seconds. Banners (put_flash) remain for page-level outcomes like
deletions, state changes, and async operations.
Task 3 of notification overhaul. Theme editor skipped as it auto-saves.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Split the editor sheet into two distinct elements:
- .editor-fab: floating action button, always a pill in the corner
- .editor-panel: sliding panel that animates in/out independently
This enables proper CSS keyframe animations (slide-up/down on mobile,
slide-in/out on desktop) with a closing class for exit transitions.
Simplified the JS hook to only handle close behaviour.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- collapsed state: floating pill button in bottom-right corner
- removed panel background when collapsed (transparent)
- violet accent colour to distinguish from shop theme
- white glow outline for visibility on any background
- consistent behaviour on mobile and desktop
- opens to bottom sheet (mobile) or side panel (desktop)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- semantic HTML: step numbers inside h2, strong provider names, details
for adapter configs, strong error messages, fieldset drawer toggle hidden
- inline field errors via flash for no-JS controller fallback
- single form POST button for test email (works with and without JS)
- admin sidebar: remove brand/view-shop, move user email to footer nav
- replace inline style with .admin-setup-step-spaced class
- clean up unused CSS (.admin-brand, .admin-sidebar-header, etc.)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Non-selected adapter configs now get HTML hidden attribute so only the
active config shows without CSS. Provider card labels use div instead
of span for natural block stacking in text-only rendering.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document the CSS :has(:checked) pattern for forms with dynamic
sections, noscript fallbacks for JS-only elements, and the HEEx
<style> raw text gotcha.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Render all adapter field sections in the form with CSS :has(:checked)
controlling visibility. Selecting a provider instantly shows its config
fields — no JS, no page reload, no server round-trip needed.
- Render all 6 adapter configs with data-adapter attribute
- CSS :has(:checked) show/hide rules per adapter in admin stylesheet
- Namespace field names per adapter (email[brevo][api_key] etc)
- Drop 4 transactional-only providers (Resend, Postmark, Mailgun, MailPace)
- Remove noscript "Switch provider" button and controller redirect workaround
- Remove configured_adapter hidden input tracking
- Hide JS-only test email button for no-JS users via noscript style
- LiveView progressively enhances with async save and test email
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
show all 10 providers in three groups (popular, transactional,
advanced) with category headings. fix phx-change clobbering text
fields, async test email sending state, integer parse crash on
bad port. add keyboard focus on card radios, fieldset legend,
WCAG-compliant badge contrast, responsive grid. extract shared
save_config into Mailer, add no-JS controller fallback with
configured_adapter hidden field for adapter change detection.
remove CardRadioScroll JS hook (no longer needed).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
auth pages (login, registration, confirmation, recover) now use
setup-page/setup-header/admin-btn-block. theme toggle indicator
gets proper CSS. cleaned up dead h-full, size-3.5, ml-2 classes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
grouped providers by category, added per-provider key validation
with cross-provider detection, friendly delivery error messages,
retryable vs config error distinction, from-address in general
settings, and "Save settings" button to match admin conventions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Disable checkout when Stripe isn't connected (cart drawer, cart page,
and early guard in checkout controller to prevent orphaned orders).
Show amber warning on order detail when email isn't configured.
Fix pre-existing missing vertical spacing between page blocks.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add KeyValidation module for format-checking API keys before
attempting connections. Auto-strips whitespace, detects common
mistakes (e.g. pasting a Stripe publishable key), and returns
helpful error messages.
Inline field errors across all three entry points:
- Setup wizard: provider + Stripe keys
- Admin provider form: simplified to single Connect button
- Email settings: per-field errors instead of flash toasts
Also: plain text inputs for all API keys (not password fields),
accessible error states (aria-invalid, role=alert, thick border,
bold text), inner_block slot declaration on error component.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add icon={false} option to external_link for links with their own
visual indicator. Migrate remaining manual target="_blank" links:
email settings adapter links, product show provider edit, card radio
links, social link cards/icons, page renderer tracking and video
fallback. Every external link in the codebase now goes through the
single component — one place to change rel, target, or sr-only text.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New external_link component in core_components handles target="_blank",
rel="noopener noreferrer", external-link icon, and sr-only "(opens in
new tab)" text. Migrated admin providers form, settings (Stripe),
order tracking, onboarding setup links to use it. Fixed rel="noopener"
to "noopener noreferrer" on remaining links (email settings, product
show, core_components card radio). Added sr-only text to shop social
link cards and aria-label to page renderer tracking link.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New --t-border-input token per mood, all 3:1+ contrast against their
surface backgrounds (neutral #8c8c8c, warm #8a827a, cool #7a8591,
dark #707070). Used on admin inputs/selects/textareas and shop
themed-input/themed-select, with graceful fallback to --t-border-default.
Decorative borders on cards, dividers, panels are unchanged.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add AnalyticsHook to the coming_soon live session — the shop layout
fires an analytics:screen JS event but the session had no handler,
crashing the page on connect.
Centre the logo image (display:block from CSS reset needs
margin-inline:auto). Add a subtle "Admin" link at the bottom using
flex flow rather than fixed/absolute positioning so it works in
iframes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wrap logo mode radios in fieldset/legend for screen reader grouping.
Hide native radio input properly (was using nonexistent .hidden class),
add aria-hidden on decorative dot spans, focus-visible ring on cards,
and IDs on each input.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Onboarding UX v2 supersedes the original plan — reworks setup into a
single guided journey with progress bar, forgiving validation, and
contextual prompts for skipped steps.
Notification overhaul replaces floating toasts with inline feedback
and persistent top banners (110+ flash messages audited).
Live site editor is a design exploration for on-site editing with
contenteditable text and live CSS variable injection.
Also adds SEO settings and multiple providers to the roadmap.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- add password field and required shop name to setup wizard
- extract SetupHook for DRY redirect to /setup when no admin exists
- add ?from=checklist param to checklist hrefs with contextual banner on
email settings and theme pages for easy return to dashboard
- remove email warning banner from admin layout (checklist covers it)
- make email a required checklist item (no longer optional)
- add DevReset module for wiping dev data without restart
- rename "Theme Studio" to "Theme", drop subtitle
- lower theme editor side-by-side breakpoint from 64em to 48em
- clean up login/registration pages (remove dead registration_open code)
- fix settings.put_secret to invalidate cache after write
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract Products.connect_provider/2 that tests the connection, fetches
shop_id, creates the record, and enqueues sync. Both the setup wizard
and the providers form now use this shared function instead of
duplicating the flow. Also makes the products empty state context-aware
(distinguishes "no provider" from "provider connected but no products").
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
site_name and site_description are shop identity, not theme concerns.
They now live in the Settings table as first-class settings with their
own assigns (@site_name, @site_description) piped through hooks and
plugs. The setup wizard writes site_name on account creation, and the
theme editor reads/writes via Settings.put_setting. Removed the
"configure your shop" checklist item since currency/country aren't
built yet. Also adds shop name field to setup wizard step 1.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix resolve_content_image returning base path (not full URL) so
responsive_image doesn't double-append width/extension
- Remove legacy image fields (image_src, image_alt, image_url) from
block settings schemas
- Remove demo/mockup fallbacks from renderer and defaults — blank
fields stay blank instead of showing preview content
- Replace demo text in defaults with instructional placeholders that
guide new shop owners
- Remove redundant X button from editor sidebar, add unsaved-changes
confirmation to Done button
- Fix block card name overflow on mobile (display: block, flex-wrap)
- Add onboarding UX improvement plan (10 tasks)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Badge inside admin-btn-primary was inheriting white text colour
with a light grey background — unreadable. Now uses inverted
colours (accent text on near-white bg) for WCAG AA+ compliance.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>