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
17 changes: 14 additions & 3 deletions docs/_data/portland-2026-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand Down Expand Up @@ -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:
Expand All @@ -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
Expand All @@ -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
11 changes: 11 additions & 0 deletions docs/_data/schema-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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)

---

Expand Down Expand Up @@ -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)

144 changes: 144 additions & 0 deletions docs/_scripts/process_flickr_images.py
Original file line number Diff line number Diff line change
@@ -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)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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 docs/_static/conf/images/headers/2026/hike.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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 docs/_static/conf/images/headers/2026/news.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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 docs/_static/conf/images/headers/2026/qa.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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 docs/_static/conf/images/headers/2026/team.jpg
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 docs/_static/conf/images/headers/2026/tickets.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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 docs/_static/conf/images/headers/2026/virtual.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 8 additions & 2 deletions docs/_templates/2026/menu-desktop.html
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,21 @@
<ul class="uk-nav uk-navbar-dropdown-nav">
<li><a href="{{ pathto('conf/'+shortcode+'/'+year_str+'/venue') }}">Venue</a></li>
{% if not flagisvirtual %}
{% if flaghasvisiting %}
<li><a href="{{ pathto('conf/'+shortcode+'/'+year_str+'/visiting') }}">Visiting {{ city }}</a></li>
{% endif %}
{% if flaghasattendeeguide %}
<li><a href="{{ pathto('conf/'+shortcode+'/'+year_str+'/attendee-guide') }}">Attendee Guide</a></li>
<li><a href="{{ pathto('conf/'+shortcode+'/'+year_str+'/health') }}">Health and Safety Policy</a></li>
{% endif %}
<li><a href="{{ pathto('conf/'+shortcode+'/'+year_str+'/volunteer') }}">Volunteer Info</a></li>

{% endif %}
<li><a href="{{ pathto('conf/'+shortcode+'/'+year_str+'/virtual') }}">Virtual Attendance</a></li>
{% if not flagisvirtual %}
<li><a href="{{ pathto('conf/'+shortcode+'/'+year_str+'/health') }}">Health and Safety Policy</a></li>
{% endif %}
<li><a href="{{ pathto('conf/'+shortcode+'/'+year_str+'/code-of-conduct') }}">Code of Conduct</a></li>
{% if flagspeakersannounced %}
{% if flaghasteam %}
<li><a href="{{ pathto('conf/'+shortcode+'/'+year_str+'/team') }}">Meet the Team</a></li>
{% endif %}
<li><a href="{{ pathto('conf/'+shortcode+'/'+year_str+'/contact') }}">Contact us</a></li>
Expand Down
10 changes: 8 additions & 2 deletions docs/_templates/2026/menu-mobile.html
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,20 @@
<ul class="uk-nav-sub">
<li><a href="{{ pathto('conf/'+shortcode+'/'+year_str+'/venue') }}">Venue</a></li>
{% if not flagisvirtual %}
{% if flaghasvisiting %}
<li><a href="{{ pathto('conf/'+shortcode+'/'+year_str+'/visiting') }}">Visiting {{ city }}</a></li>
{% endif %}
{% if flaghasattendeeguide %}
<li><a href="{{ pathto('conf/'+shortcode+'/'+year_str+'/attendee-guide') }}">Attendee Guide</a></li>
<li><a href="{{ pathto('conf/'+shortcode+'/'+year_str+'/health') }}">Health and Safety Policy</a></li>
{% endif %}
<li><a href="{{ pathto('conf/'+shortcode+'/'+year_str+'/volunteer') }}">Volunteer Info</a></li>
{% endif %}
<li><a href="{{ pathto('conf/'+shortcode+'/'+year_str+'/virtual') }}">Virtual Attendance</a></li>
{% if not flagisvirtual %}
<li><a href="{{ pathto('conf/'+shortcode+'/'+year_str+'/health') }}">Health and Safety Policy</a></li>
{% endif %}
<li><a href="{{ pathto('conf/'+shortcode+'/'+year_str+'/code-of-conduct') }}">Code of Conduct</a></li>
{% if flagspeakersannounced %}
{% if flaghasteam %}
<li><a href="{{ pathto('conf/'+shortcode+'/'+year_str+'/team') }}">Meet the Team</a></li>
{% endif %}
<li><a href="{{ pathto('conf/'+shortcode+'/'+year_str+'/contact') }}">Contact us</a></li>
Expand Down
11 changes: 5 additions & 6 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,18 +208,17 @@ def _load_data(self, env, data_source, encoding):

