Switch the mobile app's icons to lucide, matching management/controlpanel

Every icon in mobile/templates/mobile/ was a hand-rolled inline <svg> with
raw path data -- management and controlpanel have used django-lucide
throughout instead (confirmed already 100% consistent there, audited as
part of this change). django-lucide is a pure server-side Python tag with
no JS/CDN runtime dependency, so this is a drop-in swap producing the same
kind of literal <svg><path .../></svg> markup mobile already wrote by hand,
just pulled from the shared vendored icon set instead of duplicated per
call site. Mapped each shape to its nearest Lucide name: bell, house
("home" doesn't exist as a lucide name -- confirmed by hand), calendar,
newspaper, user, users, chevron-left, chevron-right, check, x. Hardcoded
hex strokes (#0b1220, #fff) became stroke="currentColor" + a text-ink/
text-white class, matching how every other icon in this app already gets
its color.

Also caught and fixed a hx-boost gap while touching coach/base.html: the
coach tab bar's own "Me" link (-> mobile:me, a Member-shell view) was
missing the hx-boost="false" every other cross-shell link already got.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ECGMEwrc2k4D8VQuwjstj9
This commit is contained in:
2026-08-21 23:08:32 +02:00
parent 1ced0619a3
commit 64d0fec547
10 changed files with 38 additions and 33 deletions

View File

@@ -1,4 +1,4 @@
{% load static i18n %}
{% load static i18n lucide %}
{% comment %}
App shell for Member mode (M1-M7) -- design_handoff_rosterchief_platform/README.md.
@@ -78,7 +78,7 @@
</a>
<div class="flex-1"></div>
<a class="relative flex h-11 w-11 shrink-0 items-center justify-center" href="{% url "mobile:notifications" %}" aria-label="{% trans "Notifications" %}">
<svg width="21" height="21" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg>
{% lucide "bell" size=21 class="text-white" %}
{% if unread_notification_count %}
<span class="absolute -top-1 -right-1 flex h-[19px] min-w-[19px] items-center justify-center rounded-full bg-club px-1 font-mono text-[11px] font-bold text-white" style="border: 2px solid var(--color-navy)">
{% if unread_notification_count > 9 %}9+{% else %}{{ unread_notification_count }}{% endif %}
@@ -111,19 +111,19 @@
<nav class="tab-bar">
<a class="tab-bar-item {% if active_tab == "home" %}tab-bar-item-active{% endif %}" href="{% url "mobile:home" %}">
<svg width="21" height="21" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9.5 12 3l9 6.5V21a1 1 0 0 1-1 1h-5v-7H9v7H4a1 1 0 0 1-1-1Z"/></svg>
{% lucide "house" size=21 %}
<span class="tab-bar-label">{% trans "Home" %}</span>
</a>
<a class="tab-bar-item {% if active_tab == "calendar" %}tab-bar-item-active{% endif %}" href="{% url "mobile:calendar" %}">
<svg width="21" height="21" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2"/><path d="M16 2v4M8 2v4M3 10h18"/></svg>
{% lucide "calendar" size=21 %}
<span class="tab-bar-label">{% trans "Calendar" %}</span>
</a>
<a class="tab-bar-item {% if active_tab == "news" %}tab-bar-item-active{% endif %}" href="{% url "mobile:news_list" %}">
<svg width="21" height="21" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 20H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h9l5 5v9a2 2 0 0 1-2 2Z"/><path d="M9 13h6M9 17h6M9 9h1"/></svg>
{% lucide "newspaper" size=21 %}
<span class="tab-bar-label">{% trans "News" %}</span>
</a>
<a class="tab-bar-item {% if active_tab == "me" %}tab-bar-item-active{% endif %}" href="{% url "mobile:me" %}">
<svg width="21" height="21" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="8" r="4"/><path d="M4 21c0-4.4 3.6-8 8-8s8 3.6 8 8"/></svg>
{% lucide "user" size=21 %}
<span class="tab-bar-label">{% trans "Me" %}</span>
</a>
</nav>

View File

@@ -1,5 +1,5 @@
{% extends "mobile/base.html" %}
{% load i18n %}
{% load i18n lucide %}
{% comment %}
M5's "Calendar sync" row -- subscribe an external calendar app (Apple/
@@ -12,7 +12,7 @@
{% block content %}
<div class="-mx-4 -mt-4 flex items-center gap-1 border-b border-line bg-white px-4 py-3">
<a class="-ml-2.5 flex h-11 w-11 shrink-0 items-center justify-center" href="{% url "mobile:me" %}" aria-label="{% trans "Back" %}">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#0b1220" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M15 5l-7 7 7 7"/></svg>
{% lucide "chevron-left" size=20 stroke_width=2.4 class="text-ink" %}
</a>
<span class="min-w-0 flex-1 truncate font-display text-xl leading-none font-extrabold text-ink uppercase">{% trans "Calendar sync" %}</span>
</div>

View File

@@ -1,5 +1,5 @@
{% extends "mobile/coach/base.html" %}
{% load i18n %}
{% load i18n lucide %}
{% comment %}
C2 -- design_handoff_rosterchief_platform/README.md's C2 section: check
@@ -50,10 +50,10 @@
<input type="hidden" name="showed_up_{{ row.pk }}" :value="state">
<div class="flex h-11 w-23 shrink-0 overflow-hidden rounded-lg">
<button type="button" class="flex-1" :class="state === 'true' ? 'bg-ok text-white' : 'bg-rule text-dim'" @click="state = 'true'" aria-label="{% trans "In" %}">
<svg class="mx-auto" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>
{% lucide "check" size=18 stroke_width=2.4 class="mx-auto" %}
</button>
<button type="button" class="flex-1" :class="state === 'false' ? 'bg-club text-white' : 'bg-rule text-dim'" @click="state = 'false'" aria-label="{% trans "Out" %}">
<svg class="mx-auto" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18M6 6l12 12"/></svg>
{% lucide "x" size=18 stroke_width=2.4 class="mx-auto" %}
</button>
</div>
{% elif row.showed_up is not None %}

View File

@@ -1,4 +1,4 @@
{% load static i18n %}
{% load static i18n lucide %}
{% comment %}
App shell for Coach mode (C1-C6) -- design_handoff_rosterchief_platform/README.md's
@@ -105,11 +105,16 @@
<nav class="coach-tab-bar">
<a class="coach-tab-bar-item {% if active_tab == "coach_today" %}coach-tab-bar-item-active{% endif %}" href="{% url "mobile:coach_today" %}">
<svg width="21" height="21" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 9.5 12 3l9 6.5V21a1 1 0 0 1-1 1h-5v-7H9v7H4a1 1 0 0 1-1-1Z"/></svg>
{% lucide "house" size=21 %}
<span class="tab-bar-label">{% trans "Today" %}</span>
</a>
<a class="coach-tab-bar-item" href="{% url "mobile:me" %}">
<svg width="21" height="21" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="8" r="4"/><path d="M4 21c0-4.4 3.6-8 8-8s8 3.6 8 8"/></svg>
{% comment %}
hx-boost="false" -- mobile:me is a Member-shell view (bg-paper, not
this page's bg-ink); see base.html's own comment for why a boosted
cross-shell swap would leave the wrong <body> class in place.
{% endcomment %}
<a class="coach-tab-bar-item" href="{% url "mobile:me" %}" hx-boost="false">
{% lucide "user" size=21 %}
<span class="tab-bar-label">{% trans "Me" %}</span>
</a>
</nav>

View File

@@ -1,5 +1,5 @@
{% extends "mobile/base.html" %}
{% load i18n %}
{% load i18n lucide %}
{% comment %}
M6 -- design_handoff_rosterchief_platform/README.md's M6 section, "Edit
@@ -17,7 +17,7 @@
<div class="-mx-4 -mt-4 flex items-center gap-1 border-b border-line bg-white px-4 py-3">
<a class="-ml-2.5 flex h-11 w-11 shrink-0 items-center justify-center" href="{% url "mobile:me" %}" aria-label="{% trans "Back" %}">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#0b1220" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M15 5l-7 7 7 7"/></svg>
{% lucide "chevron-left" size=20 stroke_width=2.4 class="text-ink" %}
</a>
<span class="min-w-0 flex-1 truncate font-display text-xl leading-none font-extrabold text-ink uppercase">{{ member.get_full_name }}</span>
<button type="submit" class="btn btn-primary h-9 px-3.5 text-sm">{% trans "Save" %}</button>

View File

@@ -1,5 +1,5 @@
{% extends "mobile/base.html" %}
{% load i18n %}
{% load i18n lucide %}
{% comment %}
M2 -- design_handoff_rosterchief_platform/README.md's M2 section, "answer
@@ -21,7 +21,7 @@
<div class="absolute inset-0" style="background: linear-gradient(180deg, rgba(11,18,32,.35) 0%, rgba(11,18,32,.55) 60%, rgba(11,18,32,.92) 100%)"></div>
<div class="relative z-10 flex flex-1 flex-col justify-end p-4 text-white">
<a class="mb-auto flex h-11 w-11 items-center justify-center rounded-full bg-white/15" href="{% url "mobile:home" %}" aria-label="{% trans "Back" %}">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M15 5l-7 7 7 7"/></svg>
{% lucide "chevron-left" size=20 stroke_width=2.4 class="text-white" %}
</a>
<span class="mb-2 inline-block w-fit rounded bg-club px-2 py-1 font-display text-xs font-extrabold tracking-wide text-white uppercase">
{% if event.kind == "game" %}{% if event.is_home_game %}{% trans "Home game" %}{% else %}{% trans "Away game" %}{% endif %}{% else %}{{ event.get_kind_display }}{% endif %}

View File

@@ -1,5 +1,5 @@
{% extends "mobile/base.html" %}
{% load i18n %}
{% load i18n lucide %}
{% comment %}
M1 -- design_handoff_rosterchief_platform/README.md's M1 section. The
@@ -20,7 +20,7 @@
<div class="scrollbar-hide -mt-1 flex gap-2 overflow-x-auto pb-0.5">
<a class="person-chip {% if scope_everyone %}person-chip-active{% endif %}" href="?as=all">
<span class="person-chip-avatar">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><circle cx="8" cy="8" r="3"/><circle cx="17" cy="9" r="2.6"/><path d="M2.5 20c0-3.3 2.5-5.6 5.5-5.6s5.5 2.3 5.5 5.6"/><path d="M14 15c2.6.3 4.5 2.3 4.5 5"/></svg>
{% lucide "users" size=12 stroke_width=2.4 %}
</span>
<span class="person-chip-label">{% trans "All" %}</span>
</a>

View File

@@ -1,5 +1,5 @@
{% extends "mobile/base.html" %}
{% load i18n %}
{% load i18n lucide %}
{% comment %}
M5 -- design_handoff_rosterchief_platform/README.md's M5 section, "Me &
@@ -60,7 +60,7 @@
</div>
{% endif %}
</div>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" class="shrink-0 text-dim" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 5l7 7-7 7"/></svg>
{% lucide "chevron-right" size=18 class="shrink-0 text-dim" %}
</a>
{% endfor %}
</div>
@@ -74,13 +74,13 @@
{% if not forloop.first %}<div class="h-px bg-white/10"></div>{% endif %}
<a class="flex items-center gap-3 p-3.5" href="{% url "mobile:coach_today" %}?team={{ assignment.team.pk }}" hx-boost="false">
<span class="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-steel text-ice">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><circle cx="8" cy="8" r="3"/><circle cx="17" cy="9" r="2.6"/><path d="M2.5 20c0-3.3 2.5-5.6 5.5-5.6s5.5 2.3 5.5 5.6"/><path d="M14 15c2.6.3 4.5 2.3 4.5 5"/></svg>
{% lucide "users" size=20 stroke_width=2.4 %}
</span>
<div class="min-w-0 flex-1">
<div class="text-[15px] font-semibold text-white">{{ assignment.team.name }}</div>
<div class="text-xs text-on-dark-dim">{{ assignment.position }}</div>
</div>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" class="shrink-0 text-on-dark-dim" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 5l7 7-7 7"/></svg>
{% lucide "chevron-right" size=18 class="shrink-0 text-on-dark-dim" %}
</a>
{% endfor %}
</div>
@@ -90,7 +90,7 @@
<div class="m-card overflow-hidden">
<a class="flex items-center gap-3 p-3.5" href="{% url "mobile:edit_profile" me.pk %}">
<span class="flex-1 text-[15px] font-semibold text-ink">{% trans "Personal details" %}</span>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" class="shrink-0 text-dim" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 5l7 7-7 7"/></svg>
{% lucide "chevron-right" size=18 class="shrink-0 text-dim" %}
</a>
<div class="h-px bg-rule"></div>
<a class="flex items-center gap-3 p-3.5" href="{% url "mobile:payments" %}">
@@ -100,17 +100,17 @@
{% blocktrans count counter=open_dues_count %}{{ counter }} OPEN{% plural %}{{ counter }} OPEN{% endblocktrans %}
</span>
{% endif %}
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" class="shrink-0 text-dim" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 5l7 7-7 7"/></svg>
{% lucide "chevron-right" size=18 class="shrink-0 text-dim" %}
</a>
<div class="h-px bg-rule"></div>
<a class="flex items-center gap-3 p-3.5" href="{% url "mobile:notifications" %}">
<span class="flex-1 text-[15px] font-semibold text-ink">{% trans "Notifications" %}</span>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" class="shrink-0 text-dim" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 5l7 7-7 7"/></svg>
{% lucide "chevron-right" size=18 class="shrink-0 text-dim" %}
</a>
<div class="h-px bg-rule"></div>
<a class="flex items-center gap-3 p-3.5" href="{% url "mobile:calendar_feed_settings" %}">
<span class="flex-1 text-[15px] font-semibold text-ink">{% trans "Calendar sync" %}</span>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" class="shrink-0 text-dim" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 5l7 7-7 7"/></svg>
{% lucide "chevron-right" size=18 class="shrink-0 text-dim" %}
</a>
</div>

View File

@@ -1,5 +1,5 @@
{% extends "mobile/base.html" %}
{% load i18n %}
{% load i18n lucide %}
{% comment %}
M4 -- design_handoff_rosterchief_platform/README.md's M4 section, "News
@@ -14,7 +14,7 @@
<div class="-mx-4 -mt-4 flex h-[330px] flex-col justify-end p-4 text-white"
style="background: linear-gradient(180deg, rgba(11,18,32,.6) 0%, rgba(11,18,32,0) 40%, rgba(11,18,32,.88) 100%){% if news_item.main_photo %}, url('{{ news_item.main_photo.image.url }}') center/cover no-repeat{% else %}, var(--color-navy){% endif %}">
<a class="mb-auto flex h-11 w-11 items-center justify-center rounded-full bg-white/15" href="{% url "mobile:home" %}#news" aria-label="{% trans "Back" %}">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M15 5l-7 7 7 7"/></svg>
{% lucide "chevron-left" size=20 stroke_width=2.4 class="text-white" %}
</a>
<span class="mb-1.5 inline-block w-fit font-display text-xs font-extrabold tracking-wide text-club uppercase">
{% with team=news_item.teams.first %}

View File

@@ -1,5 +1,5 @@
{% extends "mobile/base.html" %}
{% load i18n %}
{% load i18n lucide %}
{% comment %}
M5's "Payments & dues" row -- every open season-dues balance across every
@@ -12,7 +12,7 @@
{% block content %}
<div class="-mx-4 -mt-4 flex items-center gap-1 border-b border-line bg-white px-4 py-3">
<a class="-ml-2.5 flex h-11 w-11 shrink-0 items-center justify-center" href="{% url "mobile:me" %}" aria-label="{% trans "Back" %}">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#0b1220" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M15 5l-7 7 7 7"/></svg>
{% lucide "chevron-left" size=20 stroke_width=2.4 class="text-ink" %}
</a>
<span class="min-w-0 flex-1 truncate font-display text-xl leading-none font-extrabold text-ink uppercase">{% trans "Payments & dues" %}</span>
</div>