feat: enhance contact page with newsletter and social cards

Add newsletter_card component with :card and :inline variants to share
between footer and contact page. Add social_links_card component with
full-width icon+text cards for better discoverability.

Improve contact_form with optional email link and response time display,
keeping important contact info above the fold. Reorganize contact page
layout with form on left, info cards on right.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jamey Greenwood 2026-01-20 19:13:48 +00:00
parent 1f5498d7d8
commit 6b45846d6d
3 changed files with 147 additions and 51 deletions

View File

@ -339,29 +339,7 @@ This ensures sellers never unknowingly sell at a loss due to Printify price chan
## Quick Wins (Low Effort)
### Enhanced Contact Page
**Status:** Not implemented
**Effort:** Small
The current contact page has subtle footer social icons that are easy to miss. Improvements:
1. **Newsletter signup card** - Prominent card encouraging newsletter subscription as the best way to stay updated (already in footer, but deserves dedicated placement)
2. **Social media links card** - Full-width card listing social platforms with icons and text labels:
```
[Instagram icon] Instagram
[Patreon icon] Patreon
[TikTok icon] TikTok
[Facebook icon] Facebook
[Pinterest icon] Pinterest
```
This makes social links more discoverable than the current small footer icons.
**Implementation:**
- Add `newsletter_card/1` component to ShopComponents
- Add `social_links_card/1` component with configurable platforms
- Update contact page template to include both cards
- Consider making platforms configurable via theme settings
*(None pending)*
---
@ -488,3 +466,9 @@ The project is currently named `simpleshop_theme` (reflecting its origins as a t
- Current page is not a link (avoids self-links)
- Logo links to home except when on home page
- `aria-current="page"` with visual underline indicator
### Enhanced Contact Page ✅
- `newsletter_card` component with `:card` and `:inline` variants (shared with footer)
- `social_links_card` component with icon + text label cards
- Contact form with integrated email link and response time
- Reorganized layout: contact form left, info cards right

View File

@ -15,7 +15,7 @@
/>
<div class="grid gap-8 md:grid-cols-2 mb-12">
<.contact_form />
<.contact_form email="hello@example.com" response_time="We typically respond within 24 hours" />
<div class="space-y-6">
<.order_tracking_card />
@ -26,9 +26,9 @@
%{label: "Returns", value: "Happy to help with faulty or damaged items"}
]} />
<.contact_info_card email="hello@example.com" />
<.newsletter_card />
<.social_links />
<.social_links_card />
</div>
</div>
</main>

View File

