refactor admin CSS: replace utility classes with semantic styles

Replace Tailwind utility soup across admin templates with semantic
CSS classes. Add layout primitives (stack, row, cluster, grid),
extract JS transition helpers into transitions.css, and refactor
core_components, layouts, settings, newsletter, order_show, providers,
and theme editor templates.

Utility occurrences reduced from 290+ to 127 across admin files.
All 1679 tests pass.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jamey
2026-03-01 17:15:25 +00:00
parent edef628214
commit b7ec41b0cf
13 changed files with 2661 additions and 1643 deletions

View File

@@ -51,17 +51,17 @@ defmodule BerrypodWeb.CoreComponents do
{@rest}
>
<div class={[
"admin-alert w-80 sm:w-96 max-w-80 sm:max-w-96 text-wrap",
"admin-alert",
@kind == :info && "admin-alert-info",
@kind == :error && "admin-alert-error"
]}>
<.icon :if={@kind == :info} name="hero-information-circle" class="size-5 shrink-0" />
<.icon :if={@kind == :error} name="hero-exclamation-circle" class="size-5 shrink-0" />
<div>
<p :if={@title} class="font-semibold">{@title}</p>
<p :if={@title} class="admin-alert-title">{@title}</p>
<p>{msg}</p>
</div>
<div class="flex-1" />
<div class="admin-alert-spacer" />
<button type="button" class="group self-start cursor-pointer" aria-label={gettext("close")}>
<.icon name="hero-x-mark" class="size-5 opacity-40 group-hover:opacity-70" />
</button>
@@ -271,7 +271,7 @@ defmodule BerrypodWeb.CoreComponents do
# Helper used by inputs to generate form errors
defp error(assigns) do
~H"""
<p class="admin-error mt-1.5 flex gap-2 items-center text-sm">
<p class="admin-error">
<.icon name="hero-exclamation-circle" class="size-5" />
{render_slot(@inner_block)}
</p>
@@ -287,16 +287,19 @@ defmodule BerrypodWeb.CoreComponents do
def header(assigns) do
~H"""
<header class={[@actions != [] && "flex items-center justify-between gap-6", "pb-4"]}>
<header class={[
"admin-header",
@actions != [] && "admin-header-with-actions"
]}>
<div>
<h1 class="text-lg font-semibold leading-8">
<h1 class="admin-header-title">
{render_slot(@inner_block)}
</h1>
<p :if={@subtitle != []} class="text-sm text-base-content/70">
<p :if={@subtitle != []} class="admin-header-subtitle">
{render_slot(@subtitle)}
</p>
</div>
<div class="flex-none">{render_slot(@actions)}</div>
<div class="admin-header-actions">{render_slot(@actions)}</div>
</header>
"""
end
@@ -352,8 +355,8 @@ defmodule BerrypodWeb.CoreComponents do
>
{render_slot(col, @row_item.(row))}
</td>
<td :if={@action != []} class="w-0 font-semibold">
<div class="flex gap-4">
<td :if={@action != []} class="admin-table-actions">
<div class="admin-table-actions-row">
<%= for action <- @action do %>
{render_slot(action, @row_item.(row))}
<% end %>
@@ -385,7 +388,7 @@ defmodule BerrypodWeb.CoreComponents do
<ul class="admin-list">
<li :for={item <- @item} class="admin-list-row">
<div class="admin-list-grow">
<div class="font-bold">{item.title}</div>
<div class="admin-list-title">{item.title}</div>
<div>{render_slot(item)}</div>
</div>
</li>

View File

@@ -35,8 +35,8 @@ defmodule BerrypodWeb.Layouts do
def app(assigns) do
~H"""
<main class="px-4 py-12 sm:px-6 lg:px-8">
<div class="mx-auto max-w-lg flex flex-col gap-4">
<main class="app-main">
<div class="app-container">
{render_slot(@inner_block)}
</div>
</main>
@@ -108,11 +108,11 @@ defmodule BerrypodWeb.Layouts do
"""
def theme_toggle(assigns) do
~H"""
<div class="card relative flex flex-row items-center border-2 border-base-300 bg-base-300 rounded-full">
<div class="theme-toggle">
<div class="theme-toggle-indicator absolute w-1/3 h-full rounded-full border-1 border-base-200 bg-base-100 brightness-200 left-0" />
<button
class="flex p-2 cursor-pointer w-1/3"
class="theme-toggle-btn"
phx-click={JS.dispatch("phx:set-theme")}
data-phx-theme="system"
>
@@ -120,7 +120,7 @@ defmodule BerrypodWeb.Layouts do
</button>
<button
class="flex p-2 cursor-pointer w-1/3"
class="theme-toggle-btn"
phx-click={JS.dispatch("phx:set-theme")}
data-phx-theme="light"
>
@@ -128,7 +128,7 @@ defmodule BerrypodWeb.Layouts do
</button>
<button
class="flex p-2 cursor-pointer w-1/3"
class="theme-toggle-btn"
phx-click={JS.dispatch("phx:set-theme")}
data-phx-theme="dark"
>

View File

@@ -1,4 +1,4 @@
<div class="admin-layout h-full">
<div class="admin-layout">
<input id="admin-drawer" type="checkbox" class="admin-layout-toggle" />
<%!-- main content area --%>
@@ -23,15 +23,15 @@
<.icon name="hero-exclamation-triangle" class="size-5 shrink-0" />
<p>
Email delivery isn't set up yet — customers won't receive order confirmations or shipping updates.
<.link navigate={~p"/admin/settings/email"} class="underline font-medium">
<.link navigate={~p"/admin/settings/email"} class="admin-link">
Configure email
</.link>
</p>
</div>
<%!-- page content --%>
<main class="flex-1 p-4 sm:p-6 lg:p-8">
<div class="mx-auto max-w-5xl">
<main class="admin-main">
<div class="admin-container">
{@inner_content}
</div>
</main>
@@ -42,17 +42,17 @@
<label for="admin-drawer" class="admin-sidebar-overlay" aria-label="Close navigation"></label>
<aside class="admin-sidebar">
<%!-- sidebar header --%>
<div class="p-4 border-b border-base-300">
<.link navigate={~p"/admin"} class="text-lg font-bold tracking-tight">
<div class="admin-sidebar-header">
<.link navigate={~p"/admin"} class="admin-brand">
Berrypod
</.link>
<p class="text-xs text-base-content/60 mt-0.5 truncate">
<p class="admin-text-secondary truncate" style="margin-top: 0.125rem;">
{@current_scope.user.email}
</p>
</div>
<%!-- nav links --%>
<nav class="flex-1 p-2" aria-label="Admin navigation">
<nav class="admin-sidebar-nav" aria-label="Admin navigation">
<div class="admin-nav-group">
<span class="admin-nav-heading">Shop</span>
<ul class="admin-nav">
@@ -191,7 +191,7 @@
</nav>
<%!-- sidebar footer --%>
<div class="p-2 border-t border-base-300">
<div class="admin-sidebar-footer">
<ul class="admin-nav">
<li>
<.link href={~p"/"}>