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:
@@ -39,19 +39,16 @@ defmodule BerrypodWeb.Admin.OrderShow do
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<.header>
|
||||
<.link
|
||||
navigate={~p"/admin/orders"}
|
||||
class="text-sm font-normal text-base-content/60 hover:underline"
|
||||
>
|
||||
<.link navigate={~p"/admin/orders"} class="admin-link-subtle" style="font-weight: 400;">
|
||||
← Orders
|
||||
</.link>
|
||||
<div class="flex items-center gap-3 mt-1">
|
||||
<span class="text-2xl font-bold">{@order.order_number}</span>
|
||||
<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>
|
||||
<.status_badge status={@order.payment_status} />
|
||||
</div>
|
||||
</.header>
|
||||
|
||||
<div class="grid gap-6 mt-6 lg:grid-cols-2">
|
||||
<div class="admin-grid" style="--admin-grid-min: 20rem; --admin-grid-gap: 1.5rem; margin-top: 1.5rem;">
|
||||
<%!-- 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 class="text-xs">{@order.stripe_payment_intent_id}</code>
|
||||
<code style="font-size: 0.75rem;">{@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="text-base-content/60 text-sm">No shipping address provided</p>
|
||||
<p class="admin-section-desc" style="margin-top: 0;">No shipping address provided</p>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%!-- timeline --%>
|
||||
<div class="admin-card mt-6">
|
||||
<div class="admin-card" style="margin-top: 1.5rem;">
|
||||
<div class="admin-card-body">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="admin-row" style="justify-content: space-between;">
|
||||
<h3 class="admin-card-title">Timeline</h3>
|
||||
<.fulfilment_badge status={@order.fulfilment_status} />
|
||||
</div>
|
||||
<div class="flex gap-2 mt-2 mb-4">
|
||||
<div class="admin-row" style="margin-top: 0.5rem; margin-bottom: 1rem;">
|
||||
<button
|
||||
:if={can_submit?(@order)}
|
||||
phx-click="submit_to_provider"
|
||||
@@ -133,16 +130,17 @@ defmodule BerrypodWeb.Admin.OrderShow do
|
||||
</div>
|
||||
<div
|
||||
:if={@order.tracking_number not in [nil, ""]}
|
||||
class="flex items-center gap-2 mb-4 text-sm"
|
||||
class="admin-row"
|
||||
style="margin-bottom: 1rem; font-size: 0.875rem;"
|
||||
>
|
||||
<.icon name="hero-truck-mini" class="size-4 text-base-content/60" />
|
||||
<span class="font-medium">{@order.tracking_number}</span>
|
||||
<span class="admin-text-secondary"><.icon name="hero-truck-mini" class="size-4" /></span>
|
||||
<span style="font-weight: 500;">{@order.tracking_number}</span>
|
||||
<a
|
||||
:if={@order.tracking_url not in [nil, ""]}
|
||||
href={@order.tracking_url}
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
class="text-primary hover:underline"
|
||||
class="admin-link"
|
||||
>
|
||||
Track shipment →
|
||||
</a>
|
||||
@@ -152,7 +150,7 @@ defmodule BerrypodWeb.Admin.OrderShow do
|
||||
</div>
|
||||
|
||||
<%!-- line items --%>
|
||||
<div class="admin-card mt-6">
|
||||
<div class="admin-card" style="margin-top: 1.5rem;">
|
||||
<div class="admin-card-body">
|
||||
<h3 class="admin-card-title">Items</h3>
|
||||
<table class="admin-table admin-table-zebra">
|
||||
@@ -160,28 +158,28 @@ defmodule BerrypodWeb.Admin.OrderShow do
|
||||
<tr>
|
||||
<th>Product</th>
|
||||
<th>Variant</th>
|
||||
<th class="text-right">Qty</th>
|
||||
<th class="text-right">Unit price</th>
|
||||
<th class="text-right">Total</th>
|
||||
<th style="text-align: end;">Qty</th>
|
||||
<th style="text-align: end;">Unit price</th>
|
||||
<th style="text-align: end;">Total</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr :for={item <- @order.items}>
|
||||
<td>{item.product_name}</td>
|
||||
<td>{item.variant_title}</td>
|
||||
<td class="text-right">{item.quantity}</td>
|
||||
<td class="text-right">{Cart.format_price(item.unit_price)}</td>
|
||||
<td class="text-right">{Cart.format_price(item.unit_price * item.quantity)}</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>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan="4" class="text-right font-medium">Subtotal</td>
|
||||
<td class="text-right font-medium">{Cart.format_price(@order.subtotal)}</td>
|
||||
<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>
|
||||
</tr>
|
||||
<tr class="text-lg">
|
||||
<td colspan="4" class="text-right font-bold">Total</td>
|
||||
<td class="text-right font-bold">{Cart.format_price(@order.total)}</td>
|
||||
<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>
|
||||
</tfoot>
|
||||
</table>
|
||||
@@ -236,7 +234,7 @@ defmodule BerrypodWeb.Admin.OrderShow do
|
||||
|
||||
defp order_timeline(assigns) do
|
||||
~H"""
|
||||
<div :if={@entries == []} class="text-sm text-base-content/60 py-4">
|
||||
<div :if={@entries == []} class="admin-section-desc" style="padding-block: 1rem; margin-top: 0;">
|
||||
No activity recorded yet.
|
||||
</div>
|
||||
<ol :if={@entries != []} class="admin-timeline" id="order-timeline">
|
||||
@@ -279,76 +277,40 @@ defmodule BerrypodWeb.Admin.OrderShow do
|
||||
end
|
||||
|
||||
defp fulfilment_badge(assigns) do
|
||||
{bg, text, ring, icon} =
|
||||
{color, icon} =
|
||||
case assigns.status do
|
||||
"submitted" ->
|
||||
{"bg-blue-50", "text-blue-700", "ring-blue-600/20", "hero-paper-airplane-mini"}
|
||||
|
||||
"processing" ->
|
||||
{"bg-amber-50", "text-amber-700", "ring-amber-600/20", "hero-cog-6-tooth-mini"}
|
||||
|
||||
"shipped" ->
|
||||
{"bg-purple-50", "text-purple-700", "ring-purple-600/20", "hero-truck-mini"}
|
||||
|
||||
"delivered" ->
|
||||
{"bg-green-50", "text-green-700", "ring-green-600/20", "hero-check-circle-mini"}
|
||||
|
||||
"failed" ->
|
||||
{"bg-red-50", "text-red-700", "ring-red-600/20", "hero-x-circle-mini"}
|
||||
|
||||
"cancelled" ->
|
||||
{"bg-base-200/50", "text-base-content/60", "ring-base-content/10",
|
||||
"hero-no-symbol-mini"}
|
||||
|
||||
_ ->
|
||||
{"bg-base-200/50", "text-base-content/60", "ring-base-content/10",
|
||||
"hero-minus-circle-mini"}
|
||||
"submitted" -> {"admin-status-pill-blue", "hero-paper-airplane-mini"}
|
||||
"processing" -> {"admin-status-pill-amber", "hero-cog-6-tooth-mini"}
|
||||
"shipped" -> {"admin-status-pill-purple", "hero-truck-mini"}
|
||||
"delivered" -> {"admin-status-pill-green", "hero-check-circle-mini"}
|
||||
"failed" -> {"admin-status-pill-red", "hero-x-circle-mini"}
|
||||
"cancelled" -> {"admin-status-pill-zinc", "hero-no-symbol-mini"}
|
||||
_ -> {"admin-status-pill-zinc", "hero-minus-circle-mini"}
|
||||
end
|
||||
|
||||
assigns = assign(assigns, bg: bg, text: text, ring: ring, icon: icon)
|
||||
assigns = assign(assigns, color: color, icon: icon)
|
||||
|
||||
~H"""
|
||||
<span class={[
|
||||
"inline-flex items-center gap-1 rounded-full px-2 py-1 text-xs font-medium ring-1 ring-inset",
|
||||
@bg,
|
||||
@text,
|
||||
@ring
|
||||
]}>
|
||||
<span class={["admin-status-pill", @color]}>
|
||||
<.icon name={@icon} class="size-3" /> {@status}
|
||||
</span>
|
||||
"""
|
||||
end
|
||||
|
||||
defp status_badge(assigns) do
|
||||
{bg, text, ring, icon} =
|
||||
{color, icon} =
|
||||
case assigns.status do
|
||||
"paid" ->
|
||||
{"bg-green-50", "text-green-700", "ring-green-600/20", "hero-check-circle-mini"}
|
||||
|
||||
"pending" ->
|
||||
{"bg-amber-50", "text-amber-700", "ring-amber-600/20", "hero-clock-mini"}
|
||||
|
||||
"failed" ->
|
||||
{"bg-red-50", "text-red-700", "ring-red-600/20", "hero-x-circle-mini"}
|
||||
|
||||
"refunded" ->
|
||||
{"bg-base-200/50", "text-base-content/60", "ring-base-content/10",
|
||||
"hero-arrow-uturn-left-mini"}
|
||||
|
||||
_ ->
|
||||
{"bg-base-200/50", "text-base-content/60", "ring-base-content/10",
|
||||
"hero-question-mark-circle-mini"}
|
||||
"paid" -> {"admin-status-pill-green", "hero-check-circle-mini"}
|
||||
"pending" -> {"admin-status-pill-amber", "hero-clock-mini"}
|
||||
"failed" -> {"admin-status-pill-red", "hero-x-circle-mini"}
|
||||
"refunded" -> {"admin-status-pill-zinc", "hero-arrow-uturn-left-mini"}
|
||||
_ -> {"admin-status-pill-zinc", "hero-question-mark-circle-mini"}
|
||||
end
|
||||
|
||||
assigns = assign(assigns, bg: bg, text: text, ring: ring, icon: icon)
|
||||
assigns = assign(assigns, color: color, icon: icon)
|
||||
|
||||
~H"""
|
||||
<span class={[
|
||||
"inline-flex items-center gap-1 rounded-full px-2 py-1 text-xs font-medium ring-1 ring-inset",
|
||||
@bg,
|
||||
@text,
|
||||
@ring
|
||||
]}>
|
||||
<span class={["admin-status-pill", @color]}>
|
||||
<.icon name={@icon} class="size-3" /> {@status}
|
||||
</span>
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user