Skip to content
Draft
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
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ No install needed — `open-location-code` is already available at `pcd-website/

- **Astro** owns routing, layouts, metadata, and static content pages. `src/layouts/BaseLayout.astro` provides the document shell; `MapLayout.astro`, `SiteLayout.astro`, and `DocsLayout.astro` provide the map, standard content, and Organizer Kit shells respectively.
- The Organizer Kit introduction lives in `src/content/organizer-kit/getting-started/introduction.md`; `/organize/` redirects to its canonical `/organize/getting-started/introduction/` route.
- The Organizer Kit's `partners.md` supplies the “Discover our Partners” overview introduction. `PartnerCards.astro` renders published Organizer Kit entries with `partnerCard` frontmatter, sorted by `order` then title. Each partner detail page in `src/content/organizer-kit/partner-pages/` owns its card's `logo` (relative image path validated by Astro), `summary` (one paragraph leading with the participant or organizer benefit, followed by a short partner description); its title and route supply the card name and link. The same data supplies the overview's shared Markdown and the detail-page logo. Detail pages use `hideFromNav: true` to stay published while being omitted from both shared navigation trees and prev/next links; `draft: true` still excludes a page from build output and cards. Partner card styles live in `src/styles/prose.css`.
- Partner detail routes pass their logo to `DocsLayout` through its optional `headingLogo` prop; the image stays inside the h1 with the page title as alt text. Its optional `backLink` prop renders the shared `BackButton` above the heading in place of the eyebrow; partner pages link back to `/organize/partners/`.
- **Vue** handles the interactive map UI as `client:only="vue"` island components. Map-specific interactive features belong in Vue; static site and Organizer Kit pages belong in Astro and Markdown content collections. The map filter drawer in `MapView.vue` filters clustered markers by date (future, past, or all), format, and activity type; checkbox choices are ORed within a group and filter groups are ANDed together.

### Event list
Expand Down
15 changes: 6 additions & 9 deletions pcd-website/src/components/Footer.astro
Original file line number Diff line number Diff line change
Expand Up @@ -179,22 +179,19 @@ const UTILITY_LINKS = [
.sponsor-logo {
display: inline-flex;
align-items: center;
padding: 0.5rem 0.625rem;
border: 1px solid var(--color-border);
border-radius: 4px;
background: #fff;
padding: 0.5rem 0;
}

.sponsor-logo img {
display: block;
width: 200px;
width: auto;
max-width: 100%;
height: auto;
height: 30px;
object-fit: contain;
}

.sponsor-logo:hover {
border-color: var(--color-primary);
color: var(--color-primary);
.sponsor-logo:hover img {
opacity: 0.8;
}

.social-row {
Expand Down
24 changes: 24 additions & 0 deletions pcd-website/src/components/PartnerCards.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
import { Image } from 'astro:assets';
import { kitHref, type KitEntry } from '../config/organizer-kit-nav';

interface Props {
partners: KitEntry[];
}

const { partners } = Astro.props;
---

<div class="partner-grid">
{partners.map((partner) => {
const card = partner.data.partnerCard;
if (!card) return null;
return (
<section class="partner-card">
<p><Image src={card.logo} alt={partner.data.title} /></p>
<p>{card.summary}</p>
<p><a href={kitHref(partner.id)}>Learn more about {partner.data.title} →</a></p>
</section>
);
})}
</div>
6 changes: 4 additions & 2 deletions pcd-website/src/config/organizer-kit-nav.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const TOP_LEVEL: ReadonlyArray<string | { page: string }> = [
{ page: 'peer-support-sessions' },
{ page: 'code-of-conduct' },
{ page: 'faq' },
{ page: 'partners' },
{ page: 'about-processing-foundation' },
{ page: 'contact' },
{ page: 'documents' },
Expand All @@ -49,13 +50,14 @@ function toPage(entry: KitEntry): KitPage {

/**
* Builds the sidebar tree by walking TOP_LEVEL and pulling matching entries out
* of the collection. Throws if an entry exists that TOP_LEVEL never places, so
* of the collection. Pages with `hideFromNav` remain published but are omitted.
* Throws if any other entry exists that TOP_LEVEL never places, so
* adding a Markdown file without listing it here fails the build rather than
* silently producing an unreachable page.
*/
export async function getKitNav(): Promise<KitNavNode[]> {
const allEntries = await getCollection('organizerKit');
const entries = allEntries.filter((entry) => !entry.data.draft);
const entries = allEntries.filter((entry) => !entry.data.draft && !entry.data.hideFromNav);
const allIds = new Set(allEntries.map((entry) => entry.id));

const byId = new Map(entries.map((entry) => [entry.id, entry]));
Expand Down
6 changes: 6 additions & 0 deletions pcd-website/src/config/sponsors.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { ImageMetadata } from 'astro';
import openProcessingLogo from '../images/openprocessing_logo.svg';
import butterLogo from '../images/butter_logo.svg';

export interface Sponsor {
name: string;
Expand All @@ -13,4 +14,9 @@ export const SPONSORS: Sponsor[] = [
href: 'https://openprocessing.org',
logo: openProcessingLogo,
},
{
name: 'Butter',
href: 'https://www.butter.video/',
logo: butterLogo,
},
];
8 changes: 7 additions & 1 deletion pcd-website/src/content.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,23 @@ const pages = defineCollection({

const organizerKit = defineCollection({
loader: glob({ base: './src/content/organizer-kit', pattern: '**/*.md' }),
schema: z.object({
schema: ({ image }) => z.object({
title: z.string(),
// Sidebar grouping. `section` is the parent group's title; standalone
// top-level pages omit it. `order` sorts a page within its section — the
// top level's own order comes from TOP_LEVEL in config/organizer-kit-nav.ts.
section: z.string().optional(),
order: z.number().default(0),
description: z.string().optional(),
partnerCard: z.object({
logo: image(),
summary: z.string().min(1),
}).optional(),
// Excludes the page from the sidebar and from build output entirely, for
// TBD pages that shouldn't be publicly reachable yet.
draft: z.boolean().default(false),
// Keeps a page published while omitting it from navigation and prev/next links.
hideFromNav: z.boolean().default(false),
// Suppresses the "On this page" table of contents, for short pages whose
// headings aren't worth navigating.
hideToc: z.boolean().default(false),
Expand Down
21 changes: 21 additions & 0 deletions pcd-website/src/content/organizer-kit/partner-pages/butter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
title: Butter
hideFromNav: true
order: 1
description: Free Butter Pro for PCD participants in October 2026
draft: false
hideToc: true
partnerCard:
logo: ../../../images/butter_logo.svg
summary: Get free access to Butter Pro as a PCD participant during October 2026 and build a tool to get a chance to win a cash prize.
---

[Butter](https://www.butter.video/) is an online video editor with customizable blocks for motion graphics, animated type, and visual effects.

## Butter Pro in October

Butter is offering PCD participants access to Butter Pro during October 2026. Details on how to claim access will be shared here when available.

## Creative Coding Challenge

Details TBD
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
title: OpenProcessing
hideFromNav: true
order: 2
description: One free month of OpenProcessing ProfessorPlus
draft: false
hideToc: true
partnerCard:
logo: ../../../images/openprocessing_logo.svg
summary: Get one free month of ProfessorPlus membership for your workshop during October 2026.
---

[OpenProcessing](https://openprocessing.org/) is a creative coding platform and community for creating, sharing, and exploring sketches in the browser.

## Free ProfessorPlus for your workshop

Sinan from OpenProcessing is offering PCD organizers one free month of ProfessorPlus membership for their workshop during October 2026.

You can use the membership to try features such as collaborative code editing in your workshop.

## How to request access

Contact Sinan at OpenProcessing directly to request the one-month ProfessorPlus membership for your PCD workshop.
7 changes: 7 additions & 0 deletions pcd-website/src/content/organizer-kit/partners.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
title: Discover our Partners
description: Meet our partners and explore what they offer PCD organizers.
hideToc: true
---

Meet the platforms supporting our community and discover what they offer PCD organizers.
1 change: 1 addition & 0 deletions pcd-website/src/images/butter_logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 32 additions & 5 deletions pcd-website/src/layouts/DocsLayout.astro
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
---
import type { MarkdownHeading } from 'astro';
import type { ImageMetadata, MarkdownHeading } from 'astro';
import { Image } from 'astro:assets';
import BaseLayout from './BaseLayout.astro';
import Header from '../components/Header.astro';
import Footer from '../components/Footer.astro';
import DocsSidebar from '../components/DocsSidebar.astro';
import DocsTableOfContents from '../components/DocsTableOfContents.astro';
import DocsPageActions from '../components/DocsPageActions.astro';
import BackButton from '../components/BackButton.astro';
import { getKitNav } from '../config/organizer-kit-nav';
import '../styles/base.css';
import '../styles/docs.css';
Expand All @@ -15,8 +17,12 @@ interface Props {
description: string;
/** Rendered above the h1 as the section label. */
eyebrow?: string;
/** Parent navigation shown in place of the eyebrow. */
backLink?: { href: string; label: string };
/** Page heading. Falls back to `title` when omitted. */
heading?: string;
/** Optional logo displayed within the h1, using the heading as alt text. */
headingLogo?: ImageMetadata;
headings?: MarkdownHeading[];
/** Suppresses the "On this page" table of contents. */
hideToc?: boolean;
Expand All @@ -26,7 +32,7 @@ interface Props {
editHref?: string;
}

const { title, description, eyebrow, heading, headings = [], hideToc = false, markdown, editHref } = Astro.props;
const { title, description, eyebrow, backLink, heading, headingLogo, headings = [], hideToc = false, markdown, editHref } = Astro.props;

const nav = await getKitNav();
const permalink = new URL(Astro.url.pathname, Astro.site ?? Astro.url.origin).href;
Expand All @@ -49,9 +55,13 @@ const permalink = new URL(Astro.url.pathname, Astro.site ?? Astro.url.origin).hr

<main id="main" tabindex="-1" class="docs-shell__main">
<article class="docs-prose">
{eyebrow && <p class="prose__eyebrow">{eyebrow}</p>}
<div class="docs-title-row">
<h1>{heading ?? title}</h1>
{backLink
? <BackButton href={backLink.href} label={backLink.label} />
: eyebrow && <p class="prose__eyebrow">{eyebrow}</p>}
<div class:list={['docs-title-row', { 'docs-title-row--logo': headingLogo }]}>
<h1>{headingLogo
? <Image class="docs-heading-logo" src={headingLogo} alt={heading ?? title} />
: heading ?? title}</h1>
{markdown && editHref && (
<DocsPageActions markdown={markdown} permalink={permalink} editHref={editHref} />
)}
Expand All @@ -64,6 +74,23 @@ const permalink = new URL(Astro.url.pathname, Astro.site ?? Astro.url.origin).hr
<Footer />
</BaseLayout>

<style>
.docs-title-row--logo {
row-gap: var(--sp-6);
margin-bottom: var(--sp-6);
}

.docs-heading-logo {
display: block;
width: auto;
height: 48px;
max-width: 100%;
object-fit: contain;
object-position: left;
margin: 0;
}
</style>

<script is:inline>
(() => {
const toggle = document.querySelector('.docs-nav-toggle');
Expand Down
17 changes: 15 additions & 2 deletions pcd-website/src/pages/organize/[...slug].astro
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import Icon from '../../components/Icon.astro';
import { getCollection, render } from 'astro:content';
import type { GetStaticPaths } from 'astro';
import DocsLayout from '../../layouts/DocsLayout.astro';
import { flattenKitNav, getKitNav } from '../../config/organizer-kit-nav';
import { flattenKitNav, getKitNav, kitHref } from '../../config/organizer-kit-nav';
import { ZINE_SUBMIT_URL } from '../../config';
import ZineGrid from '../../components/ZineGrid.astro';
import PartnerCards from '../../components/PartnerCards.astro';

export const getStaticPaths: GetStaticPaths = async () => {
const entries = await getCollection('organizerKit', (entry) => !entry.data.draft);
Expand All @@ -16,6 +17,11 @@ export const getStaticPaths: GetStaticPaths = async () => {
};

const { entry } = Astro.props;
const headingLogo = entry.data.partnerCard?.logo;
const partners = entry.id === 'partners'
? (await getCollection('organizerKit', (partner) => !partner.data.draft && !!partner.data.partnerCard))
.sort((a, b) => a.data.order - b.data.order || a.data.title.localeCompare(b.data.title))
: [];
const { Content, headings } = await render(entry);

// Prev/next follow the sidebar's reading order rather than the raw collection
Expand All @@ -31,11 +37,17 @@ const SUBMIT_PAGES = new Set(['zines/zine-library']);
const markdownSuffix = SUBMIT_PAGES.has(entry.id)
? `\n\n[Submit a zine](${ZINE_SUBMIT_URL})\n`
: '';
const markdown = `# ${entry.data.title}\n\n${entry.body?.trim() ?? ''}\n${markdownSuffix}`;
const partnerMarkdown = partners.map((partner) => {
const card = partner.data.partnerCard!;
return `\n\n## ${partner.data.title}\n\n${card.summary}\n\n[Learn more about ${partner.data.title} →](${kitHref(partner.id)})`;
}).join('');
const markdown = `# ${entry.data.title}\n\n${entry.body?.trim() ?? ''}\n${markdownSuffix}${partnerMarkdown}`;
---

