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

@@ -156,9 +156,9 @@ defmodule BerrypodWeb.Admin.Newsletter.CampaignForm do
</:subtitle>
</.header>
<div class="mt-6 max-w-2xl">
<div class="admin-content-medium admin-section">
<.form for={@form} phx-change="validate" phx-submit="save_draft">
<div class="space-y-4">
<div class="admin-stack">
<.input
field={@form[:subject]}
type="text"
@@ -178,14 +178,17 @@ defmodule BerrypodWeb.Admin.Newsletter.CampaignForm do
placeholder="Hello!\n\nYour newsletter content here.\n\nUnsubscribe: {{unsubscribe_url}}"
/>
<p :if={!readonly?(@campaign)} class="text-sm text-base-content/60">
<p
:if={!readonly?(@campaign)}
class="admin-help-text"
>
Use <code>{"{{unsubscribe_url}}"}</code>
to insert the unsubscribe link. This is required for GDPR compliance.
</p>
<p
:if={missing_unsubscribe_url?(@form[:body].value) && !readonly?(@campaign)}
class="flex items-center gap-2 text-sm text-amber-700"
class="admin-warning-text"
>
<.icon name="hero-exclamation-triangle" class="size-4 shrink-0" /> Body is missing
<code>{"{{unsubscribe_url}}"}</code>
@@ -193,15 +196,17 @@ defmodule BerrypodWeb.Admin.Newsletter.CampaignForm do
</p>
<%= if @form[:body].value && @form[:body].value != "" do %>
<details class="mt-4">
<summary class="text-sm font-medium cursor-pointer">Preview</summary>
<pre class="mt-2 p-4 bg-base-200 rounded-lg text-sm whitespace-pre-wrap overflow-auto max-h-64">{preview_body(@form[:body].value)}</pre>
<details>
<summary class="admin-preview-summary">
Preview
</summary>
<pre class="admin-preview-body">{preview_body(@form[:body].value)}</pre>
</details>
<% end %>
<div
:if={!readonly?(@campaign)}
class="flex items-center gap-3 pt-4 border-t border-base-200"
class="admin-campaign-actions"
>
<.button type="submit">
Save draft
@@ -219,8 +224,7 @@ defmodule BerrypodWeb.Admin.Newsletter.CampaignForm do
type="button"
phx-click="send_now"
data-confirm={"Send this campaign to #{@subscriber_count} subscribers now?"}
class="admin-btn admin-btn-primary"
style="background-color: var(--color-green-600)"
class="admin-btn admin-btn-primary admin-btn-success"
disabled={@subscriber_count == 0}
>
<.icon name="hero-paper-airplane" class="size-4" /> Send now
@@ -234,7 +238,7 @@ defmodule BerrypodWeb.Admin.Newsletter.CampaignForm do
</.link>
</div>
<div :if={readonly?(@campaign)} class="pt-4 border-t border-base-200">
<div :if={readonly?(@campaign)} class="admin-readonly-actions">
<.link navigate={~p"/admin/newsletter?tab=campaigns"} class="admin-btn admin-btn-ghost">
<.icon name="hero-arrow-left" class="size-4" /> Back to campaigns
</.link>