berrypod/lib/berrypod_web/components/layouts/shop_root.html.heex
jamey a039c8d53c
All checks were successful
deploy / deploy (push) Successful in 6m49s
add live page editor sidebar with collapsible UI
Admins can now edit pages directly on the live shop by clicking the
pencil icon in the header. A sidebar slides in with block management
controls (add, remove, reorder, edit settings, save, reset, done).

Key features:
- PageEditorHook on_mount with handle_params/event/info hooks
- BlockEditor pure functions extracted from admin editor
- Shared BlockEditorComponents with event_prefix namespacing
- Collapsible sidebar: X closes it, header pencil reopens it
- Backdrop overlay dismisses sidebar on tap
- Conditional admin.css loading for logged-in users
- content_body block now portable (textarea setting + rich text fallback)

13 integration tests, 26 unit tests, 1370 total passing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 16:22:35 +00:00

94 lines
3.7 KiB
Plaintext

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="csrf-token" content={get_csrf_token()} />
<meta
name="description"
content={
assigns[:page_description] || @theme_settings.site_description ||
"Welcome to #{@theme_settings.site_name}"
}
/>
<!-- Favicon & PWA -->
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
<link rel="icon" href="/favicon-32x32.png" sizes="32x32" type="image/png" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
<link rel="manifest" href="/site.webmanifest" />
<meta name="theme-color" content={@theme_settings.accent_color || "#000000"} />
<.live_title suffix={" · #{@theme_settings.site_name}"}>
{assigns[:page_title]}
</.live_title>
<% og_title =
if assigns[:page_title],
do: "#{assigns[:page_title]} · #{@theme_settings.site_name}",
else: @theme_settings.site_name
og_description =
assigns[:page_description] ||
@theme_settings.site_description ||
"Welcome to #{@theme_settings.site_name}" %>
<meta property="og:site_name" content={@theme_settings.site_name} />
<meta property="og:title" content={og_title} />
<meta property="og:description" content={og_description} />
<meta property="og:type" content={assigns[:og_type] || "website"} />
<%= if assigns[:og_url] do %>
<link rel="canonical" href={assigns[:og_url]} />
<meta property="og:url" content={assigns[:og_url]} />
<% end %>
<%= if assigns[:og_image] do %>
<meta property="og:image" content={assigns[:og_image]} />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:image" content={assigns[:og_image]} />
<% else %>
<meta name="twitter:card" content="summary" />
<% end %>
<meta name="twitter:title" content={og_title} />
<meta name="twitter:description" content={og_description} />
<%= if assigns[:json_ld] do %>
<script type="application/ld+json">
<%= Phoenix.HTML.raw(assigns[:json_ld]) %>
</script>
<% end %>
<!-- Preload critical fonts for the current typography preset -->
<%= for preload <- Berrypod.Theme.Fonts.preload_links(
@theme_settings.typography,
&BerrypodWeb.Endpoint.static_path/1
) do %>
<link rel="preload" href={preload.href} as="font" type="font/woff2" crossorigin />
<% end %>
<!-- Pre-declare layer order so reset < components regardless of load order -->
<style>
@layer properties, reset, primitives, tokens, theme, base, components, layout, utilities, overrides;
</style>
<link phx-track-static rel="stylesheet" href={~p"/assets/css/shop.css"} />
<%= if assigns[:current_scope] && @current_scope.user do %>
<link phx-track-static rel="stylesheet" href={~p"/assets/css/admin.css"} />
<% end %>
<script defer phx-track-static src={~p"/assets/js/app.js"}>
</script>
<!-- Generated theme CSS with @font-face declarations -->
<style id="theme-css">
<%= Phoenix.HTML.raw(@generated_css) %>
</style>
</head>
<body>
<div
class="themed shop-root"
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}
data-button-style={@theme_settings.button_style}
>
{@inner_content}
</div>
</body>
</html>