Skip to content

Commit d2c27a5

Browse files
authored
Merge pull request #380 from github/maintainer-month-2026-update
Maintainer month 2026 update
2 parents f582e87 + 5ebc1e6 commit d2c27a5

File tree

100 files changed

+1878
-227
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

100 files changed

+1878
-227
lines changed

.github/ISSUE_TEMPLATE/add-to-calendar.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,19 @@ body:
3737
type: input
3838
attributes:
3939
label: Start time in UTC
40+
description: 'Use HH:MM format (e.g., 14:00). Enter "TBD" if time is not yet confirmed, or "all-day" for all-day events.'
4041
placeholder: '14:00'
4142
validations:
42-
required: true
43+
required: false
4344

4445
- id: UTCEndTime
4546
type: input
4647
attributes:
4748
label: End time in UTC
49+
description: 'Use HH:MM format (e.g., 15:00). Leave blank if start time is TBD or all-day.'
4850
placeholder: '15:00'
4951
validations:
50-
required: true
52+
required: false
5153

5254
- id: type
5355
type: dropdown
@@ -61,6 +63,7 @@ body:
6163
- talk
6264
- meetup
6365
- fundraising
66+
- workshop
6467
- misc
6568
validations:
6669
required: true

CONTRIBUTING.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ Need to run the website locally for testing? → [Jump to Development Guidelines
4242
### Adding a New Event
4343

4444
1. Navigate to the `content/events/` folder
45-
2. Create a new markdown file with a descriptive name (e.g., `2025-05-20-your-event-name.md`)
45+
2. Create a new markdown file with a descriptive name (e.g., `2026-05-20-your-event-name.md`)
4646
3. Use the following template:
4747

4848
```markdown
@@ -51,6 +51,7 @@ title: 'Your Event Title'
5151
metaTitle: 'Your Event Title'
5252
metaDesc: 'A brief description of your event'
5353
date: 'MM/DD'
54+
endDate: 'MM/DD'
5455
UTCStartTime: 'HH:MM'
5556
UTCEndTime: 'HH:MM'
5657
type: 'meetup'
@@ -64,7 +65,7 @@ linkUrl: 'https://link-to-event.com'
6465
Detailed description of your event goes here. You can use markdown formatting.
6566
```
6667

67-
4. All frontmatter fields (between `---`) are mandatory
68+
> **Note:** `UTCStartTime` and `UTCEndTime` are optional. If omitted, the event will display "TBD" for the time. You can also set them to `'TBD'` explicitly or use `'all-day'` for events that span an entire day. Use `endDate` for multi-day events.
6869
5. Submit a PR with your changes
6970

7071
### Adding a New Resource
@@ -175,8 +176,9 @@ For significant changes like:
175176
- `metaTitle`: Title for SEO meta tags
176177
- `metaDesc`: Description for SEO meta tags
177178
- `date`: Event date in `MM/DD` format
178-
- `UTCStartTime`: Start time in UTC, in `HH:MM` format
179-
- `UTCEndTime`: End time in UTC, in `HH:MM` format
179+
- `endDate`: _(optional)_ End date in `MM/DD` format, for multi-day events (e.g., a conference running May 16-18 would use `date: '05/16'` and `endDate: '05/18'`). Multi-day events display a date range and remain listed as upcoming until the end date passes.
180+
- `UTCStartTime`: _(optional)_ Start time in UTC, in `HH:MM` format. Omit or set to `'TBD'` if the time is not yet confirmed. Set to `'all-day'` for events without a specific start time.
181+
- `UTCEndTime`: _(optional)_ End time in UTC, in `HH:MM` format. Same rules as `UTCStartTime`.
180182
- `type`: One of: `podcast`, `stream`, `talk`, `meetup`, `fundraising`, `conference`, `misc`
181183
- `language`: Primary language of the event
182184
- `location`: `Virtual` or physical location

Participation.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
...a month for open source maintainers to gather, share, and be celebrated.
44
Open source runs the world, but who runs open source? Open source maintainers are behind the software we use everyday, but they don't always have the community or support they need. That's why we're celebrating open source maintainers all month long.
55

6-
The 2025 Maintainer Month is, of course, in **May**! You're invited to participate in whatever ways you'd like, and list what you're doing on the public [Maintainer Month site](https://maintainermonth.github.com/).
6+
The 2026 Maintainer Month is, of course, in **May**! You're invited to participate in whatever ways you'd like, and list what you're doing on the public [Maintainer Month site](https://maintainermonth.github.com/).
77

8-
## Themes for 2025
8+
## Themes for 2026
99

1010
**Theme for Maintainers**
1111

README.md

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Repository for the official GitHub Maintainer Month website. You can access the
66

77
**Add your event!** See the [contributing guide](CONTRIBUTING.md) for details on how.
88

9-
**<p align="center"> ❇️ May 2025 ❇️ </p>**
9+
**<p align="center"> ❇️ May 2026 ❇️ </p>**
1010

1111
## Table of Contents
1212

@@ -20,32 +20,30 @@ Repository for the official GitHub Maintainer Month website. You can access the
2020

2121
## Getting Started
2222

23-
### Installation
23+
Requires [Node.js](https://nodejs.org/) v20 or later.
2424

25-
Run the following command before any other to install all the project's dependencies.
25+
### Installation
2626

2727
```
2828
npm install
2929
```
3030

3131
### Usage
3232

33-
To start application in development mode at [http://localhost:3000](http://localhost:3000) run the following command.
33+
Start the development server at [http://localhost:3000](http://localhost:3000):
3434

3535
```
36-
npm start
36+
npm run dev
3737
```
3838

3939
### Build
4040

41-
To generate the application build run the following command
41+
Generate a production build (static export to the `out` folder):
4242

4343
```
4444
npm run build
4545
```
4646

47-
This will create an `out` folder in the repository root with the static files.
48-
4947
## Contributing
5048

5149
See the [contributing guide](CONTRIBUTING.md) for more details.
@@ -60,5 +58,5 @@ Maintainer Month was created, and is maintained, by GitHub, starting in 2021 as
6058

6159
## License
6260

63-
Copyright © 2025 [GitHub](https://github.com/github).<br />
61+
Copyright © 2026 [GitHub](https://github.com/github).<br />
6462
This project is [MIT](LICENSE) licensed.

api/calendar.js

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { createEvents } from 'ics'
2+
3+
const EVENT_YEAR = 2026
4+
5+
const isTBDValue = (value) =>
6+
!value || (typeof value === 'string' && value.toUpperCase() === 'TBD')
7+
8+
const isAllDayValue = (value) =>
9+
typeof value === 'string' &&
10+
value.toLowerCase().replace(/[\s\-_]/g, '') === 'allday'
11+
12+
function parseDateParts(dateStr) {
13+
const [month, day] = dateStr.split('/').map(Number)
14+
return { month, day }
15+
}
16+
17+
function toICSEvent(event) {
18+
const { month: startMonth, day: startDay } = parseDateParts(event.date)
19+
20+
const hasTime =
21+
!isTBDValue(event.UTCStartTime) && !isAllDayValue(event.UTCStartTime)
22+
23+
const icsEvent = {
24+
title: event.title,
25+
description: event.metaDesc || '',
26+
location: event.location || '',
27+
url: event.linkUrl || '',
28+
calName: 'Maintainer Month 2026',
29+
}
30+
31+
if (hasTime) {
32+
const [startHour, startMinute] = event.UTCStartTime.split(':').map(Number)
33+
icsEvent.start = [EVENT_YEAR, startMonth, startDay, startHour, startMinute]
34+
icsEvent.startInputType = 'utc'
35+
36+
if (!isTBDValue(event.UTCEndTime) && !isAllDayValue(event.UTCEndTime)) {
37+
const [endHour, endMinute] = event.UTCEndTime.split(':').map(Number)
38+
39+
if (event.endDate && event.endDate !== event.date) {
40+
const { month: endMonth, day: endDay } = parseDateParts(event.endDate)
41+
icsEvent.end = [EVENT_YEAR, endMonth, endDay, endHour, endMinute]
42+
} else {
43+
icsEvent.end = [EVENT_YEAR, startMonth, startDay, endHour, endMinute]
44+
}
45+
icsEvent.startOutputType = 'utc'
46+
icsEvent.endInputType = 'utc'
47+
icsEvent.endOutputType = 'utc'
48+
} else {
49+
icsEvent.duration = { hours: 1 }
50+
}
51+
} else {
52+
// All-day or TBD: treat as all-day event
53+
icsEvent.start = [EVENT_YEAR, startMonth, startDay]
54+
icsEvent.startInputType = 'utc'
55+
56+
if (event.endDate && event.endDate !== event.date) {
57+
const { month: endMonth, day: endDay } = parseDateParts(event.endDate)
58+
// ICS all-day end date is exclusive, so add one day
59+
const endDate = new Date(Date.UTC(EVENT_YEAR, endMonth - 1, endDay + 1))
60+
icsEvent.end = [
61+
endDate.getUTCFullYear(),
62+
endDate.getUTCMonth() + 1,
63+
endDate.getUTCDate(),
64+
]
65+
} else {
66+
// Use Date math to handle month boundary rollover
67+
const endDate = new Date(Date.UTC(EVENT_YEAR, startMonth - 1, startDay + 1))
68+
icsEvent.end = [
69+
endDate.getUTCFullYear(),
70+
endDate.getUTCMonth() + 1,
71+
endDate.getUTCDate(),
72+
]
73+
}
74+
}
75+
76+
return icsEvent
77+
}
78+
79+
export function generateICS(events) {
80+
const icsEvents = events.map(toICSEvent)
81+
const { error, value } = createEvents(icsEvents)
82+
83+
if (error) {
84+
throw new Error(`Failed to generate ICS: ${error.message}`)
85+
}
86+
87+
return value
88+
}

api/events.js

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,18 @@ dayjs.extend(utc)
1212
dayjs.extend(timezone)
1313

1414
const TBD = 'TBD'
15+
const ALL_DAY = 'All Day'
16+
17+
const isTBDValue = (value) =>
18+
!value || (typeof value === 'string' && value.toUpperCase() === 'TBD')
19+
20+
const isAllDayValue = (value) =>
21+
typeof value === 'string' &&
22+
value.toLowerCase().replace(/[\s\-_]/g, '') === 'allday'
1523

1624
export const getEvents = (year) => {
1725
const events_path = year ? `content/${year}/events` : 'content/events'
26+
if (!fs.existsSync(events_path)) return []
1827
const eventFiles = fs.readdirSync(events_path)
1928

2029
const events = eventFiles
@@ -108,27 +117,38 @@ const formatEventDateTime = (
108117
formattedEndDate = endUTCDate.format('MMM D')
109118
}
110119

120+
// All-day events
121+
if (isAllDayValue(startTime) || isAllDayValue(endTime)) {
122+
return {
123+
date: formattedDate,
124+
startTime: { utc: ALL_DAY, pt: ALL_DAY },
125+
endTime: { utc: ALL_DAY, pt: ALL_DAY },
126+
endDate: formattedEndDate,
127+
timeDisplay: 'all-day',
128+
}
129+
}
130+
111131
// Start time
112132
let formattedStartTime = {
113133
utc: TBD,
114134
pt: TBD,
115135
}
116136

117-
if (startTime) {
137+
let hasSpecificStartTime = false
138+
139+
if (!isTBDValue(startTime)) {
118140
const [startHour, startMinute] = startTime.split(':')
119141

120142
const UTCStartTime = UTCDate.hour(startHour).minute(startMinute)
121143

122144
if (!isNaN(UTCStartTime)) {
123145
const PTStartTime = UTCStartTime.tz('America/Los_Angeles')
124146

125-
const formattedUTCStartTime = UTCStartTime.format('HH:mm a')
126-
const formattedPTStartTime = PTStartTime.format('HH:mm a')
127-
128147
formattedStartTime = {
129-
utc: formattedUTCStartTime,
130-
pt: formattedPTStartTime,
148+
utc: UTCStartTime.format('h:mm a'),
149+
pt: PTStartTime.format('h:mm a'),
131150
}
151+
hasSpecificStartTime = true
132152
}
133153
}
134154

@@ -138,28 +158,32 @@ const formatEventDateTime = (
138158
pt: TBD,
139159
}
140160

141-
if (endTime && endTime !== TBD) {
161+
let hasSpecificEndTime = false
162+
163+
if (!isTBDValue(endTime)) {
142164
const [endHour, endMinute] = endTime.split(':')
143165

144166
const UTCEndTime = UTCDate.hour(endHour).minute(endMinute)
145167

146168
if (!isNaN(UTCEndTime)) {
147169
const PTEndTime = UTCEndTime.tz('America/Los_Angeles')
148170

149-
const formattedUTCEndTime = UTCEndTime.format('HH:mm a')
150-
const formattedPTEndTime = PTEndTime.format('HH:mm a')
151-
152171
formattedEndTime = {
153-
utc: formattedUTCEndTime,
154-
pt: formattedPTEndTime,
172+
utc: UTCEndTime.format('h:mm a'),
173+
pt: PTEndTime.format('h:mm a'),
155174
}
175+
hasSpecificEndTime = true
156176
}
157177
}
158178

179+
const timeDisplay =
180+
hasSpecificStartTime || hasSpecificEndTime ? 'specific' : 'tbd'
181+
159182
return {
160183
date: formattedDate,
161184
startTime: formattedStartTime,
162185
endTime: formattedEndTime,
163186
endDate: formattedEndDate,
187+
timeDisplay,
164188
}
165189
}

common/routes.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ export const Y2024 = makePath('/2024')
3030

3131
export const NEWS = makePath("/news")
3232

33+
export const SHIPS = makePath('/ships')
34+
3335
export const PARTNER_PACK = makePath('/partner-pack')
3436

3537
export const SECURITY_CHALLENGE = makePath('/security-challenge')

components/chip/chip.scss

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
display: inline-flex;
44
align-items: center;
55
column-gap: 6px;
6-
flex-shrink: 0;
76
white-space: nowrap;
7+
max-width: 100%;
8+
overflow: hidden;
9+
text-overflow: ellipsis;
810

911
background-color: $white;
1012
@extend %subtitle-1;

0 commit comments

Comments
 (0)