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
41 changes: 41 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
version: 2
updates:
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"
day: "sunday"
time: "04:00"
timezone: "UTC"
open-pull-requests-limit: 5
commit-message:
prefix: "deps(pip)"
labels:
- "dependencies"

- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
day: "sunday"
time: "04:00"
timezone: "UTC"
open-pull-requests-limit: 5
commit-message:
prefix: "deps(actions)"
labels:
- "dependencies"

- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
day: "sunday"
time: "04:00"
timezone: "UTC"
open-pull-requests-limit: 3
commit-message:
prefix: "deps(npm)"
labels:
- "dependencies"

20 changes: 18 additions & 2 deletions .github/workflows/preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,28 @@ jobs:
pip3 install wheel
pip3 install -r requirements.txt
make preview
- uses: amondnet/vercel-action@v20
# Deploy only when PR originates from this repo (not a fork)
# and when Vercel secrets are available.
- name: Deploy preview to Vercel
if: ${{ github.event.pull_request.head.repo.fork == false && secrets.VERCEL_TOKEN != '' && secrets.VERCEL_ORG_ID != '' && secrets.VERCEL_PROJECT_ID != '' }}
uses: amondnet/vercel-action@v20
env:
PR_NUMBER: ${{ github.event.number }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }} #Optional
vercel-token: ${{ secrets.VERCEL_TOKEN }} # Required
zeit-token: ${{ secrets.VERCEL_TOKEN }} # Backward-compat for older inputs
vercel-org-id: ${{ secrets.VERCEL_ORG_ID}} #Required
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID}} #Required
working-directory: ./output
alias-domains: | #Optional
alias-domains: |
pr-{{PR_NUMBER}}.dev.py.amsterdam

# If we cannot deploy (fork PR or secrets absent),
# upload the generated site as a build artifact for review.
- name: Upload preview artifact
if: ${{ github.event.pull_request.head.repo.fork == true || secrets.VERCEL_TOKEN == '' || secrets.VERCEL_ORG_ID == '' || secrets.VERCEL_PROJECT_ID == '' }}
uses: actions/upload-artifact@v4
with:
name: site-preview
path: output
1 change: 1 addition & 0 deletions .github/workflows/prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ jobs:
github-token: ${{ secrets.GITHUB_TOKEN }} #Optional
vercel-args: "--prod"
vercel-token: ${{ secrets.VERCEL_TOKEN }} # Required
zeit-token: ${{ secrets.VERCEL_TOKEN }} # Backward-compat for older inputs
vercel-org-id: ${{ secrets.VERCEL_ORG_ID}} #Required
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID}} #Required
working-directory: ./output
172 changes: 172 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

This is the PyAmsterdam community website built with Pelican, a Python-based static site generator. The site showcases meetup events, hosts information, and community pages using reStructuredText content and custom Jinja2 templates.

## Development Environment Setup

**Prerequisites**: Python 3.14+, uv package manager

```bash
# Install dependencies
uv sync

# Activate virtual environment
source .venv/bin/activate
```

## Common Development Commands

### Building and Serving

```bash
# Build site for local development
make html
# or
invoke build

# Serve site locally at http://localhost:8000
make serve

# Build and serve together
invoke reserve

# Auto-rebuild on file changes with live reload
invoke livereload
# or
make devserver

# Rebuild with delete flag (clean build)
invoke rebuild
```

### Testing and Validation

```bash
# Build the site and check for Pelican warnings
make html

# Preview production build locally
invoke preview

# Clean generated output
make clean
```

### Deployment

```bash
# Build production version (for py.amsterdam domain)
make prod

# Build for GitHub Pages and deploy
invoke gh-pages

# Build preview version (requires PR_NUMBER env var)
make preview
```

## Architecture Overview

### Configuration Files

- **pelicanconf.py**: Base configuration with site metadata, Jinja2 filters, plugin settings, and content organization rules
- **conf_prod.py**: Production configuration for https://py.amsterdam (enables CDN, feeds)
- **conf_gh_pages.py**: GitHub Pages configuration for preview deployments
- **tasks.py**: Invoke-based task automation for building, serving, and deploying

### Content Organization

```
content/
├── 2019/...2023/ # Event articles organized by year
│ └── YYYY-MM-DD-*.rst # Events named with ISO date prefix
├── pages/ # Static pages (e.g., Code of Conduct)
└── images/ # Shared assets (logos, banners)
```

**Event Article Structure**: Events use reStructuredText with required metadata fields:
- `:event_type:` (e.g., "Meetup")
- `:rsvp_url:` (Meetup.com or external link)
- `:date:` (YYYY-MM-DD HH:MM format)
- `:cover:` (relative path to cover image for SEO)