<DocsLayout
title={entry.data.title}
headingLogo={headingLogo}
backLink={headingLogo ? { href: '/organize/partners/', label: 'Back to Partners' } : undefined}
description={entry.data.description ?? `${entry.data.title} — the Processing Community Day Organizer's Kit.`}
eyebrow={entry.data.section ?? "Organizer's Kit"}
headings={headings}
Expand All @@ -45,6 +57,7 @@ const markdown = `# ${entry.data.title}\n\n${entry.body?.trim() ?? ''}\n${markdo
>
<Content />
{entry.id === 'zines/zine-library' && <ZineGrid />}
{entry.id === 'partners' && <PartnerCards partners={partners} />}

<a class="docs-back-to-top" href="#main">
<Icon name="arrow-up" class="docs-back-to-top__icon" />
Expand Down
53 changes: 53 additions & 0 deletions pcd-website/src/styles/prose.css
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,59 @@
color: var(--color-text);
}

.docs-prose .partner-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
gap: var(--spacing-md);
margin: var(--spacing-lg) 0;
}

.docs-prose .partner-card {
position: relative;
display: flex;
flex-direction: column;
min-width: 0;
padding: var(--spacing-lg);
border: 1px solid var(--color-border);
border-radius: 6px;
}

.docs-prose .partner-card > p:first-child {
margin-top: 0;
}

.docs-prose .partner-card > p:first-child img {
display: block;
width: auto;
height: 30px;
max-width: 100%;
object-fit: contain;
object-position: left;
margin: 0;
}

.docs-prose .partner-card p:last-child {
margin-top: auto;
margin-bottom: 0;
padding-top: var(--spacing-sm);
}

.docs-prose .partner-card p:last-child a::after {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
}

.docs-prose .partner-card:hover {
border-color: var(--color-primary);
}

.docs-prose .partner-card:has(a:focus-visible) {
outline: 2px solid var(--color-focus);
outline-offset: 2px;
}

.placeholder-note {
border: 1px dashed var(--color-border);
border-radius: 6px;
Expand Down