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

@@ -39,19 +39,16 @@ defmodule BerrypodWeb.Admin.OrderShow do
def render(assigns) do
~H"""
<.header>
<.link navigate={~p"/admin/orders"} class="admin-link-subtle" style="font-weight: 400;">
<.link navigate={~p"/admin/orders"} class="admin-back-link">
&larr; Orders
</.link>
<div class="admin-row" style="--admin-row-gap: 0.75rem; margin-top: 0.25rem;">
<span style="font-size: 1.5rem; font-weight: 700;">{@order.order_number}</span>
<div class="admin-product-header">
<span class="admin-product-title">{@order.order_number}</span>
<.status_badge status={@order.payment_status} />
</div>
</.header>
<div
class="admin-grid"
style="--admin-grid-min: 20rem; --admin-grid-gap: 1.5rem; margin-top: 1.5rem;"
>
<div class="admin-grid order-detail-grid">
<%!-- order info --%>
<div class="admin-card">
<div class="admin-card-body">
@@ -63,7 +60,7 @@ defmodule BerrypodWeb.Admin.OrderShow do
<.status_badge status={@order.payment_status} />
</:item>
<:item :if={@order.stripe_payment_intent_id} title="Stripe payment">
<code style="font-size: 0.75rem;">{@order.stripe_payment_intent_id}</code>
<code class="admin-code-sm">{@order.stripe_payment_intent_id}</code>
</:item>
<:item title="Currency">{String.upcase(@order.currency)}</:item>
</.list>
@@ -99,20 +96,20 @@ defmodule BerrypodWeb.Admin.OrderShow do
</:item>
</.list>
<% else %>
<p class="admin-section-desc" style="margin-top: 0;">No shipping address provided</p>
<p class="admin-section-desc admin-section-desc-flush">No shipping address provided</p>
<% end %>
</div>
</div>
</div>
<%!-- timeline --%>
<div class="admin-card" style="margin-top: 1.5rem;">
<div class="admin-card admin-card-spaced">
<div class="admin-card-body">
<div class="admin-row" style="justify-content: space-between;">
<div class="admin-row admin-row-between">
<h3 class="admin-card-title">Timeline</h3>
<.fulfilment_badge status={@order.fulfilment_status} />
</div>
<div class="admin-row" style="margin-top: 0.5rem; margin-bottom: 1rem;">
<div class="admin-row order-timeline-actions">
<button
:if={can_submit?(@order)}
phx-click="submit_to_provider"
@@ -133,11 +130,10 @@ defmodule BerrypodWeb.Admin.OrderShow do
</div>
<div
:if={@order.tracking_number not in [nil, ""]}
class="admin-row"
style="margin-bottom: 1rem; font-size: 0.875rem;"
class="admin-row order-tracking"
>
<span class="admin-text-secondary"><.icon name="hero-truck-mini" class="size-4" /></span>
<span style="font-weight: 500;">{@order.tracking_number}</span>
<span class="admin-text-medium">{@order.tracking_number}</span>
<a
:if={@order.tracking_url not in [nil, ""]}
href={@order.tracking_url}
@@ -153,7 +149,7 @@ defmodule BerrypodWeb.Admin.OrderShow do
</div>
<%!-- line items --%>
<div class="admin-card" style="margin-top: 1.5rem;">
<div class="admin-card admin-card-spaced">
<div class="admin-card-body">
<h3 class="admin-card-title">Items</h3>
<table class="admin-table admin-table-zebra">
@@ -161,28 +157,28 @@ defmodule BerrypodWeb.Admin.OrderShow do
<tr>
<th>Product</th>
<th>Variant</th>
<th style="text-align: end;">Qty</th>
<th style="text-align: end;">Unit price</th>
<th style="text-align: end;">Total</th>
<th class="admin-cell-end">Qty</th>
<th class="admin-cell-end">Unit price</th>
<th class="admin-cell-end">Total</th>
</tr>
</thead>
<tbody>
<tr :for={item <- @order.items}>
<td>{item.product_name}</td>
<td>{item.variant_title}</td>
<td style="text-align: end;">{item.quantity}</td>
<td style="text-align: end;">{Cart.format_price(item.unit_price)}</td>
<td style="text-align: end;">{Cart.format_price(item.unit_price * item.quantity)}</td>
<td class="admin-cell-numeric">{item.quantity}</td>
<td class="admin-cell-numeric">{Cart.format_price(item.unit_price)}</td>
<td class="admin-cell-numeric">{Cart.format_price(item.unit_price * item.quantity)}</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="4" style="text-align: end; font-weight: 500;">Subtotal</td>
<td style="text-align: end; font-weight: 500;">{Cart.format_price(@order.subtotal)}</td>
<td colspan="4" class="admin-cell-end admin-text-medium">Subtotal</td>
<td class="admin-cell-end admin-text-medium">{Cart.format_price(@order.subtotal)}</td>
</tr>
<tr style="font-size: 1.125rem;">
<td colspan="4" style="text-align: end; font-weight: 700;">Total</td>
<td style="text-align: end; font-weight: 700;">{Cart.format_price(@order.total)}</td>
<tr class="order-total-row">
<td colspan="4" class="admin-cell-end admin-text-bold">Total</td>
<td class="admin-cell-end admin-text-bold">{Cart.format_price(@order.total)}</td>
</tr>
</tfoot>
</table>
@@ -237,7 +233,7 @@ defmodule BerrypodWeb.Admin.OrderShow do
defp order_timeline(assigns) do
~H"""
<div :if={@entries == []} class="admin-section-desc" style="padding-block: 1rem; margin-top: 0;">
<div :if={@entries == []} class="admin-section-desc order-timeline-empty">
No activity recorded yet.
</div>
<ol :if={@entries != []} class="admin-timeline" id="order-timeline">