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

@@ -40,7 +40,7 @@
<!-- Header -->
<div class="theme-header">
<div style="flex: 1;">
<div class="admin-fill">
<h1 class="theme-title">Theme Studio</h1>
<p class="theme-subtitle">
One theme, infinite possibilities. Every combination is designed to work beautifully.
@@ -50,7 +50,6 @@
type="button"
phx-click="toggle_sidebar"
class="theme-collapse-btn"
style="margin: -0.25rem -0.5rem 0 0;"
aria-label="Collapse sidebar"
aria-expanded="true"
aria-controls="theme-sidebar"
@@ -69,7 +68,7 @@
</div>
<!-- Site Name -->
<div class="theme-field" style="margin-bottom: 1.5rem;">
<div class="theme-section">
<label class="theme-section-label">Shop name</label>
<form phx-change="update_setting" phx-value-field="site_name">
<input
@@ -77,18 +76,17 @@
name="site_name"
value={@theme_settings.site_name}
placeholder="Your shop name"
class="admin-input"
style="padding: 0.75rem 1rem; font-size: 1rem;"
class="admin-input admin-input-lg"
/>
</form>
</div>
<!-- Branding Section -->
<div class="theme-panel">
<label class="theme-section-label" style="margin-bottom: 1rem;">Logo & header</label>
<label class="theme-section-label">Logo & header</label>
<!-- Logo Mode Radio Cards -->
<div class="admin-stack" style="--admin-stack-gap: 0.5rem; margin-bottom: 1rem;">
<div class="admin-stack admin-stack-sm theme-field">
<%= for {value, title, desc} <- [
{"text-only", "Shop name only", "Your name in the heading font"},
{"logo-text", "Logo + shop name", "Your logo image with name beside it"},
@@ -124,7 +122,7 @@
]}>
</span>
</span>
<div style="flex: 1;">
<div class="admin-fill">
<div class="theme-radio-title">{title}</div>
<div class="admin-text-secondary">{desc}</div>
</div>
@@ -135,11 +133,11 @@
<!-- Logo Upload (for logo-text and logo-only modes) -->
<%= if @theme_settings.logo_mode in ["logo-text", "logo-only"] do %>
<div class="theme-subsection">
<span class="theme-slider-label" style="display: block; margin-bottom: 0.5rem;">
<span class="theme-slider-label theme-block-label">
Upload logo (SVG or PNG)
</span>
<div class="admin-row" style="--admin-row-gap: 0.75rem;">
<form phx-change="noop" phx-submit="noop" style="flex: 1;">
<div class="admin-row admin-row-lg">
<form phx-change="noop" phx-submit="noop" class="admin-fill">
<label class="theme-upload-label">
<span>Choose file...</span>
<.live_file_input upload={@uploads.logo_upload} class="hidden" />
@@ -163,17 +161,16 @@
<form
phx-change="update_image_alt"
phx-value-image-id={@logo_image.id}
style="margin-top: 0.5rem;"
class="theme-subfield-sm"
>
<label class="admin-row" style="--admin-row-gap: 0.5rem;">
<label class="admin-row">
<span class="admin-text-secondary shrink-0">Alt text</span>
<input
type="text"
name="alt"
value={@logo_image.alt || ""}
placeholder="Describe this image"
class="admin-input admin-input-sm"
style="flex: 1;"
class="admin-input admin-input-sm admin-fill"
phx-debounce="blur"
/>
</label>
@@ -221,7 +218,7 @@
<form
phx-change="update_setting"
phx-value-field="logo_size"
style="margin-top: 0.75rem;"
class="theme-subfield"
>
<div class="theme-slider-header">
<span class="theme-slider-label">Logo size</span>
@@ -234,13 +231,12 @@
value={@theme_settings.logo_size}
name="logo_size"
class="admin-range"
style="width: 100%;"
/>
</form>
<!-- SVG Recolor Toggle (only for SVG logos) -->
<%= if @logo_image.is_svg do %>
<div style="margin-top: 0.75rem;">
<div class="theme-subfield">
<label class="admin-toggle-label">
<input
type="checkbox"
@@ -261,8 +257,7 @@
phx-change="update_color"
phx-value-field="logo_color"
phx-hook="ColorSync"
class="theme-color-row"
style="margin-top: 0.5rem;"
class="theme-color-row theme-subfield-sm"
>
<input
type="color"
@@ -283,12 +278,12 @@
<!-- Site Icon / Favicon -->
<div class="theme-panel">
<label class="theme-section-label">Site icon</label>
<p class="admin-text-tertiary" style="margin-bottom: 1rem;">
<p class="admin-text-tertiary theme-field">
Your icon appears in browser tabs and on home screens.
</p>
<!-- Use logo as icon toggle -->
<label class="admin-toggle-label" style="margin-bottom: 1rem;">
<label class="admin-toggle-label theme-field">
<input
type="checkbox"
checked={@theme_settings.use_logo_as_icon}
@@ -301,12 +296,12 @@
<!-- Icon upload (only when not using logo) -->
<%= if !@theme_settings.use_logo_as_icon do %>
<div style="padding-top: 0.75rem; border-top: 1px solid var(--t-border-default);">
<span class="theme-slider-label" style="display: block; margin-bottom: 0.5rem;">
<div class="admin-separator">
<span class="theme-slider-label theme-block-label">
Upload icon (PNG or SVG, 512×512+)
</span>
<div class="admin-row" style="--admin-row-gap: 0.75rem;">
<form phx-change="noop" phx-submit="noop" style="flex: 1;">
<div class="admin-row admin-row-lg">
<form phx-change="noop" phx-submit="noop" class="admin-fill">
<label class="theme-upload-label">
<span>Choose file...</span>
<.live_file_input upload={@uploads.icon_upload} class="hidden" />
@@ -369,9 +364,9 @@
<% end %>
<!-- Short name -->
<div class="theme-subsection" style="padding-top: 0.75rem;">
<div class="theme-subfield">
<form phx-change="update_setting" phx-value-field="favicon_short_name">
<div class="theme-slider-header" style="margin-bottom: 0.25rem;">
<div class="theme-slider-header">
<span class="theme-slider-label">Short name</span>
<span class="admin-text-tertiary">Home screen label</span>
</div>
@@ -387,7 +382,7 @@
</div>
<!-- Icon background colour -->
<div style="margin-top: 0.75rem;">
<div class="theme-subfield">
<form
id="icon-bg-color-form"
phx-change="update_color"
@@ -402,8 +397,8 @@
class="theme-color-swatch theme-color-swatch-sm"
/>
<div>
<span class="theme-slider-label" style="display: block;">Icon background</span>
<span class="theme-slider-value" style="font-size: 0.75rem;">
<span class="theme-slider-label theme-block-label">Icon background</span>
<span class="theme-slider-value">
{@theme_settings.icon_background_color}
</span>
</div>
@@ -412,7 +407,7 @@
</div>
<!-- Header Background Toggle -->
<div style="margin-bottom: 1.5rem;">
<div class="theme-section">
<label class="admin-toggle-label">
<input
type="checkbox"
@@ -424,7 +419,7 @@
}
class="admin-toggle admin-toggle-sm"
/>
<span style="font-size: 0.875rem; color: color-mix(in oklch, var(--t-text-primary) 80%, transparent);">
<span class="theme-check-text">
Header background image
</span>
</label>
@@ -433,7 +428,7 @@
<!-- Header Image Upload (only when enabled) -->
<%= if @theme_settings.header_background_enabled do %>
<div class="theme-panel">
<span class="theme-slider-label" style="display: block; margin-bottom: 0.5rem;">
<span class="theme-slider-label theme-block-label">
Upload header image
</span>
<form phx-change="noop" phx-submit="noop">
@@ -461,17 +456,16 @@
<form
phx-change="update_image_alt"
phx-value-image-id={@header_image.id}
style="margin-top: 0.5rem;"
class="theme-subfield-sm"
>
<label class="admin-row" style="--admin-row-gap: 0.5rem;">
<label class="admin-row">
<span class="admin-text-secondary shrink-0">Alt text</span>
<input
type="text"
name="alt"
value={@header_image.alt || ""}
placeholder="Describe this image"
class="admin-input admin-input-sm"
style="flex: 1;"
class="admin-input admin-input-sm admin-fill"
phx-debounce="blur"
/>
</label>
@@ -484,7 +478,7 @@
</form>
<!-- Header Image Controls -->
<div class="admin-stack" style="--admin-stack-gap: 0.75rem; margin-top: 0.75rem;">
<div class="admin-stack admin-stack-md theme-subfield">
<form phx-change="update_setting" phx-value-field="header_zoom">
<div class="theme-slider-header">
<span class="theme-slider-label">Zoom</span>
@@ -497,7 +491,6 @@
value={@theme_settings.header_zoom}
name="header_zoom"
class="admin-range"
style="width: 100%;"
/>
</form>
<form phx-change="update_setting" phx-value-field="header_position_x">
@@ -512,7 +505,6 @@
value={@theme_settings.header_position_x}
name="header_position_x"
class="admin-range"
style="width: 100%;"
/>
</form>
<form phx-change="update_setting" phx-value-field="header_position_y">
@@ -527,7 +519,6 @@
value={@theme_settings.header_position_y}
name="header_position_y"
class="admin-range"
style="width: 100%;"
/>
</form>
</div>
@@ -565,7 +556,7 @@
<% end %>
<!-- Presets Section -->
<div style="margin-bottom: 1.5rem;">
<div class="theme-section">
<label class="theme-section-label">Start with a preset</label>
<div class="theme-presets">
<%= for {preset_name, description} <- @presets_with_descriptions do %>
@@ -586,7 +577,7 @@
</div>
<!-- Accent Colors -->
<div style="margin-bottom: 1.5rem;">
<div class="theme-section">
<label class="theme-section-label">Accent colour</label>
<form
id="accent-color-form"
@@ -607,7 +598,7 @@
</form>
</div>
<div style="margin-bottom: 1.5rem;">
<div class="theme-section">
<label class="theme-section-label">Hover colour</label>
<form
id="secondary-accent-color-form"
@@ -628,7 +619,7 @@
</form>
</div>
<div style="margin-bottom: 1.5rem;">
<div class="theme-section">
<label class="theme-section-label">Sale colour</label>
<form
id="sale-color-form"
@@ -668,7 +659,7 @@
</svg>
</summary>
<div style="padding-top: 1rem;">
<div class="theme-customise-body">
<!-- Typography Group -->
<div class="theme-group">
<div class="theme-group-header">
@@ -867,7 +858,7 @@
phx-value-field="announcement_bar"
class="admin-checkbox admin-checkbox-sm"
/>
<span style="font-size: 0.875rem;">Announcement bar</span>
<span class="theme-check-text">Announcement bar</span>
</label>
</div>
@@ -880,13 +871,13 @@
phx-value-field="sticky_header"
class="admin-checkbox admin-checkbox-sm"
/>
<span style="font-size: 0.875rem;">Sticky header</span>
<span class="theme-check-text">Sticky header</span>
</label>
</div>
</div>
<!-- Shape Group -->
<div style="margin-bottom: 1rem;">
<div class="theme-group-flush">
<div class="theme-group-header">
<svg
class="theme-group-icon"
@@ -1045,7 +1036,7 @@
phx-value-field="hover_image"
class="admin-checkbox admin-checkbox-sm"
/>
<span style="font-size: 0.875rem;">Second image on hover</span>
<span class="theme-check-text">Second image on hover</span>
</label>
</div>
@@ -1058,13 +1049,13 @@
phx-value-field="show_prices"
class="admin-checkbox admin-checkbox-sm"
/>
<span style="font-size: 0.875rem;">Show prices</span>
<span class="theme-check-text">Show prices</span>
</label>
</div>
</div>
<!-- Product Page Group -->
<div style="margin-bottom: 1rem;">
<div class="theme-group-flush">
<div class="theme-group-header">
<svg
class="theme-group-icon"
@@ -1088,7 +1079,7 @@
phx-value-field="pdp_trust_badges"
class="admin-checkbox admin-checkbox-sm"
/>
<span style="font-size: 0.875rem;">Trust badges</span>
<span class="theme-check-text">Trust badges</span>
</label>
</div>
@@ -1101,7 +1092,7 @@
phx-value-field="pdp_reviews"
class="admin-checkbox admin-checkbox-sm"
/>
<span style="font-size: 0.875rem;">Reviews section</span>
<span class="theme-check-text">Reviews section</span>
</label>
</div>
@@ -1114,7 +1105,7 @@
phx-value-field="pdp_related_products"
class="admin-checkbox admin-checkbox-sm"
/>
<span style="font-size: 0.875rem;">Related products</span>
<span class="theme-check-text">Related products</span>
</label>
</div>
</div>