perf: improve SEO and accessibility for PageSpeed

- Add meta description tag with theme_settings.site_description fallback
- Add site_description field to ThemeSettings schema
- Fix color contrast on tertiary text (WCAG AA compliance)
  - Clean mood: #a3a3a3 → #737373
  - Warm mood: #a8a29e → #78716c
  - Cool mood: #94a3b8 → #64748b
- Add width/height attributes to product images to prevent CLS:
  - Product cards: 600x600
  - Cart items: 96x96
  - Gallery thumbnails: 150x150
  - Lightbox: 1200x1200

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jamey Greenwood 2026-01-21 21:55:55 +00:00
parent f29772010e
commit 7fbde87c5b
4 changed files with 20 additions and 3 deletions

View File

@ -16,6 +16,7 @@ defmodule SimpleshopTheme.Settings.ThemeSettings do
# Branding
field :site_name, :string, default: "Store Name"
field :site_description, :string, default: "Discover unique products and original designs."
field :logo_mode, :string, default: "text-only"
field :logo_image_id, :binary_id
field :logo_size, :integer, default: 36
@ -62,6 +63,7 @@ defmodule SimpleshopTheme.Settings.ThemeSettings do
:header_layout,
:accent_color,
:site_name,
:site_description,
:logo_mode,
:logo_image_id,
:logo_size,

View File

@ -58,7 +58,7 @@ defmodule SimpleshopTheme.Theme.CSSGenerator do
--t-surface-overlay: rgba(255, 255, 255, 0.95);
--t-text-primary: #171717;
--t-text-secondary: #525252;
--t-text-tertiary: #a3a3a3;
--t-text-tertiary: #737373;
--t-text-inverse: #ffffff;
--t-border-default: #e5e5e5;
--t-border-subtle: #f0f0f0;
@ -73,7 +73,7 @@ defmodule SimpleshopTheme.Theme.CSSGenerator do
--t-surface-overlay: rgba(253, 248, 243, 0.95);
--t-text-primary: #1c1917;
--t-text-secondary: #57534e;
--t-text-tertiary: #a8a29e;
--t-text-tertiary: #78716c;
--t-text-inverse: #ffffff;
--t-border-default: #e7e0d8;
--t-border-subtle: #f0ebe4;
@ -88,7 +88,7 @@ defmodule SimpleshopTheme.Theme.CSSGenerator do
--t-surface-overlay: rgba(244, 247, 251, 0.95);
--t-text-primary: #0f172a;
--t-text-secondary: #475569;
--t-text-tertiary: #94a3b8;
--t-text-tertiary: #64748b;
--t-text-inverse: #ffffff;
--t-border-default: #d4dce8;
--t-border-subtle: #e8eff5;

View File

@ -4,6 +4,7 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="csrf-token" content={get_csrf_token()} />
<meta name="description" content={assigns[:page_description] || @theme_settings.site_description || "Welcome to #{@theme_settings.site_name}"} />
<.live_title><%= assigns[:page_title] || @theme_settings.site_name %></.live_title>
<link phx-track-static rel="stylesheet" href={~p"/assets/css/app.css"} />
<script defer phx-track-static type="text/javascript" src={~p"/assets/js/app.js"}>

View File

@ -860,6 +860,8 @@ defmodule SimpleshopThemeWeb.ShopComponents do
<img
src={@product.image_url}
alt={@product.name}
width="600"
height="600"
loading={if @variant == :minimal, do: nil, else: "lazy"}
decoding={if @variant == :minimal, do: nil, else: "async"}
class="product-image-primary w-full h-full object-cover transition-opacity duration-300"
@ -868,6 +870,8 @@ defmodule SimpleshopThemeWeb.ShopComponents do
<img
src={@product.hover_image_url}
alt={@product.name}
width="600"
height="600"
loading={if @variant == :minimal, do: nil, else: "lazy"}
decoding={if @variant == :minimal, do: nil, else: "async"}
class="product-image-hover w-full h-full object-cover"
@ -2255,6 +2259,9 @@ defmodule SimpleshopThemeWeb.ShopComponents do
<img
src={@item.product.image_url}
alt={@item.product.name}
width="96"
height="96"
loading="lazy"
class="w-full h-full object-cover"
/>
</div>
@ -2696,6 +2703,8 @@ defmodule SimpleshopThemeWeb.ShopComponents do
id={"#{@id_prefix}-main-image"}
src={List.first(@images)}
alt={@product_name}
width="600"
height="600"
class="w-full h-full object-cover"
/>
<div class="absolute inset-0 flex items-center justify-center opacity-0 hover:opacity-100 transition-opacity bg-black/10">
@ -2721,6 +2730,9 @@ defmodule SimpleshopThemeWeb.ShopComponents do
<img
src={img_url}
alt={@product_name}
width="150"
height="150"
loading="lazy"
class="w-full h-full object-cover"
/>
</button>
@ -2787,6 +2799,8 @@ defmodule SimpleshopThemeWeb.ShopComponents do
id="lightbox-image"
src={List.first(@images)}
alt={@product_name}
width="1200"
height="1200"
/>
</div>
<figcaption class="lightbox-caption"><%= @product_name %></figcaption>