Skip to content
Open
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
16 changes: 16 additions & 0 deletions src/content.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,21 @@ const jobs = defineCollection({
}),
});

const events = defineCollection({
loader: glob({ pattern: "*.{md,mdx}", base: "./src/content/events" }),
schema: z.object({
title: z.string(),
date: z.string(),
date_end: z.string().optional(),
time_start: z.string().optional(),
time_end: z.string().optional(),
location: z.string().optional(),
url: z.string().optional(),
description: z.string(),
draft: z.boolean().optional().default(false),
}),
});

const sprints = defineCollection({
loader: glob({ pattern: "*.{md,mdx}", base: "./src/content/sprints" }),
schema: z.object({
Expand Down Expand Up @@ -411,6 +426,7 @@ const sprints = defineCollection({

export const collections = {
days,
events,
pages,
deadlines,
week,
Expand Down
12 changes: 12 additions & 0 deletions src/content/events/language-summit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
title: Python Language Summit
date: "2026-07-14"
time_start: "09:00"
time_end: "17:00"
location: "ICE Kraków Congress Centre, room TBA"
url: /language-summit
description:
CPython and alternative implementation developers gather to share information,
discuss common problems, and solve them. Invite only.
draft: false
---
12 changes: 12 additions & 0 deletions src/content/events/packaging-summit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
title: Packaging Summit
date: "2026-07-13"
time_start: "09:00"
time_end: "17:00"
location: "ICE Kraków Congress Centre, room TBA"
url: /packaging-summit
description:
Maintainers of packaging tools, standards, and infrastructure discuss the
future of Python packaging. Open to all contributors.
draft: false
---
13 changes: 13 additions & 0 deletions src/content/events/rust-summit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
title: Rust Summit
date: "2026-07-13"
time_start: "09:00"
time_end: "17:00"
location: "ICE Kraków Congress Centre, room TBA"
url: /rust-summit
description:
A summit for Python developers interested in Rust integrations, the PyO3
ecosystem, and bringing Rust tooling into CPython and other Python
implementations.
draft: false
---
11 changes: 11 additions & 0 deletions src/content/events/sprints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
title: Sprints Weekend
date: "2026-07-18"
date_end: "2026-07-19"
location: "Details Soon"
url: /sprints
description:
Two days of open-source contribution alongside project maintainers. Sign up
for a project or bring your own. All experience levels welcome.
draft: false
---
12 changes: 12 additions & 0 deletions src/content/events/women-in-python-run.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
title: "Women in Python 5K @ EuroPython 2026"
date: "2026-07-16"
time_start: "Morning"
location: "TBA (approx. 5 min walk from ICE)"
url: https://docs.google.com/forms/d/e/1FAIpQLSdLczNLEkOP2itz42KyW7kD-9TSez6H6KrMluBVdOoNE3ZgSQ/formResponse
description:
A ~5 km community run along the river before the conference day begins.
Meeting point is approximately a 5-minute walk from the conference venue. Sign
up required.
draft: false
---
3 changes: 3 additions & 0 deletions src/data/nav.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const L = {
packagingSummit: { label: "Packaging Summit", url: "/packaging-summit" },

// Events & Social
sideEvents: { label: "Side Events", url: "/schedule/events" },
sprints: { label: "Sprints Weekend", url: "/sprints" },
socialEvent: { label: "Social Event", url: "/social-event" },
beginnersDay: { label: "Beginners' Day", url: "/beginners-day" },
Expand Down Expand Up @@ -129,6 +130,7 @@ export const NAV_MENUS: NavMenu[] = [
label: "Talks & Schedule",
items: [
L.schedule,
L.sideEvents,
L.talks,
L.tutorials,
L.posters,
Expand Down Expand Up @@ -257,6 +259,7 @@ export const FOOTER_COLUMNS: FooterColumn[] = [
{
title: "Events",
items: [
L.sideEvents,
L.sprints,
L.socialEvent,
L.beginnersDay,
Expand Down
276 changes: 276 additions & 0 deletions src/pages/schedule/events.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
---
import { getCollection } from "astro:content";
import Layout from "@layouts/Layout.astro";
import Section from "@ui/Section.astro";

const allEvents = await getCollection("events", ({ data }) =>
import.meta.env.MODE === "production" ? data.draft !== true : true
);

// Sort by date then time_start
allEvents.sort((a, b) => {
const dateCompare = a.data.date.localeCompare(b.data.date);
if (dateCompare !== 0) return dateCompare;
const aTime = a.data.time_start ?? "00:00";
const bTime = b.data.time_start ?? "00:00";
return aTime.localeCompare(bTime);
});

// Group by date
const byDay: Map<string, typeof allEvents> = new Map();
for (const event of allEvents) {
const key = event.data.date;
if (!byDay.has(key)) byDay.set(key, []);
byDay.get(key)!.push(event);
}

const formatDate = (isoDate: string) => {
const d = new Date(isoDate + "T12:00:00Z");
return d.toLocaleDateString("en-GB", {
weekday: "long",
day: "numeric",
month: "long",
timeZone: "Europe/Warsaw",
});
};

const formatTimeRange = (start?: string, end?: string, dateEnd?: string, date?: string) => {
if (dateEnd && date) {
const d1 = new Date(date + "T12:00:00Z");
const d2 = new Date(dateEnd + "T12:00:00Z");
const d1str = d1.toLocaleDateString("en-GB", { weekday: "short", day: "numeric", month: "short", timeZone: "Europe/Warsaw" });
const d2str = d2.toLocaleDateString("en-GB", { weekday: "short", day: "numeric", month: "short", timeZone: "Europe/Warsaw" });
return `${d1str} – ${d2str}`;
}
if (start && end) return `${start} – ${end}`;
if (start) return `From ${start}`;
return "All day";
};
---

<Layout
title="Side Events — EuroPython 2026"
description="Summits, sprints, and community gatherings happening alongside EuroPython 2026 in Kraków."
>
<Section>
<div class="events-page">
<header class="events-header">
<h1>Side Events</h1>
<p class="events-subtitle">
Summits, sprints, and community gatherings running alongside the main
programme. July 13–19, Kraków.
</p>
</header>

{Array.from(byDay.entries()).map(([date, events]) => (
<div class="events-day">
<h2 class="day-heading">{formatDate(date)}</h2>
<div class="events-list">
{events.map((event) => (
<article class="event-card">
<div class="event-meta">
<span class="event-time">
{formatTimeRange(event.data.time_start, event.data.time_end, event.data.date_end, event.data.date)}
</span>
{event.data.location && (
<span class="event-location">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z"/>
<circle cx="12" cy="10" r="3"/>
</svg>
{event.data.location}
</span>
)}
</div>
<div class="event-body">
<h3 class="event-title">
{event.data.url ? (
<a href={event.data.url}>{event.data.title}</a>
) : (
event.data.title
)}
</h3>
<p class="event-description">{event.data.description}</p>
{event.data.url && (
<a href={event.data.url} class="event-link">
Full details
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M5 12h14M12 5l7 7-7 7"/>
</svg>
</a>
)}
</div>
</article>
))}
</div>
</div>
))}
</div>
</Section>
</Layout>

<style>
.events-page {
max-width: 760px;
margin: 0 auto;
padding: 3rem 0 5rem;
}

.events-header {
margin-bottom: 3.5rem;
}

.events-header h1 {
font-size: clamp(2rem, 5vw, 3rem);
font-weight: 700;
letter-spacing: -0.03em;
color: var(--color-text-primary);
margin: 0 0 0.75rem;
}

.events-subtitle {
font-size: 1.1rem;
color: var(--color-text-muted);
margin: 0;
max-width: 52ch;
line-height: 1.6;
}

/* Day section */
.events-day {
margin-bottom: 3rem;
}

.day-heading {
font-size: 0.78rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.12em;
color: #2559e4;
margin: 0 0 1.25rem;
padding-bottom: 0.6rem;
border-bottom: 1px solid var(--color-surface-medium);
}

.events-list {
display: flex;
flex-direction: column;
gap: 1rem;
}

/* Event card */
.event-card {
display: grid;
grid-template-columns: 200px 1fr;
gap: 1.5rem;
background: var(--color-surface-faint);
border: 1px solid var(--color-surface-medium);
border-radius: 10px;
padding: 1.25rem 1.5rem;
transition: border-color 0.15s ease;
}

.event-card:hover {
border-color: var(--color-surface-subtle);
}

/* Left: meta column */
.event-meta {
display: flex;
flex-direction: column;
gap: 0.5rem;
padding-top: 0.15rem;
}

.event-time {
font-size: 0.85rem;
font-weight: 600;
color: var(--color-text-secondary);
font-variant-numeric: tabular-nums;
line-height: 1.4;
}

.event-location {
display: flex;
align-items: flex-start;
gap: 0.3rem;
font-size: 0.8rem;
color: var(--color-text-muted);
line-height: 1.4;
}

.event-location svg {
flex-shrink: 0;
margin-top: 0.15em;
opacity: 0.6;
}

/* Right: body column */
.event-body {
display: flex;
flex-direction: column;
gap: 0.5rem;
}

.event-title {
font-size: 1.1rem;
font-weight: 700;
color: var(--color-text-primary);
margin: 0;
line-height: 1.3;
}

.event-title a {
color: inherit;
text-decoration: none;
}

.event-title a:hover {
color: #2559e4;
}

.event-description {
font-size: 0.92rem;
color: var(--color-text-secondary);
margin: 0;
line-height: 1.6;
}

.event-link {
display: inline-flex;
align-items: center;
gap: 0.3rem;
font-size: 0.85rem;
font-weight: 600;
color: #2559e4;
text-decoration: none;
margin-top: 0.25rem;
transition: gap 0.15s ease;
}

.event-link:hover {
gap: 0.5rem;
text-decoration: underline;
}

/* Mobile: stack meta above body */
@media (max-width: 600px) {
.event-card {
grid-template-columns: 1fr;
gap: 0.6rem;
padding: 1rem 1.1rem;
}

.event-meta {
flex-direction: row;
flex-wrap: wrap;
align-items: center;
gap: 0.75rem;
padding-top: 0;
}

.event-time {
font-size: 0.8rem;
}
}
</style>
Loading