Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions _layouts/_includes/footer.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@ <h3>Quick link</h3>
<ul>
<li><a href="/about.html">About Us</a></li>
<li><a href="/events.html">Events</a></li>
<li><a href="/support.html#partnerships">Partnerships</a></li>
<li><a href="/about.html#join-the-community">Community</a></li>
<li><a href="/support.html">Support</a></li>
<li><a href="/code-of-conduct.html">Code of Conduct</a></li>
<li><a href="/students.html">BPD Students Ambassador Program</a></li>
</ul>
</div>
<!-- Contact Us Section -->
Expand Down
6 changes: 0 additions & 6 deletions _layouts/_includes/pycon_banner.html

This file was deleted.

3 changes: 3 additions & 0 deletions _layouts/_includes/sponsors.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,8 @@ <h3>Corporate Sponsors</h3>
<article class="sponsor">
<img src="/assets/images/pydantic-lg.webp" alt="JetBrains Logo" style="height: 2rem" />
</article>
<article>
<p><a href="/corporate-sponsorships.html">Learn more about corporate sponsorships</a></p>
</article>
</div>
</section>
6 changes: 6 additions & 0 deletions _layouts/_includes/toast.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<section class="toast" aria-label="{{toast['label']}}">
<a href="{{toast['url']}}">
<span class="toast-text">{{toast['text']}}</span>
<i class="iconoir-arrow-right toast-icon" aria-hidden="true"></i>
</a>
</section>
3 changes: 3 additions & 0 deletions _layouts/default.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
<a class="skip-to-content" href="#main-content">Skip to content</a>
{%- include '_includes/header.html' -%}
<main id="main-content" class="container" role="main" aria-label="Content">
{% if toast %}
{% include '_includes/toast.html' %}
{% endif %}

{% block content %}
{% if content %}
Expand Down
2 changes: 0 additions & 2 deletions _layouts/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
{% endif %}
</div>

{% include "_includes/pycon_banner.html" %}

<article class="grid hero">
<div style="display:flex;align-items:center;justify-content:center">
<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" />
Expand Down
1 change: 1 addition & 0 deletions _layouts/support.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
{% include "_includes/partnerships.html" %}
{% set foundational_supporters=data.foundational_supporters %}
{% include "_includes/foundational_supporters.html" %}
{% include "_includes/sponsors.html" %}
{% include "_includes/pitch_deck.html" %}
{% endblock %}
37 changes: 25 additions & 12 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import pathlib
import pluggy

from render_engine import Site, Page, Collection, Blog
from render_engine import Site, Page, Collection, Blog, RedirectPage
from render_engine_markdown import MarkdownPageParser

from render_engine_clean_urls import CleanURLsPlugin
Expand All @@ -26,7 +26,7 @@
"icon": "iconoir-calendar",
},
{
"text": "Support Us",
"text": "Donate",
"url": "/support.html",
"icon": "iconoir-donate",
},
Expand All @@ -52,6 +52,7 @@ def pre_build_site():
app = Site()
app.template_path = "_layouts"
app.static_paths.add("assets")
app.site_vars["SITE_TITLE"] = "Black Python Devs"
app.site_vars["locales"] = ["en"]
app.site_vars["navigation"] = navigation
app.site_vars["DATETIME_FORMAT"] = "%d %b %Y"
Expand All @@ -68,31 +69,43 @@ def pre_build_site():
class Index(Page):
template = "index.html"
content_path = "index.html"
template_vars = {
"toast": {
"label": "Black Python Devs",
"url": "/leadership",
"text": "Tickets are on sale for the Python Community Leadership Summit! Learn More!",
}
}


@app.page
class Students(Page):
content_path = "students.html"
class Students(RedirectPage):
slug = "students"
redirect_url = "/student-ambassador-program.html"


@app.page
class Community(Page):
content_path = "community.html"
class Community(RedirectPage):
slug = "community"
redirect_url = "/about.html#join-the-community"


@app.page
class Partnerships(Page):
content_path = "partnerships.html"
class Partnerships(RedirectPage):
slug = "partnerships"
redirect_url = "/support.html#partnerships"


@app.page
class Leadership(Page):
content_path = "leadership.html"
class Leadership(RedirectPage):
slug = "leadership"
redirect_url = "/bpd-events/black-python-devs-leadership-summit-2026-ohio.html"


@app.page
class Pycon(Page):
content_path = "pycon.html"
class Pycon(RedirectPage):
slug = "pycon"
redirect_url = "/blog/black-python-devs-at-pycon-us-2026.html"


@app.page
Expand Down
40 changes: 14 additions & 26 deletions assets/css/bpd.css
Original file line number Diff line number Diff line change
Expand Up @@ -1004,25 +1004,9 @@ a.logo-text:hover img {
color: var(--bpd-cyan);
}

/* ── 12b. PyCon Banner ───────────────────────────────────── */
/* ── 12b. Toast Banner ───────────────────────────────────── */