# Our additions

global_sponsors = yaml.safe_load("""
- name: gitbook
link: https://www.gitbook.com/?utm_campaign=launch&utm_medium=display&utm_source=write_the_docs&utm_content=ad
brand: GitBook
comment: Community sponsor
""")
global_sponsors = ""

# Dynamic announcement message
announcement_message = None

if datetime.date(2025, 8, 19) <= datetime.date.today() <= datetime.date(2025, 10, 28):
announcement_message = "Berlin conference: Oct 27-28. <a href='/conf/berlin/2025/'>View the conference site</a>."
elif datetime.date.today() <= datetime.date(2026, 1, 19):
announcement_message = "Portland 2026 CFP is open! <a href='/conf/portland/2026/cfp/'>Submit your talk</a>."
elif datetime.date(2026, 1, 20) <= datetime.date.today() <= datetime.date(2026, 5, 2):
announcement_message = "Portland 2026 tickets are on sale! <a href='/conf/portland/2026/tickets/'>Get your ticket</a>."

html_context = {
'conf_py_root': os.path.dirname(os.path.abspath(__file__)),
Expand Down
2 changes: 1 addition & 1 deletion docs/conf/portland/2026/about.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ We invite you to join hundreds of other folks for a three-day event to explore t
The Write the Docs conference covers any topic related to documentation in the software industry.
Past talks have also covered such diverse topics as empathy, the history of math symbols, and using emoji to keep your users' attention.

Write the Docs brings *everyone* who writes the docs together in the same room: Writers, developers, support engineers, community managers, developer relations, and more.
Write the Docs brings *everyone* who writes the docs together in the same room: writers, developers, support engineers, community managers, developer relations, and more.
We all have things to learn, and there's no better way than gathering at our events and sharing knowledge.
1 change: 1 addition & 0 deletions docs/conf/portland/2026/attendee-guide.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
template: {{year}}/generic.html
og:image: _static/conf/images/headers/{{shortcode}}-{{year}}-opengraph.jpg
banner: _static/conf/images/headers/2026/attendee-guide.jpg
---

# Attendee Guide
Expand Down
6 changes: 3 additions & 3 deletions docs/conf/portland/2026/convince-your-manager.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
template: {{year}}/generic.html
og:image: _static/conf/images/headers/{{shortcode}}-{{year}}-opengraph.jpg
banner: _static/conf/images/headers/2025/unconference.jpg
banner: _static/conf/images/headers/2026/convince-your-manager.jpg
---

# Convince Your Manager
Expand All @@ -24,7 +24,7 @@ Remember to change the things in [brackets]!

*Write the Docs conferences bring together everyone who writes the docs – Tech Writers, Developers, Developer Relations, Customer Support – making the events an ideal networking opportunity. Each conference successfully combines a number of different event formats to deliver engaging, practical, and timely content.*

*There is a single track of talks, a parallel unconference event, and a community writing day. The [sessions from last year](https://www.writethedocs.org/conf/portland/2024/speakers/) will give you a good idea of the kinds of topics covered, many of which are relevant to my work.*
*There is a single track of talks, a parallel unconference event, and a community writing day. The [sessions from last year](https://www.writethedocs.org/conf/portland/2025/speakers/) will give you a good idea of the kinds of topics covered, many of which are relevant to my work.*

*Costs:*

Expand Down Expand Up @@ -94,7 +94,7 @@ Peer review new and existing documentation*

When discussing how to pitch Writing Day, a few helpful tips emerged:

- Highlight specific projects from a previous [Writing Day project list. ](https://www.writethedocs.org/conf/portland/2023/writing-day/#project-listing)
- Highlight specific projects from a previous [Writing Day project list.](https://www.writethedocs.org/conf/portland/2025/writing-day/#project-listing)
- If your community is looking for regular documentation contributions, this is a great place to onboard potential contributors and editors.
- Attending raises the visibility of your company in the community.
- Establishes your team's reputation for caring about their docs.
Expand Down
18 changes: 4 additions & 14 deletions docs/conf/portland/2026/hike.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
template: {{year}}/generic.html
og:image: _static/conf/images/headers/{{shortcode}}-{{year}}-opengraph.jpg
banner: _static/conf/images/headers/hike.png
banner: _static/conf/images/headers/2026/hike.jpg
---

# Hike
Expand All @@ -12,26 +12,16 @@ We will be hiking in the amazing [Forest Park](https://forestparkconservancy.org

**The hike is around 5 miles long with 1,200 feet of elevation gain and is classified as a moderate hike. We’ll be going nice and slow so people can appreciate the views and forest.**

It’s rained on us in the past, but we have faith it will be beautiful this year! We will hopefully see Mount Hood at the top :)

<p style="margin: 2em 0;">
<table border="0" cellpadding="0" cellspacing="0" style="background-color:#2ECC71; border:1px solid #4a4a4a; border-radius:5px;">
<tr>
<td align="center" valign="middle" style="color:#FFFFFF; font-family:Helvetica, Arial, sans-serif; font-size:16px; font-weight:bold; letter-spacing:-.5px; line-height:150%; padding-top:15px; padding-right:30px; padding-bottom:15px; padding-left:30px;">
<a href="https://ti.to/writethedocs/write-the-docs-portland-2026/with/k-pi4-g8s80" target="_blank" style="color:#FFFFFF; text-decoration:none; border-bottom: none;">Sign up for the hike with a free ticket</a>
</td>
</tr>
</table>
</p>
It's rained on us in the past, but we have faith it will be beautiful this year! We will hopefully see Mount Hood at the top :)

## Schedule & Logistics

- **Date: {{ hike.date }}**
- **Date: {{ hike.date }}**
- **Arrival:** Meet 15 minutes before the start time.
- **Lunch (optional):** Join us at the [Nob Hill food carts](https://www.google.com/maps/place/Nob+Hill+Food+Carts/@45.5360531,-122.7007924,19.6z/data=!4m7!3m6!1s0x54950942eb34ca71:0xe277fed8c0cec152!8m2!3d45.5362156!4d-122.7000932!15sChZmb29kIGNhcnRzIG53IHBvcnRsYW5kkgEKZm9vZF9jb3VydOABAA!16s%2Fg%2F11vwhg4f9_?entry=tts) at 12:30pm for lunch. We'll leave for the trailhead at 1:40pm.
- **Start:** [Lower Macleay Park](https://www.google.com/maps/place/Lower+Macleay+Park/@45.5336665,-122.7234215,16z/data=!4m7!3m6!1s0x549509e9f2adf02d:0x1b3668a7adc941d9!8m2!3d45.5359671!4d-122.7125142!15sChVNYWNsZWF5IFBhcmsgRW50cmFuY2VaFyIVbWFjbGVheSBwYXJrIGVudHJhbmNlkgEEcGFya5oBJENoZERTVWhOTUc5blMwVkpRMEZuU1VOb2RWQklaRzluUlJBQuABAA!16s%2Fg%2F11g7wcqxt9?coh=164777&entry=tt&shorturl=1). Meet at the pavilion at the park entrance.
- **End:** Oregon Zoo around 5pm, where we will take the MAX back to town.
- **Tickets:** Participating in the hike is free, but please [register for your ticket](https://ti.to/writethedocs/write-the-docs-portland-2026/with/k-pi4-g8s80) so we can contact you in advance for day-of weather and logistics information.
- **Tickets:** Participating in the hike is free, but please [register for your ticket]({{ hike.register_url }}) so we can contact you in advance for day-of weather and logistics information.

## What to Bring

Expand Down
Loading