@ -147,30 +147,7 @@ defmodule SimpleshopThemeWeb.ShopComponents do
<footer style="background-color: var(--t-surface-raised); border-top: 1px solid var(--t-border-default);">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
<div class="grid grid-cols-1 md:grid-cols-2 gap-12">
<!-- Newsletter -->
<div>
<h3 class="text-xl font-bold mb-2" style="font-family: var(--t-font-heading); color: var(--t-text-primary); font-weight: var(--t-heading-weight);">
Stay in touch
</h3>
<p class="mb-4 text-sm" style="color: var(--t-text-secondary);">
Get 10% off your first order and be the first to know about new designs.
</p>
<form class="flex flex-wrap gap-2">
<input
type="email"
placeholder="your@email.com"
class="flex-1 min-w-0 px-4 py-2 text-sm"
style="background-color: var(--t-surface-base); color: var(--t-text-primary); border: 1px solid var(--t-border-default); border-radius: var(--t-radius-input); min-width: 150px;"
/>
<button
type="submit"
class="px-6 py-2 font-medium transition-all text-sm whitespace-nowrap"
style="background-color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l)); color: var(--t-text-inverse); border-radius: var(--t-radius-button);"
>
Subscribe
</button>
</form>
</div>
<.newsletter_card variant={:inline} />
<!-- Links -->
<div class="grid grid-cols-2 gap-8">
@ -1479,13 +1456,18 @@ defmodule SimpleshopThemeWeb.ShopComponents do
## Attributes
* `title` - Optional. Form heading. Defaults to "Send us a message".
* `email` - Optional. If provided, displays "or email us at [email]" below the title.
* `response_time` - Optional. Response time text shown below email (e.g., "We typically respond within 24 hours").
## Examples
<.contact_form />
<.contact_form title="Get in touch" />
<.contact_form email="hello@example.com" response_time="We typically respond within 24 hours" />
"""
attr :title, :string, default: "Send us a message"
attr :email, :string, default: nil
attr :response_time, :string, default: nil
def contact_form(assigns) do
~H"""
@ -1493,9 +1475,21 @@ defmodule SimpleshopThemeWeb.ShopComponents do
class="p-8"
style="background-color: var(--t-surface-raised); border: 1px solid var(--t-border-default); border-radius: var(--t-radius-card);"
>
<h2 class="text-xl font-bold mb-6" style="font-family: var(--t-font-heading); color: var(--t-text-primary);">
<h2 class="text-xl font-bold mb-2" style="font-family: var(--t-font-heading); color: var(--t-text-primary);">
<%= @title %>
</h2>
<%= if @email || @response_time do %>
<div class="mb-6 text-sm space-y-1" style="color: var(--t-text-secondary);">
<%= if @email do %>
<p>or email <a href={"mailto:#{@email}"} style="color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));"><%= @email %></a></p>
<% end %>
<%= if @response_time do %>
<p><%= @response_time %></p>
<% end %>
</div>
<% else %>
<div class="mb-4"></div>
<% end %>
<form class="space-y-4">
<div>
@ -1667,6 +1661,124 @@ defmodule SimpleshopThemeWeb.ShopComponents do
"""
end
@doc """
Renders a newsletter signup card.
## Attributes
* `title` - Optional. Card heading. Defaults to "Stay in touch".
* `description` - Optional. Card description.
* `button_text` - Optional. Button text. Defaults to "Subscribe".
* `variant` - Optional. Either `:card` (default, with border/background) or `:inline` (no card styling, for embedding in footer).
## Examples
<.newsletter_card />
<.newsletter_card title="Join our newsletter" description="Get updates on new products." />
<.newsletter_card variant={:inline} />
"""
attr :title, :string, default: "Stay in touch"
attr :description, :string, default: "Be the first to see new designs and get updates from the studio."
attr :button_text, :string, default: "Subscribe"
attr :variant, :atom, default: :card
def newsletter_card(%{variant: :inline} = assigns) do
~H"""
<div>
<h3 class="text-xl font-bold mb-2" style="font-family: var(--t-font-heading); color: var(--t-text-primary); font-weight: var(--t-heading-weight);">
<%= @title %>
</h3>
<p class="text-sm mb-4" style="color: var(--t-text-secondary);">
<%= @description %>
</p>
<form class="flex flex-wrap gap-2">
<input
type="email"
placeholder="your@email.com"
class="flex-1 min-w-0 px-4 py-2 text-sm"
style="background-color: var(--t-surface-base); color: var(--t-text-primary); border: 1px solid var(--t-border-default); border-radius: var(--t-radius-input); min-width: 150px;"
/>
<button
type="submit"
class="px-6 py-2 text-sm font-medium whitespace-nowrap"
style="background-color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l)); color: var(--t-text-inverse); border-radius: var(--t-radius-button);"
>
<%= @button_text %>
</button>
</form>
</div>
"""
end
def newsletter_card(assigns) do
~H"""
<div
class="p-6"
style="background-color: var(--t-surface-raised); border: 1px solid var(--t-border-default); border-radius: var(--t-radius-card);"
>
<h3 class="font-bold mb-2" style="color: var(--t-text-primary);"><%= @title %></h3>
<p class="text-sm mb-4" style="color: var(--t-text-secondary);">
<%= @description %>
</p>
<form class="flex flex-wrap gap-2">
<input
type="email"
placeholder="your@email.com"
class="flex-1 min-w-0 px-3 py-2 text-sm"
style="background-color: var(--t-surface-base); color: var(--t-text-primary); border: 1px solid var(--t-border-default); border-radius: var(--t-radius-input); min-width: 150px;"
/>
<button
type="submit"
class="px-4 py-2 text-sm font-medium whitespace-nowrap"
style="background-color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l)); color: var(--t-text-inverse); border-radius: var(--t-radius-button);"
>
<%= @button_text %>
</button>
</form>
</div>
"""
end
@doc """
Renders social media links as full-width cards with icons and text labels.
## Attributes
* `links` - Optional. List of maps with `platform`, `url`, and `label` keys.
Supported platforms: :instagram, :pinterest, :facebook, :twitter, :tiktok
## Examples
<.social_links_card />
<.social_links_card links={[%{platform: :instagram, url: "https://instagram.com/example", label: "Follow on Instagram"}]} />
"""
attr :links, :list, default: [
%{platform: :instagram, url: "#", label: "Follow on Instagram"},
%{platform: :pinterest, url: "#", label: "Follow on Pinterest"}
]
def social_links_card(assigns) do
~H"""
<div class="space-y-2">
<%= for link <- @links do %>
<a
href={link.url}
class="flex items-center gap-3 p-4 transition-all hover:opacity-80"
style="background-color: var(--t-surface-raised); border: 1px solid var(--t-border-default); border-radius: var(--t-radius-card); color: var(--t-text-primary); text-decoration: none;"
>
<span
class="w-10 h-10 flex items-center justify-center flex-shrink-0"
style="background-color: var(--t-surface-base); border-radius: var(--t-radius-button); color: var(--t-text-secondary);"
>
<.social_icon platform={link.platform} />
</span>
<span class="font-medium"><%= link.label %></span>
</a>
<% end %>
</div>
"""
end
@doc """
Renders social media icon links.