/* PyCon US 2026 brand purple β€” lightened in dark mode for contrast */
.pycon-banner {
--pycon-purple: #d28de8;
}
@media (prefers-color-scheme: light) {
.pycon-banner {
--pycon-purple: #680579;
}
}
[data-theme="light"] .pycon-banner {
--pycon-purple: #680579;
}
[data-theme="dark"] .pycon-banner {
--pycon-purple: #d28de8;
}

.pycon-banner {
.toast {
position: relative;
background: var(--bpd-raised);
border: 1px solid var(--bpd-border);
Expand All @@ -1036,7 +1020,7 @@ a.logo-text:hover img {
}

/* luminous gold seam β€” echoes site header + newsletter card */
.pycon-banner::before {
.toast::before {
content: "";
position: absolute;
top: 0;
Expand All @@ -1047,38 +1031,42 @@ a.logo-text:hover img {
border-radius: 12px 12px 0 0;
}

.pycon-banner:hover {
.toast:hover {
border-color: var(--bpd-border-hi);
box-shadow: 0 0 28px var(--bpd-cyan-glow);
transform: translateY(-2px);
}

.pycon-banner a {
.toast a {
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
gap: 0.5rem 0.85rem;
padding: 1.1rem 1.5rem;
color: var(--pycon-purple);
color: var(--bpd-cyan);
text-decoration: none;
font-weight: 600;
text-align: center;
}

.pycon-banner-icon {
color: var(--pycon-purple);
.toast a:hover {
color: var(--bpd-white);
}

.toast-icon {
color: var(--bpd-gold);
font-size: 1.15rem;
flex-shrink: 0;
transition: transform 0.3s ease;
}

.pycon-banner:hover .pycon-banner-icon {
.toast:hover .toast-icon {
transform: translateX(4px);
}

@media (max-width: 600px) {
.pycon-banner a {
.toast a {
padding: 0.95rem 1.1rem;
font-size: 0.92rem;
}
Expand Down
11 changes: 0 additions & 11 deletions community.html

This file was deleted.

11 changes: 0 additions & 11 deletions leadership.html

This file was deleted.

14 changes: 0 additions & 14 deletions partnerships.html

This file was deleted.

11 changes: 0 additions & 11 deletions pycon.html

This file was deleted.

21 changes: 15 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,26 @@ version = "0.1.0"
description = "Black Python Devs community website"
requires-python = ">=3.13"
dependencies = [
"render-engine[cli]>=2026.3.4a2",
"render-engine-clean-urls",
"pyyaml",
"render-engine[cli]>=2026.5.2a1",
"render-engine-clean-urls==0.1.0",
"pyyaml==6.0.3",
"folium>=0.20.0",
"click",
"pycountry",
"click==8.3.1",
"pycountry==26.2.16",
"python-slugify>=8.0.4",

]

[dependency-groups]
dev = ["pre-commit", "typer", "rich", "python-frontmatter", "pytest", "ruff"]
dev = [
"pin-versions==2026.3.6",
"pre-commit==4.6.0",
"typer==0.25.1",
"rich==14.3.3",
"python-frontmatter==1.1.0",
"pytest==9.0.3",
"ruff==0.15.13",
]

[tool.render-engine.cli]
module = "app"
Expand Down
11 changes: 0 additions & 11 deletions students.html

This file was deleted.

2 changes: 0 additions & 2 deletions support.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,3 @@ title: Support
# Support Black Python Devs

Black Python Devs is a Non-Profit, fiscally hosted under the [GNOME Foundation](https://foundation.gnome.org/). The GNOME Foundation takes a small percentage for administration costs and support but at least 90% of proceeds goes directly to Black Python Devs Fund to support operational costs and supporting community events in the communities of Black Python Devs.

Looking for member discounts? View our [Partnerships](#partnerships).
51 changes: 42 additions & 9 deletions tests/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,41 @@ def parse_html(path: pathlib.Path) -> HTMLMetaParser:
return parser


class ToastParser(HTMLParser):
"""Extract aria-label, link href, and visible text from a `.toast` section."""

def __init__(self):
super().__init__()
self._depth = 0
self.aria_label: str | None = None
self.href: str | None = None
self.text: str = ""

def handle_starttag(self, tag, attrs):
attrs_dict = dict(attrs)
if self._depth:
self._depth += 1
if tag == "a" and self.href is None:
self.href = attrs_dict.get("href")
elif tag == "section" and "toast" in attrs_dict.get("class", "").split():
self._depth = 1
self.aria_label = attrs_dict.get("aria-label")

def handle_endtag(self, tag):
if self._depth:
self._depth -= 1

def handle_data(self, data):
if self._depth:
self.text += data


def parse_toast(path: pathlib.Path) -> ToastParser | None:
parser = ToastParser()
parser.feed(path.read_text())
return parser if parser.aria_label is not None else None


OUTPUT_DIR = pathlib.Path("output")


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


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


def _blog_post_files() -> list[pathlib.Path]:
Expand Down
Loading
Loading