complete admin CSS refactor: delete utilities.css, add layout primitives

- Delete utilities.css (701 lines / 24 KB of Tailwind utility clones)
- Add layout.css with admin-stack, admin-row, admin-cluster, admin-grid
  primitives and gap variants (sm, md, lg, xl)
- Add transitions.css import and layout.css import to admin.css entry point
- Replace all Tailwind utility classes across 26 admin templates with
  semantic admin-*/theme-*/page-specific CSS classes
- Replace all non-dynamic inline styles with semantic classes
- Add ~100 new semantic classes to components.css (analytics, dashboard,
  order detail, settings, theme editor, generic utilities)
- Fix stray text-error → admin-text-error in media.ex
- Add missing .truncate definition to admin CSS
- Only remaining inline styles are dynamic data values (progress bars,
  chart dimensions) and one JS.toggle target

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jamey
2026-03-01 21:40:21 +00:00
parent 22d3e36ed5
commit ae6cf209aa
26 changed files with 1343 additions and 1247 deletions

View File

@@ -367,7 +367,7 @@ defmodule BerrypodWeb.Admin.Settings do
<.provider_connected provider={@provider} />
<% else %>
<div class="admin-section-body">
<p class="admin-section-desc" style="margin-top: 0;">
<p class="admin-section-desc admin-section-desc-flush">
Connect a print-on-demand provider to import products into your shop.
</p>
<div class="admin-section-body">
@@ -397,7 +397,7 @@ defmodule BerrypodWeb.Admin.Settings do
No tracking pixels. One email, never more.
</p>
<%= if @cart_recovery_enabled do %>
<p class="admin-section-desc" style="color: #b45309;">
<p class="admin-section-desc admin-text-warning">
Make sure your privacy policy mentions that a single recovery email may be sent,
and that customers can unsubscribe at any time.
</p>
@@ -419,7 +419,7 @@ defmodule BerrypodWeb.Admin.Settings do
<section class="admin-section">
<h2 class="admin-section-title">Account</h2>
<div class="admin-stack" style="margin-top: 1rem; --admin-stack-gap: 1.5rem;">
<div class="admin-stack admin-stack-lg admin-section-body">
<.form
for={@email_form}
id="email_form"
@@ -433,12 +433,12 @@ defmodule BerrypodWeb.Admin.Settings do
autocomplete="username"
required
/>
<div style="margin-top: 0.75rem;">
<div class="admin-form-actions-sm">
<.button phx-disable-with="Saving...">Change email</.button>
</div>
</.form>
<div style="border-top: 1px solid var(--t-surface-sunken); padding-top: 1.5rem;">
<div class="admin-separator-xl">
<.form
for={@password_form}
id="password_form"
@@ -468,7 +468,7 @@ defmodule BerrypodWeb.Admin.Settings do
label="Confirm new password"
autocomplete="new-password"
/>
<div style="margin-top: 0.75rem;">
<div class="admin-form-actions-sm">
<.button phx-disable-with="Saving...">Change password</.button>
</div>
</.form>
@@ -477,10 +477,10 @@ defmodule BerrypodWeb.Admin.Settings do
</section>
<%!-- Advanced --%>
<section class="admin-section" style="padding-bottom: 2.5rem;">
<section class="admin-section">
<h2 class="admin-section-title">Advanced</h2>
<div class="admin-stack" style="margin-top: 1rem; --admin-stack-gap: 0.5rem;">
<div class="admin-stack admin-stack-sm admin-section-body">
<.link href={~p"/admin/dashboard"} class="admin-link-subtle">
<.icon name="hero-chart-bar" class="size-4 inline" /> System dashboard
</.link>
@@ -548,13 +548,13 @@ defmodule BerrypodWeb.Admin.Settings do
<%= if @connection.last_synced_at do %>
{format_relative_time(@connection.last_synced_at)}
<% else %>
<span style="color: #d97706;">Never</span>
<span class="admin-text-warning">Never</span>
<% end %>
</dd>
</div>
</dl>
<div class="admin-cluster" style="margin-top: 1rem;">
<div class="admin-cluster admin-section-body">
<button
phx-click="sync"
phx-value-id={@connection.id}
@@ -578,7 +578,6 @@ defmodule BerrypodWeb.Admin.Settings do
phx-value-id={@connection.id}
data-confirm={"Disconnect from #{@provider_label}? Your synced products will remain in your shop."}
class="admin-link-danger"
style="padding: 0.375rem 0.5rem;"
>
Disconnect
</button>
@@ -590,7 +589,7 @@ defmodule BerrypodWeb.Admin.Settings do
defp stripe_setup_form(assigns) do
~H"""
<div class="admin-section-body">
<p class="admin-section-desc" style="margin-top: 0;">
<p class="admin-section-desc admin-section-desc-flush">
To accept payments, connect your Stripe account by entering your secret key.
You can find it in your
<a
@@ -604,7 +603,7 @@ defmodule BerrypodWeb.Admin.Settings do
under Developers &rarr; API keys.
</p>
<.form for={@connect_form} phx-submit="connect_stripe" style="margin-top: 1.5rem;">
<.form for={@connect_form} phx-submit="connect_stripe" class="admin-card-spaced">
<.input
field={@connect_form[:api_key]}
type="password"
@@ -612,7 +611,7 @@ defmodule BerrypodWeb.Admin.Settings do
autocomplete="off"
placeholder="sk_test_... or sk_live_..."
/>
<p class="admin-text-tertiary" style="margin-top: 0.25rem;">
<p class="admin-help-text">
Starts with <code>sk_test_</code> (test mode) or <code>sk_live_</code> (live mode).
This key is encrypted at rest in the database.
</p>
@@ -628,7 +627,7 @@ defmodule BerrypodWeb.Admin.Settings do
defp stripe_connected_view(assigns) do
~H"""
<div class="admin-stack" style="margin-top: 1rem;">
<div class="admin-stack admin-section-body">
<dl class="admin-dl">
<div class="admin-dl-row">
<dt class="admin-dl-term">API key</dt>
@@ -637,7 +636,7 @@ defmodule BerrypodWeb.Admin.Settings do
<div class="admin-dl-row">
<dt class="admin-dl-term">Webhook URL</dt>
<dd class="admin-dl-value">
<code style="font-size: 0.75rem; word-break: break-all;">{@stripe_webhook_url}</code>
<code class="admin-code-break">{@stripe_webhook_url}</code>
</dd>
</div>
<div class="admin-dl-row">
@@ -646,7 +645,7 @@ defmodule BerrypodWeb.Admin.Settings do
<%= if @stripe_has_signing_secret do %>
<code>{@stripe_signing_secret_hint}</code>
<% else %>
<span style="color: #d97706;">Not set</span>
<span class="admin-text-warning">Not set</span>
<% end %>
</dd>
</div>
@@ -658,12 +657,12 @@ defmodule BerrypodWeb.Admin.Settings do
Stripe can't reach localhost for webhooks. For local testing, run the Stripe CLI:
</p>
<pre>stripe listen --forward-to localhost:4000/webhooks/stripe</pre>
<p style="margin-top: 0.5rem; font-size: 0.75rem; color: #b45309;">
<p class="admin-help-text admin-text-warning">
The CLI will output a signing secret starting with <code>whsec_</code>. Enter it below.
</p>
</div>
<.form for={@secret_form} phx-submit="save_signing_secret" style="margin-top: 0.5rem;">
<.form for={@secret_form} phx-submit="save_signing_secret">
<.input
field={@secret_form[:signing_secret]}
type="password"
@@ -671,16 +670,15 @@ defmodule BerrypodWeb.Admin.Settings do
autocomplete="off"
placeholder="whsec_..."
/>
<div style="margin-top: 0.75rem;">
<div class="admin-form-actions-sm">
<.button phx-disable-with="Saving...">Save signing secret</.button>
</div>
</.form>
<% else %>
<div style="border-top: 1px solid var(--t-surface-sunken); padding-top: 0.75rem;">
<div class="admin-separator">
<button
phx-click="toggle_stripe_advanced"
class="admin-link-subtle admin-row"
style="--admin-row-gap: 0.25rem;"
class="admin-link-subtle admin-row admin-row-sm"
>
<.icon
name={if @advanced_open, do: "hero-chevron-down-mini", else: "hero-chevron-right-mini"}
@@ -689,8 +687,8 @@ defmodule BerrypodWeb.Admin.Settings do
</button>
<%= if @advanced_open do %>
<div style="margin-top: 0.75rem;">
<p class="admin-text-tertiary" style="margin-bottom: 0.75rem;">
<div class="admin-form-actions-sm">
<p class="admin-text-tertiary">
Override the webhook signing secret if you need to use a custom endpoint or the Stripe CLI.
</p>
<.form for={@secret_form} phx-submit="save_signing_secret">
@@ -701,7 +699,7 @@ defmodule BerrypodWeb.Admin.Settings do
autocomplete="off"
placeholder="whsec_..."
/>
<div style="margin-top: 0.75rem;">
<div class="admin-form-actions-sm">
<.button phx-disable-with="Saving...">Save signing secret</.button>
</div>
</.form>
@@ -710,7 +708,7 @@ defmodule BerrypodWeb.Admin.Settings do
</div>
<% end %>
<div style="border-top: 1px solid var(--t-surface-sunken); padding-top: 1rem;">
<div class="admin-separator-lg">
<button
phx-click="disconnect_stripe"
data-confirm="This will remove your Stripe API key and delete the webhook endpoint. Are you sure?"