Rework the Live preview to match D9's actual screenshot
Replaces the earlier sidebar+small-phone mock with D9's real layout: App/ Website/Email tabs (App is the only one with real content, so these are static labels not a working control), a full-size phone mock, and a public- site mock, plus the "Where the brand shows up" list. The phone's "Next up" card now uses primary, not secondary -- it's a notice, not a call to action, so it shouldn't compete visually with an actual accent-coloured button. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ECGMEwrc2k4D8VQuwjstj9
This commit is contained in:
@@ -115,56 +115,66 @@
|
||||
<div class="xl:sticky xl:top-4 xl:self-start">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="card-title">{% lucide "eye" size=16 %} {% trans "Live preview" %}</div>
|
||||
<p class="text-xs text-muted">{% trans "Where these colours actually show up -- updates as you edit, before you save anything." %}</p>
|
||||
|
||||
<div class="mt-2 font-display text-[11px] font-bold tracking-[.12em] text-muted uppercase">{% trans "Management app" %}</div>
|
||||
<div class="preview-frame mt-1.5">
|
||||
<div id="preview-sidebar" class="preview-sidebar">
|
||||
<div class="preview-crest">{{ club.initials|default:"CL" }}</div>
|
||||
<div class="preview-club-name">{{ club.name|default:_("Your club") }}</div>
|
||||
<div class="preview-nav-item">{% trans "Overview" %}</div>
|
||||
<div id="preview-nav-active" class="preview-nav-item preview-nav-active">{% trans "Members" %}</div>
|
||||
<div class="preview-nav-item">{% trans "Calendar" %}</div>
|
||||
</div>
|
||||
<div class="preview-panel">
|
||||
<div class="preview-panel-heading">{% trans "New member" %}</div>
|
||||
<button type="button" id="preview-button" class="preview-button">{% trans "Save changes" %}</button>
|
||||
<div class="preview-skeleton-line"></div>
|
||||
<div class="preview-skeleton-line preview-skeleton-line-short"></div>
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<div class="card-title">{% lucide "eye" size=16 %} {% trans "Live preview" %}</div>
|
||||
<div class="flex overflow-hidden rounded-md border border-line">
|
||||
<span class="preview-tab preview-tab-active">{% trans "App" %}</span>
|
||||
<span class="preview-tab">{% trans "Website" %}</span>
|
||||
<span class="preview-tab">{% trans "Email" %}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex items-center justify-between gap-2">
|
||||
<div class="font-display text-[11px] font-bold tracking-[.12em] text-muted uppercase">{% trans "Mobile app" %}</div>
|
||||
<span class="badge badge-sm badge-ghost">{% trans "Coming soon" %}</span>
|
||||
</div>
|
||||
<div class="mt-1.5 preview-phone">
|
||||
<div id="preview-phone-header" class="preview-phone-header">
|
||||
<div class="preview-phone-header-row">
|
||||
<span class="preview-crest preview-crest-sm">{{ club.initials|default:"CL" }}</span>
|
||||
<span class="preview-phone-name">{{ club.name|default:_("Your club") }}</span>
|
||||
<div class="mt-3 flex flex-wrap items-start gap-4">
|
||||
<div class="preview-phone-lg">
|
||||
<div id="preview-phone-header" class="preview-phone-header">
|
||||
<div class="preview-phone-header-row">
|
||||
<span class="preview-crest preview-crest-sm">{{ club.initials|default:"CL" }}</span>
|
||||
<span class="preview-phone-name">{{ club.name|default:_("Your club") }}</span>
|
||||
</div>
|
||||
<div class="preview-phone-roles">
|
||||
<span class="preview-phone-role preview-phone-role-active">{% trans "Member" %}</span>
|
||||
<span class="preview-phone-role">{% trans "Coach" %}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="preview-phone-roles">
|
||||
<span class="preview-phone-role preview-phone-role-active">{% trans "Member" %}</span>
|
||||
<span class="preview-phone-role">{% trans "Coach" %}</span>
|
||||
<div class="preview-phone-body">
|
||||
{# A notice, not a call to action -- primary (chrome), not secondary (accent), so it doesn't visually compete with an actual button. #}
|
||||
<div id="preview-phone-card" class="preview-phone-card">
|
||||
<div class="preview-phone-eyebrow">{% trans "Next up" %}</div>
|
||||
<div class="preview-phone-title">{% trans "U16 vs Leuven" %}</div>
|
||||
<div class="preview-phone-bar"></div>
|
||||
</div>
|
||||
<div class="preview-phone-skeleton-card">
|
||||
<div class="preview-skeleton-line"></div>
|
||||
<div class="preview-skeleton-line preview-skeleton-line-short"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="preview-phone-body">
|
||||
<div id="preview-phone-card" class="preview-phone-card">
|
||||
<div class="preview-phone-eyebrow">{% trans "Next up" %}</div>
|
||||
<div class="preview-phone-title">{% trans "U16 vs Leuven" %}</div>
|
||||
<div class="preview-phone-bar"></div>
|
||||
</div>
|
||||
<div class="preview-phone-skeleton-card">
|
||||
<div class="preview-skeleton-line"></div>
|
||||
<div class="preview-skeleton-line preview-skeleton-line-short"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 text-xs text-dim">
|
||||
{% trans "Never used for: status colours (paid/overdue, present/absent), table styling, or form fields -- those stay consistent for everyone regardless of club branding." %}
|
||||
<div class="flex min-w-0 flex-1 flex-col gap-3">
|
||||
<div class="preview-website">
|
||||
<div id="preview-website-header" class="preview-website-header">
|
||||
<span class="preview-crest preview-crest-sm">{{ club.initials|default:"CL" }}</span>
|
||||
<span class="preview-website-name">{{ club.name|default:_("Your club") }}</span>
|
||||
<span class="preview-website-nav">{% trans "Teams · Club" %}</span>
|
||||
<span id="preview-website-join" class="preview-website-join">{% trans "Join" %}</span>
|
||||
</div>
|
||||
<div class="preview-website-hero">
|
||||
<div class="preview-website-headline">{% trans "#Fear the Sharks" %}</div>
|
||||
<div class="preview-skeleton-line"></div>
|
||||
<div class="preview-skeleton-line preview-skeleton-line-short"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border border-line p-3">
|
||||
<div class="mb-2 font-display text-[11px] font-bold tracking-[.12em] text-muted uppercase">{% trans "Where the brand shows up" %}</div>
|
||||
<ul class="flex flex-col gap-1.5 text-[13px] text-slate">
|
||||
<li class="flex items-center gap-2"><span id="preview-dot-1" class="preview-brand-dot"></span>{% trans "Sidebar, active nav item, primary buttons" %}</li>
|
||||
<li class="flex items-center gap-2"><span id="preview-dot-2" class="preview-brand-dot"></span>{% trans "Public site header and join button" %}</li>
|
||||
<li class="flex items-center gap-2"><span id="preview-dot-3" class="preview-brand-dot"></span>{% trans "Mobile app header and highlights" %}</li>
|
||||
<li class="flex items-center gap-2"><span class="preview-brand-dot preview-brand-dot-neutral"></span>{% trans "Never: status colours, tables, form fields" %}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -218,17 +228,21 @@
|
||||
const primaryContent = contentColorFor(primary);
|
||||
const secondaryContent = contentColorFor(secondary);
|
||||
|
||||
document.getElementById("preview-sidebar").style.background = primary;
|
||||
document.getElementById("preview-sidebar").style.color = primaryContent;
|
||||
document.getElementById("preview-nav-active").style.background = secondary;
|
||||
document.getElementById("preview-nav-active").style.color = secondaryContent;
|
||||
document.getElementById("preview-button").style.background = secondary;
|
||||
document.getElementById("preview-button").style.color = secondaryContent;
|
||||
|
||||
document.getElementById("preview-phone-header").style.background = primary;
|
||||
document.getElementById("preview-phone-header").style.color = primaryContent;
|
||||
document.getElementById("preview-phone-card").style.background = secondary;
|
||||
document.getElementById("preview-phone-card").style.color = secondaryContent;
|
||||
// A notice, not a call to action -- primary (chrome), not secondary
|
||||
// (accent), so it doesn't compete for attention with an actual button.
|
||||
document.getElementById("preview-phone-card").style.background = primary;
|
||||
document.getElementById("preview-phone-card").style.color = primaryContent;
|
||||
|
||||
document.getElementById("preview-website-header").style.background = primary;
|
||||
document.getElementById("preview-website-header").style.color = primaryContent;
|
||||
document.getElementById("preview-website-join").style.background = secondary;
|
||||
document.getElementById("preview-website-join").style.color = secondaryContent;
|
||||
|
||||
["preview-dot-1", "preview-dot-2", "preview-dot-3"].forEach((id) => {
|
||||
document.getElementById(id).style.background = secondary;
|
||||
});
|
||||
|
||||
setContrastBox("contrast-box-primary", "contrast-label-primary", "contrast-ratio-primary", primary, primaryContent, "{% trans 'on primary' %}");
|
||||
setContrastBox("contrast-box-secondary", "contrast-label-secondary", "contrast-ratio-secondary", secondary, secondaryContent, "{% trans 'on secondary' %}");
|
||||
|
||||
@@ -4465,18 +4465,19 @@ class ClubSettingsPreviewTests(ManagementTestBase):
|
||||
def setUp(self):
|
||||
self.client.force_login(self.admin_user)
|
||||
|
||||
def test_the_preview_frame_and_colour_swatches_render(self):
|
||||
def test_the_preview_tabs_and_colour_swatches_render(self):
|
||||
response = self.club_get("club_settings")
|
||||
|
||||
self.assertContains(response, "preview-sidebar")
|
||||
self.assertContains(response, "preview-tab-active")
|
||||
self.assertContains(response, 'id="primary_color_swatch"')
|
||||
self.assertContains(response, 'id="secondary_color_swatch"')
|
||||
|
||||
def test_the_mobile_app_preview_renders(self):
|
||||
def test_the_mobile_app_and_website_previews_render(self):
|
||||
response = self.club_get("club_settings")
|
||||
|
||||
self.assertContains(response, "preview-phone")
|
||||
self.assertContains(response, "Coming soon")
|
||||
self.assertContains(response, "preview-phone-lg")
|
||||
self.assertContains(response, "preview-website")
|
||||
self.assertContains(response, "Where the brand shows up")
|
||||
|
||||
def test_the_website_field_is_editable(self):
|
||||
response = self.club_get("club_settings")
|
||||
|
||||
Reference in New Issue
Block a user