Use `docs/event_template.rst` as the starting template for new events.

### Custom Jinja2 Filters (pelicanconf.py)

- **cachebust**: Appends blake2b hash to asset URLs for cache busting
- **by_year**: Groups articles by year for archive pages
- **quoteplus**: URL-encodes strings
- **count_to_font_size**: Logarithmic font sizing for tag clouds
- **chain**: Flattens iterables

### Custom Plugins

Located in `plugins/my-plugins/`:

1. **summary**: Extracts article summaries using `SUMMARY_USE_FIRST_PARAGRAPH` setting (enabled in base config). Automatically uses first `<p>` tag as summary if no explicit markers found.

2. **text_generator**: Renders articles as plain text format (controlled by `GENERATE_TXT = True` in config).

### Theme Structure

```
theme/
├── templates/ # Jinja2 templates for pages and articles
│ ├── index.html # Homepage
│ ├── events.html # Events archive (custom direct template)
│ └── article.html # Individual event pages
└── static/ # CSS, JavaScript, images
```

The theme is custom-built for PyAmsterdam. When modifying templates or static assets, test with `invoke livereload` for instant feedback.

### URL and Path Conventions

- **Article URLs**: `/{YYYY}/{MM}/{DD}/{slug}.html` (defined by `ARTICLE_SAVE_AS` and `ARTICLE_URL`)
- **Filename metadata extraction**: Date parsed from `YYYY-MM-DD-*` filename pattern via `FILENAME_METADATA` regex
- **Date formatting**: Uses strftime format `%-d %B %Y` (day without leading zero, full month name, year)

### Environment Variables

- `SITEURL`: Site base URL (default: http://localhost:8000)
- `SITEPORT`: Development server port (default: 8000)
- `TELEGRAM_URL`: PyAmsterdam Telegram group link
- `CDN`: Enable/disable CDN in production
- `PR_NUMBER`: Required for preview builds

## Development Guidelines

### Adding New Events

1. Copy `docs/event_template.rst` to `content/{YEAR}/YYYY-MM-DD-event-slug.rst`
2. Fill in required metadata (`:event_type:`, `:date:`, `:rsvp_url:`, `:cover:`)
3. Write event description, schedule table, speaker bios, and abstracts
4. Add cover image to `content/images/` and update `:cover:` field
5. Test with `make html` and `make serve`

### Editing Theme or Templates

1. Run `invoke livereload` for automatic rebuilds
2. Template changes appear in `theme/templates/*.html`
3. Static asset changes go in `theme/static/`
4. Test responsive breakpoints manually

### Plugin Development

Custom plugins in `plugins/my-plugins/` must:
- Register via `signals` in `register()` function
- Be added to `PLUGINS` list in `pelicanconf.py`
- Have `__init__.py` importing the plugin module

### Content Style

- Use reStructuredText syntax
- Include schedule tables with `:class: schedule-table`
- Add LinkedIn/website links in `Links` section with `.. _Name: URL` syntax
- End with `.. target-notes::` for automatic link footnotes
- Images use `.. figure::` directive with `{static}` prefix
30 changes: 30 additions & 0 deletions content/images/Zammad_logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added content/images/logo-zammad-community.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added content/images/logo-zammad.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 9 additions & 1 deletion theme/templates/includes/section_sponsors.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,15 @@ <h3 class="h5"><a href="https://www.python.org/psf/" target="_blank" rel="noopen
</div>
<div class="col-12 col-md-4 mb-4">
<div class="supporter-card border rounded p-4 h-100 text-center">
<h3 class="h5"><a href="https://zammad.org" target="_blank" rel="noopener noreferrer">Zammad</a></h3>
<img src="{{ SITEURL }}/images/logo-zammad.png" alt="Zammad logo" class="img-fluid mb-3" style="max-height: 120px;">
<h3 class="h5"><a href="https://zammad.com/" target="_blank" rel="noopener noreferrer">Zammad</a></h3>
<p class="text-muted mb-0 small">Provides enterprise-grade ticketing software for our community support.</p>
</div>
</div>
<div class="col-12 col-md-4 mb-4">
<div class="supporter-card border rounded p-4 h-100 text-center">
<img src="{{ SITEURL }}/images/logo-zammad-community.png" alt="Zammad Community logo" class="img-fluid mb-3" style="max-height: 120px;">
<h3 class="h5"><a href="https://zammad.org/" target="_blank" rel="noopener noreferrer">Zammad Community</a></h3>
<p class="text-muted mb-0 small">Donates ticketing software that helps us support attendees and volunteers.</p>
</div>
</div>
Expand Down