Skip to content

Commit d473205

Browse files
kjaymillerclaudedragid10
authored
make popup banner more flexible (#914)
* add styling * update tests for toast * add corporate sponsorship page and change name (#912) * Update render-engine and adopt RedirectPage (#913) * update render-engine and adopt RedirectPage Bumps render-engine to 2026.5.2a1 and switches the five redirect pages (students, community, partnerships, leadership, pycon) to use the new RedirectPage class from render-engine/render-engine#1161 instead of hand-written meta-refresh HTML. Also fixes the students slug, which previously redirected to the non-existent /student-ambassadors-program.html. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * remove unused hand-written redirect HTML These five files were the meta-refresh source for redirects now handled by RedirectPage in app.py — they were never referenced via content_path after the switch. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * lock * update broken links * Update pyproject.toml Co-authored-by: Alex Oladele <dragid10@gmail.com> * Update app.py Co-authored-by: Alex Oladele <dragid10@gmail.com> * Update app.py Co-authored-by: Alex Oladele <dragid10@gmail.com> * versions --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: Alex Oladele <dragid10@gmail.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: Alex Oladele <dragid10@gmail.com>
1 parent 2a7f3c2 commit d473205

7 files changed

Lines changed: 72 additions & 43 deletions

File tree

_layouts/_includes/pycon_banner.html

Lines changed: 0 additions & 6 deletions
This file was deleted.

_layouts/_includes/toast.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<section class="toast" aria-label="{{toast['label']}}">
2+
<a href="{{toast['url']}}">
3+
<span class="toast-text">{{toast['text']}}</span>
4+
<i class="iconoir-arrow-right toast-icon" aria-hidden="true"></i>
5+
</a>
6+
</section>

_layouts/default.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929
<a class="skip-to-content" href="#main-content">Skip to content</a>
3030
{%- include '_includes/header.html' -%}
3131
<main id="main-content" class="container" role="main" aria-label="Content">
32+
{% if toast %}
33+
{% include '_includes/toast.html' %}
34+
{% endif %}
3235

3336
{% block content %}
3437
{% if content %}

_layouts/index.html

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99
{% endif %}
1010
</div>
1111

12-
{% include "_includes/pycon_banner.html" %}
13-
1412
<article class="grid hero">
1513
<div style="display:flex;align-items:center;justify-content:center">
1614
<img style="max-width: 14rem; max-height:18rem; filter: drop-shadow(0 4px 40px var(--bpd-gold-wash));" src="/assets/images/bpd_stacked.png" alt="Black Python Devs logo" />

app.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,13 @@ def pre_build_site():
6969
class Index(Page):
7070
template = "index.html"
7171
content_path = "index.html"
72+
template_vars = {
73+
"toast": {
74+
"label": "Black Python Devs",
75+
"url": "/leadership",
76+
"text": "Tickets are on sale for the Python Community Leadership Summit! Learn More!",
77+
}
78+
}
7279

7380

7481
@app.page

assets/css/bpd.css

Lines changed: 14 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,25 +1004,9 @@ a.logo-text:hover img {
10041004
color: var(--bpd-cyan);
10051005
}
10061006

1007-
/* ── 12b. PyCon Banner ───────────────────────────────────── */
1007+
/* ── 12b. Toast Banner ───────────────────────────────────── */
10081008

1009-
/* PyCon US 2026 brand purple — lightened in dark mode for contrast */
1010-
.pycon-banner {
1011-
--pycon-purple: #d28de8;
1012-
}
1013-
@media (prefers-color-scheme: light) {
1014-
.pycon-banner {
1015-
--pycon-purple: #680579;
1016-
}
1017-
}
1018-
[data-theme="light"] .pycon-banner {
1019-
--pycon-purple: #680579;
1020-
}
1021-
[data-theme="dark"] .pycon-banner {
1022-
--pycon-purple: #d28de8;
1023-
}
1024-
1025-
.pycon-banner {
1009+
.toast {
10261010
position: relative;
10271011
background: var(--bpd-raised);
10281012
border: 1px solid var(--bpd-border);
@@ -1036,7 +1020,7 @@ a.logo-text:hover img {
10361020
}
10371021

10381022
/* luminous gold seam — echoes site header + newsletter card */
1039-
.pycon-banner::before {
1023+
.toast::before {
10401024
content: "";
10411025
position: absolute;
10421026
top: 0;
@@ -1047,38 +1031,42 @@ a.logo-text:hover img {
10471031
border-radius: 12px 12px 0 0;
10481032
}
10491033

1050-
.pycon-banner:hover {
1034+
.toast:hover {
10511035
border-color: var(--bpd-border-hi);
10521036
box-shadow: 0 0 28px var(--bpd-cyan-glow);
10531037
transform: translateY(-2px);
10541038
}
10551039

1056-
.pycon-banner a {
1040+
.toast a {
10571041
display: flex;
10581042
align-items: center;
10591043
justify-content: center;
10601044
flex-wrap: wrap;
10611045
gap: 0.5rem 0.85rem;
10621046
padding: 1.1rem 1.5rem;
1063-
color: var(--pycon-purple);
1047+
color: var(--bpd-cyan);
10641048
text-decoration: none;
10651049
font-weight: 600;
10661050
text-align: center;
10671051
}
10681052

1069-
.pycon-banner-icon {
1070-
color: var(--pycon-purple);
1053+
.toast a:hover {
1054+
color: var(--bpd-white);
1055+
}
1056+
1057+
.toast-icon {
1058+
color: var(--bpd-gold);
10711059
font-size: 1.15rem;
10721060
flex-shrink: 0;
10731061
transition: transform 0.3s ease;
10741062
}
10751063

1076-
.pycon-banner:hover .pycon-banner-icon {
1064+
.toast:hover .toast-icon {
10771065
transform: translateX(4px);
10781066
}
10791067

10801068
@media (max-width: 600px) {
1081-
.pycon-banner a {
1069+
.toast a {
10821070
padding: 0.95rem 1.1rem;
10831071
font-size: 0.92rem;
10841072
}

tests/test.py

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,41 @@ def parse_html(path: pathlib.Path) -> HTMLMetaParser:
4343
return parser
4444

4545

46+
class ToastParser(HTMLParser):
47+
"""Extract aria-label, link href, and visible text from a `.toast` section."""
48+
49+
def __init__(self):
50+
super().__init__()
51+
self._depth = 0
52+
self.aria_label: str | None = None
53+
self.href: str | None = None
54+
self.text: str = ""
55+
56+
def handle_starttag(self, tag, attrs):
57+
attrs_dict = dict(attrs)
58+
if self._depth:
59+
self._depth += 1
60+
if tag == "a" and self.href is None:
61+
self.href = attrs_dict.get("href")
62+
elif tag == "section" and "toast" in attrs_dict.get("class", "").split():
63+
self._depth = 1
64+
self.aria_label = attrs_dict.get("aria-label")
65+
66+
def handle_endtag(self, tag):
67+
if self._depth:
68+
self._depth -= 1
69+
70+
def handle_data(self, data):
71+
if self._depth:
72+
self.text += data
73+
74+
75+
def parse_toast(path: pathlib.Path) -> ToastParser | None:
76+
parser = ToastParser()
77+
parser.feed(path.read_text())
78+
return parser if parser.aria_label is not None else None
79+
80+
4681
OUTPUT_DIR = pathlib.Path("output")
4782

4883

@@ -126,15 +161,13 @@ def test_partnerships_redirects_to_support(built_site: pathlib.Path) -> None:
126161
), "partnerships.html should redirect to /support.html#partnerships"
127162

128163

129-
def test_pycon_redirects_to_blog_post(built_site: pathlib.Path) -> None:
130-
"""Check that pycon.html contains a redirect to the PyCon US blog post."""
131-
pycon = built_site / "pycon.html"
132-
assert pycon.exists(), "pycon.html should exist in build output"
133-
content = pycon.read_text()
134-
assert (
135-
"https://blackpythondevs.com/blog/black-python-devs-at-pycon-us-2026.html"
136-
in content
137-
), "pycon.html should redirect to the PyCon US 2026 blog post"
164+
def test_homepage_toast(built_site: pathlib.Path) -> None:
165+
"""Check that the homepage renders a well-formed toast banner."""
166+
toast = parse_toast(built_site / "index.html")
167+
assert toast is not None, "homepage should render a .toast section"
168+
assert toast.aria_label, "toast should have a non-empty aria-label"
169+
assert toast.href, "toast should contain a link with an href"
170+
assert toast.text.strip(), "toast should have visible text"
138171

139172

140173
def _blog_post_files() -> list[pathlib.Path]:

0 commit comments

Comments
 (0)