diff --git a/docs/_data/portland-2026-config.yaml b/docs/_data/portland-2026-config.yaml index 488d912f6..49511aefe 100644 --- a/docs/_data/portland-2026-config.yaml +++ b/docs/_data/portland-2026-config.yaml @@ -107,7 +107,7 @@ sponsorship: price: $15,000 grants: - url: https://docs.google.com/forms/d/e/1FAIpQLSf3fGfW_8W1x3oeKeoUpg8ZPLvyY4cQvO5Bii_OTrgW97cLNw/viewform?embedded=true + url: "https://docs.google.com/forms/d/e/1FAIpQLSctdb3MT_MvB1x_o8iKKhp_xik8YXDLVCnnDT_tv2k2LPlrJg/viewform?usp=dialog" ends: 'February 5, 2026' notification: 'February 14, 2026' @@ -191,8 +191,14 @@ writing_day: url: "https://docs.google.com/forms/u/1/d/e/1FAIpQLSeHMZ1uXTfnT0HMm-KfsgxYV1w3tmS7bMPtBx4H9cktJpSrdg/viewform?usp=dialog" date: Sunday, May 3, 9 AM - 5 PM +volunteer: + form_url: "https://docs.google.com/forms/d/e/1FAIpQLSeJvA3uhXDuFsl_kFYWyTyTIyYs6ItHMPspOVq_iSlIloFo6g/viewform?usp=sharing&ouid=109538527958730243648" + applications_close: "February 13" + schedule_signup_close: "March 27" + hike: date: Saturday, May 2, 2 PM + register_url: "https://ti.to/writethedocs/write-the-docs-portland-2026/with/k-pi4-g8s80" sponsors: keystone: @@ -210,14 +216,14 @@ sponsors: flaglanding: True flaghassponsors: True flagcfp: True -flagticketsonsale: False +flagticketsonsale: True flagsoldout: False flagspeakersannounced: False flagrunofshow: False flaghasschedule: False flagscheduleincomplete: True flaghasshirts: False -flaglivestreaming: True +flaglivestreaming: False flagvideos: False flagpostconf: False flaghasbadgeflair: False @@ -230,3 +236,8 @@ flaghaswritingday: True flaghaslightningtalks: True flaghasjobfair: True flaghasboat: False + +# Pages to be linked in January 2026 +flaghasvisiting: False +flaghasattendeeguide: False +flaghasteam: False diff --git a/docs/_data/schema-config.yaml b/docs/_data/schema-config.yaml index 009a0e433..60b2775f4 100644 --- a/docs/_data/schema-config.yaml +++ b/docs/_data/schema-config.yaml @@ -38,6 +38,7 @@ writing_day: include('writing_day-details', required=False) lightning_talks: include('lightning_talks-details', required=False) qa: include('qa-details', required=False) hike: include('hike-details', required=False) +volunteer: include('volunteer-details', required=False) flaghassponsors: bool() flagcfp: bool() @@ -66,6 +67,9 @@ flaghasboat: bool() flaglanding: bool() flaghasbadgeflair: bool(required=False) flaghasfood: bool(required=False) +flaghasvisiting: bool(required=False) +flaghasattendeeguide: bool(required=False) +flaghasteam: bool(required=False) --- @@ -208,9 +212,16 @@ writing_day-details: hike-details: date: str(required=True) + register_url: str(required=False) lightning_talks-details: signup_url: str(required=True) qa-details: event_id: str(required=True) + +volunteer-details: + form_url: str(required=False) + applications_close: str(required=False) + schedule_signup_close: str(required=False) + diff --git a/docs/_scripts/process_flickr_images.py b/docs/_scripts/process_flickr_images.py new file mode 100644 index 000000000..b2da9fb36 --- /dev/null +++ b/docs/_scripts/process_flickr_images.py @@ -0,0 +1,144 @@ +#!/usr/bin/env python3 +""" +Download and crop Flickr images to 3x1 aspect ratio with smart centering. +Images are cropped to keep people in frame when possible. +""" + +import os +import subprocess +from PIL import Image + + +def process_flickr_images(): + """Download and process all Flickr images for Portland 2026.""" + + output_dir = '/workspaces/projects/www/docs/_static/conf/images/headers/2026' + os.makedirs(output_dir, exist_ok=True) + + # Photo IDs + flickr_photos = { + 'writing-day': '54533185056', + 'lightning-talks': '54888818907', + 'unconference': '54495525352', + 'social-events': '54498891188', + 'tickets': '54885637248', + 'convince-your-manager': '54506604594', + 'volunteer': '54498514462', + 'virtual': '54498874517', + 'sponsors': '54519655528', + 'prospectus': '54919509718', + 'news': '54499378371', + 'speakers': '54532299817', + 'qa': '54510556714', + 'attendee-guide': '54885594124', + 'team': '54918305952', + } + + print("Downloading and cropping Flickr images to 3x1 aspect ratio...") + print("=" * 60) + + successful = [] + failed = [] + + for page_name, photo_id in flickr_photos.items(): + output_file = os.path.join(output_dir, f'{page_name}.jpg') + url = f'https://www.flickr.com/photos/writethedocs/{photo_id}/' + + print(f"\n{page_name}...", end=" ") + + try: + # Download the HTML page + html_file = f'/tmp/{page_name}_page.html' + result = subprocess.run( + ['curl', '-s', '-L', url, '-o', html_file], + timeout=10, + capture_output=True + ) + + if result.returncode == 0 and os.path.getsize(html_file) > 1000: + # Extract image URLs from HTML + grep_result = subprocess.run( + ['grep', '-oP', r'https://live\.staticflickr\.com/[^"]*?_b\.jpg|https://live\.staticflickr\.com/[^"]*?_c\.jpg|https://live\.staticflickr\.com/[^"]*?_h\.jpg'], + stdin=open(html_file), + capture_output=True, + text=True + ) + + if grep_result.stdout.strip(): + image_url = grep_result.stdout.strip().split('\n')[0] + print(f"downloading...", end=" ") + + # Download the actual image + temp_file = f'/tmp/{page_name}_orig.jpg' + img_result = subprocess.run( + ['curl', '-s', '-L', image_url, '-o', temp_file], + timeout=15, + capture_output=True + ) + + if img_result.returncode == 0 and os.path.getsize(temp_file) > 1000: + try: + img = Image.open(temp_file) + width, height = img.size + + # Crop to 3x1 aspect ratio (width = 3*height) + target_height = 300 # New height for 3x1 ratio + target_width = 900 + target_aspect = target_width / target_height # 3.0 + + aspect_ratio = width / height + + # Smart crop: try to center on content with people + if aspect_ratio > target_aspect: + # Image is wider than target - crop sides + new_width = int(height * target_aspect) + # Smart centering: slightly favor the left/right where people might be + excess = width - new_width + left = excess // 3 # Center with slight bias + img_cropped = img.crop((left, 0, left + new_width, height)) + elif aspect_ratio < target_aspect: + # Image is narrower than target - crop top/bottom + new_height = int(width / target_aspect) + # Smart centering: favor middle section where people typically are + excess = height - new_height + top = excess // 3 # Center with slight bias toward content + img_cropped = img.crop((0, top, width, top + new_height)) + else: + img_cropped = img + + # Resize to final dimensions + img_final = img_cropped.resize((target_width, target_height), Image.Resampling.LANCZOS) + img_final.save(output_file, 'JPEG', quality=92) + + print(f"✓ ({width}x{height} → {target_width}x{target_height})") + successful.append(page_name) + except Exception as e: + print(f"✗ Processing error: {str(e)[:30]}") + failed.append(page_name) + else: + print(f"✗ Download failed") + failed.append(page_name) + else: + print(f"✗ No image URL in HTML") + failed.append(page_name) + else: + print(f"✗ Failed to fetch page") + failed.append(page_name) + + except Exception as e: + print(f"✗ Error: {str(e)[:40]}") + failed.append(page_name) + + print("\n" + "=" * 60) + print(f"Successfully processed: {len(successful)}/{len(flickr_photos)}") + if successful: + print(f"All Flickr images updated to 3x1 aspect ratio (900x300px)") + if failed: + print(f"Failed: {len(failed)}") + + return len(failed) == 0 + + +if __name__ == '__main__': + success = process_flickr_images() + exit(0 if success else 1) diff --git a/docs/_static/conf/images/headers/2026/attendee-guide.jpg b/docs/_static/conf/images/headers/2026/attendee-guide.jpg new file mode 100644 index 000000000..1db788a50 Binary files /dev/null and b/docs/_static/conf/images/headers/2026/attendee-guide.jpg differ diff --git a/docs/_static/conf/images/headers/2026/convince-your-manager.jpg b/docs/_static/conf/images/headers/2026/convince-your-manager.jpg new file mode 100644 index 000000000..151572a36 Binary files /dev/null and b/docs/_static/conf/images/headers/2026/convince-your-manager.jpg differ diff --git a/docs/_static/conf/images/headers/2026/hike.jpg b/docs/_static/conf/images/headers/2026/hike.jpg new file mode 100644 index 000000000..0f413fafd Binary files /dev/null and b/docs/_static/conf/images/headers/2026/hike.jpg differ diff --git a/docs/_static/conf/images/headers/2026/lightning-talks.jpg b/docs/_static/conf/images/headers/2026/lightning-talks.jpg new file mode 100644 index 000000000..0ff980c49 Binary files /dev/null and b/docs/_static/conf/images/headers/2026/lightning-talks.jpg differ diff --git a/docs/_static/conf/images/headers/2026/news.jpg b/docs/_static/conf/images/headers/2026/news.jpg new file mode 100644 index 000000000..26f8f6f91 Binary files /dev/null and b/docs/_static/conf/images/headers/2026/news.jpg differ diff --git a/docs/_static/conf/images/headers/2026/prospectus.jpg b/docs/_static/conf/images/headers/2026/prospectus.jpg new file mode 100644 index 000000000..c84698853 Binary files /dev/null and b/docs/_static/conf/images/headers/2026/prospectus.jpg differ diff --git a/docs/_static/conf/images/headers/2026/qa.jpg b/docs/_static/conf/images/headers/2026/qa.jpg new file mode 100644 index 000000000..736ebbb76 Binary files /dev/null and b/docs/_static/conf/images/headers/2026/qa.jpg differ diff --git a/docs/_static/conf/images/headers/2026/schedule.jpg b/docs/_static/conf/images/headers/2026/schedule.jpg new file mode 100644 index 000000000..43eea9295 Binary files /dev/null and b/docs/_static/conf/images/headers/2026/schedule.jpg differ diff --git a/docs/_static/conf/images/headers/2026/social-events.jpg b/docs/_static/conf/images/headers/2026/social-events.jpg new file mode 100644 index 000000000..fd79e82fe Binary files /dev/null and b/docs/_static/conf/images/headers/2026/social-events.jpg differ diff --git a/docs/_static/conf/images/headers/2026/speakers.jpg b/docs/_static/conf/images/headers/2026/speakers.jpg new file mode 100644 index 000000000..49c12bc4d Binary files /dev/null and b/docs/_static/conf/images/headers/2026/speakers.jpg differ diff --git a/docs/_static/conf/images/headers/2026/sponsors.jpg b/docs/_static/conf/images/headers/2026/sponsors.jpg new file mode 100644 index 000000000..6da7c38a6 Binary files /dev/null and b/docs/_static/conf/images/headers/2026/sponsors.jpg differ diff --git a/docs/_static/conf/images/headers/2026/team.jpg b/docs/_static/conf/images/headers/2026/team.jpg new file mode 100644 index 000000000..ed7789f35 Binary files /dev/null and b/docs/_static/conf/images/headers/2026/team.jpg differ diff --git a/docs/_static/conf/images/headers/2026/tickets.jpg b/docs/_static/conf/images/headers/2026/tickets.jpg new file mode 100644 index 000000000..4fe2e6bf2 Binary files /dev/null and b/docs/_static/conf/images/headers/2026/tickets.jpg differ diff --git a/docs/_static/conf/images/headers/2026/unconference.jpg b/docs/_static/conf/images/headers/2026/unconference.jpg new file mode 100644 index 000000000..63afcf8be Binary files /dev/null and b/docs/_static/conf/images/headers/2026/unconference.jpg differ diff --git a/docs/_static/conf/images/headers/2026/virtual.jpg b/docs/_static/conf/images/headers/2026/virtual.jpg new file mode 100644 index 000000000..520a102b0 Binary files /dev/null and b/docs/_static/conf/images/headers/2026/virtual.jpg differ diff --git a/docs/_static/conf/images/headers/2026/visiting.jpg b/docs/_static/conf/images/headers/2026/visiting.jpg new file mode 100644 index 000000000..35e57c4d5 Binary files /dev/null and b/docs/_static/conf/images/headers/2026/visiting.jpg differ diff --git a/docs/_static/conf/images/headers/2026/volunteer.jpg b/docs/_static/conf/images/headers/2026/volunteer.jpg new file mode 100644 index 000000000..6387419c9 Binary files /dev/null and b/docs/_static/conf/images/headers/2026/volunteer.jpg differ diff --git a/docs/_static/conf/images/headers/2026/writing-day.jpg b/docs/_static/conf/images/headers/2026/writing-day.jpg new file mode 100644 index 000000000..eb8ca5632 Binary files /dev/null and b/docs/_static/conf/images/headers/2026/writing-day.jpg differ diff --git a/docs/_templates/2026/menu-desktop.html b/docs/_templates/2026/menu-desktop.html index 5ed9097f6..daf4cbe43 100644 --- a/docs/_templates/2026/menu-desktop.html +++ b/docs/_templates/2026/menu-desktop.html @@ -61,15 +61,21 @@