theme auth/setup pages and unify resets

Phase 7: add LoadTheme to base :browser pipeline so auth and setup
pages get theme settings. Update root.html.heex with .themed wrapper,
font preloads, layer declaration, and generated CSS injection.
Remove old data-theme JS toggle script.

Phase 8: upgrade admin/reset.css to a proper @layer reset matching
the shop reset structure. Remove dead theme toggle CSS rules.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jamey 2026-02-21 00:17:23 +00:00
parent 65ea11c3a2
commit 8f9ed5657f
4 changed files with 84 additions and 46 deletions

View File

@ -632,15 +632,6 @@
&.active .admin-swap-off { display: none; } &.active .admin-swap-off { display: none; }
} }
/* ── Theme toggle ── */
.theme-toggle-indicator {
transition: left 150ms cubic-bezier(0.4, 0, 0.2, 1);
}
[data-theme="light"] .theme-toggle-indicator { left: 33.333333%; }
[data-theme="dark"] .theme-toggle-indicator { left: 66.666667%; }
/* ── Dashboard stats grid ── */ /* ── Dashboard stats grid ── */
.admin-stats-grid { .admin-stats-grid {

View File

@ -1,20 +1,68 @@
/* Minimal resets for admin pages */ /* Minimal reset for admin and auth pages.
When shop.css is also loaded (admin pages), the shop reset takes precedence
since both sit in @layer reset. This ensures auth/setup pages still get
baseline resets when shop.css isn't present. */
*, *::before, *::after { @layer reset {
box-sizing: border-box; *,
} *::before,
*::after {
box-sizing: border-box;
}
body { * {
margin: 0; margin: 0;
font-family: system-ui, -apple-system, sans-serif; }
}
/* Make LiveView wrapper divs transparent for layout */ html {
[data-phx-session], [data-phx-teleported-src] { height: 100%;
display: contents; -webkit-text-size-adjust: 100%;
} text-size-adjust: 100%;
}
/* Phoenix LiveView loading states */ body {
.phx-no-feedback.phx-no-feedback { height: 100%;
/* Suppress validation styles until form is interacted with */ line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
img,
picture,
video,
canvas,
svg {
display: block;
max-width: 100%;
}
input,
button,
textarea,
select {
font: inherit;
color: inherit;
}
a {
color: inherit;
text-decoration-skip-ink: auto;
}
button {
background: none;
border: none;
padding: 0;
cursor: pointer;
}
fieldset {
border: none;
padding: 0;
}
/* LiveView wrapper divs are layout-invisible */
[data-phx-session],
[data-phx-teleported-src] {
display: contents;
}
} }

View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en" class="h-full">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
@ -7,30 +7,28 @@
<.live_title default="Berrypod" suffix=" · Phoenix Framework"> <.live_title default="Berrypod" suffix=" · Phoenix Framework">
{assigns[:page_title]} {assigns[:page_title]}
</.live_title> </.live_title>
<!-- 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 < Tailwind base regardless of load order -->
<style>
@layer properties, reset, primitives, tokens, theme, base, components, layout, admin, utilities, overrides;
</style>
<link phx-track-static rel="stylesheet" href={~p"/assets/css/admin.css"} /> <link phx-track-static rel="stylesheet" href={~p"/assets/css/admin.css"} />
<!-- Generated theme CSS with @font-face declarations -->
<style id="theme-css">
<%= Phoenix.HTML.raw(@generated_css) %>
</style>
<script defer phx-track-static src={~p"/assets/js/app.js"}> <script defer phx-track-static src={~p"/assets/js/app.js"}>
</script> </script>
<script>
(() => {
const setTheme = (theme) => {
if (theme === "system") {
localStorage.removeItem("phx:theme");
document.documentElement.removeAttribute("data-theme");
} else {
localStorage.setItem("phx:theme", theme);
document.documentElement.setAttribute("data-theme", theme);
}
};
if (!document.documentElement.hasAttribute("data-theme")) {
setTheme(localStorage.getItem("phx:theme") || "system");
}
window.addEventListener("storage", (e) => e.key === "phx:theme" && setTheme(e.newValue || "system"));
window.addEventListener("phx:set-theme", (e) => setTheme(e.target.dataset.phxTheme));
})();
</script>
</head> </head>
<body> <body class="h-full">
{@inner_content} <div class="themed" data-mood={@theme_settings.mood} style="min-height:100%">
{@inner_content}
</div>
</body> </body>
</html> </html>

View File

@ -14,6 +14,7 @@ defmodule BerrypodWeb.Router do
plug :put_secure_browser_headers plug :put_secure_browser_headers
plug :fetch_current_scope_for_user plug :fetch_current_scope_for_user
plug BerrypodWeb.Plugs.CountryDetect plug BerrypodWeb.Plugs.CountryDetect
plug BerrypodWeb.Plugs.LoadTheme
end end
pipeline :api do pipeline :api do