Skip to content

Commit d99fa3f

Browse files
committed
Provide Opportunity Open Source content as Markdown
Move the Opportunity Open Source page to the same Markdown-driven model as the other static pages (donations, sponsors, contact), so all static content uses a single format that anyone can edit. - Add contents/pages/opportunity-open-source.md with the mission, the upcoming 4.0 edition, a past-editions table (3.0/2.0/1.0 with recap and schedule links), LinkedIn, and a "Get involved" section. - Render it through the shared PageHero + MarkdownRenderer pipeline. - Remove the bespoke data/opportunity-open-source.ts structured data file.
1 parent f7f9f0c commit d99fa3f

3 files changed

Lines changed: 56 additions & 249 deletions

File tree

app/opportunity-open-source/page.tsx

Lines changed: 22 additions & 181 deletions
Original file line numberDiff line numberDiff line change
@@ -1,208 +1,49 @@
1+
import fs from "fs/promises"
2+
import path from "path"
3+
import matter from "gray-matter"
14
import type { Metadata } from "next"
2-
import Link from "next/link"
3-
import { ArrowRight, CalendarDays, ExternalLink, MapPin } from "lucide-react"
4-
5+
import { MarkdownRenderer } from "@/components/markdown-renderer"
56
import { PageHero } from "@/components/page-hero"
6-
import { Linkedin } from "lucide-react"
77
import { getSiteUrl } from "@/lib/site"
8-
import {
9-
editions,
10-
opportunityOpenSource as oos,
11-
type ConferenceEdition,
12-
} from "@/data/opportunity-open-source"
8+
9+
const FILE_PATH = path.join(
10+
process.cwd(),
11+
"contents",
12+
"pages",
13+
"opportunity-open-source.md"
14+
)
1315

1416
export const metadata: Metadata = {
1517
title: "Opportunity Open Source | OpenPrinting",
1618
description:
17-
"Opportunity Open Source is OpenPrinting's annual FOSS conference in India — talks, workshops and hackathons that bring students into open source. See past editions and the next one.",
19+
"OpenPrinting's annual free and open source software conference in India — the mission, past editions, and the upcoming one.",
1820
alternates: { canonical: getSiteUrl("/opportunity-open-source/") },
1921
openGraph: {
2022
title: "Opportunity Open Source | OpenPrinting",
2123
description:
22-
"OpenPrinting's annual free and open source software conference in India. Past editions and the upcoming one.",
24+
"OpenPrinting's annual free and open source software conference in India.",
2325
url: getSiteUrl("/opportunity-open-source/"),
2426
type: "website",
2527
},
2628
}
2729

28-
function EditionCard({ edition }: { edition: ConferenceEdition }) {
29-
return (
30-
<div className="flex h-full flex-col rounded-xl border border-border bg-card p-6 shadow-sm">
31-
<div className="flex items-center justify-between">
32-
<span className="text-2xl font-bold tracking-tight text-foreground">
33-
{oos.shortName} {edition.edition}
34-
</span>
35-
{edition.upcoming ? (
36-
<span className="inline-flex items-center rounded-full border border-emerald-500/30 bg-emerald-500/10 px-2.5 py-1 text-xs font-medium text-emerald-700 dark:text-emerald-300">
37-
Upcoming
38-
</span>
39-
) : (
40-
<span className="text-sm text-muted-foreground">{edition.year}</span>
41-
)}
42-
</div>
30+
export default async function OpportunityOpenSourcePage() {
31+
const raw = await fs.readFile(FILE_PATH, "utf8")
32+
const { data } = matter(raw)
4333

44-
<dl className="mt-4 space-y-2 text-sm">
45-
<div className="flex items-center gap-2 text-foreground">
46-
<MapPin className="h-4 w-4 shrink-0 text-muted-foreground" />
47-
<span>
48-
{edition.venue} <span className="text-muted-foreground">· {edition.location}</span>
49-
</span>
50-
</div>
51-
<div className="flex items-center gap-2 text-foreground">
52-
<CalendarDays className="h-4 w-4 shrink-0 text-muted-foreground" />
53-
<span>{edition.dates}</span>
54-
</div>
55-
</dl>
56-
57-
{edition.summary ? (
58-
<p className="mt-4 text-sm leading-6 text-muted-foreground">{edition.summary}</p>
59-
) : null}
60-
61-
<div className="mt-auto flex flex-wrap gap-x-5 gap-y-2 pt-5 text-sm">
62-
{edition.recapUrl ? (
63-
<Link
64-
href={edition.recapUrl}
65-
className="inline-flex items-center gap-1 font-medium text-primary hover:underline"
66-
>
67-
{edition.upcoming ? "Announcement" : "Read the recap"}
68-
<ArrowRight className="h-4 w-4" />
69-
</Link>
70-
) : null}
71-
{edition.scheduleUrl ? (
72-
<a
73-
href={edition.scheduleUrl}
74-
target="_blank"
75-
rel="noopener noreferrer"
76-
className="inline-flex items-center gap-1 text-muted-foreground hover:text-foreground hover:underline"
77-
>
78-
Schedule
79-
<ExternalLink className="h-3.5 w-3.5" />
80-
</a>
81-
) : null}
82-
</div>
83-
</div>
84-
)
85-
}
86-
87-
export default function OpportunityOpenSourcePage() {
88-
const next = editions.find((e) => e.upcoming)
89-
const past = editions.filter((e) => !e.upcoming)
34+
const title =
35+
typeof data.title === "string" ? data.title : "Opportunity Open Source"
9036

9137
return (
9238
<>
9339
<PageHero
94-
title="Opportunity Open Source"
40+
title={title}
9541
description="OpenPrinting's annual free and open source software conference in India."
9642
/>
9743

98-
<main className="min-h-screen bg-background text-foreground pt-16 pb-20">
99-
<div className="mx-auto max-w-5xl px-4 sm:px-6 lg:px-8 space-y-16">
100-
<section className="space-y-4">
101-
<p className="text-base leading-relaxed text-foreground sm:text-lg">{oos.mission}</p>
102-
<p className="text-sm leading-relaxed text-muted-foreground">{oos.origin}</p>
103-
<a
104-
href={oos.linkedin}
105-
target="_blank"
106-
rel="noopener noreferrer"
107-
className="inline-flex items-center gap-2 text-sm font-medium text-primary hover:underline"
108-
>
109-
<Linkedin className="h-4 w-4" />
110-
Follow Opportunity Open Source on LinkedIn
111-
<ExternalLink className="h-3.5 w-3.5" />
112-
</a>
113-
</section>
114-
115-
{next ? (
116-
<section>
117-
<h2 className="mb-4 text-sm font-semibold uppercase tracking-[0.18em] text-muted-foreground">
118-
Next edition
119-
</h2>
120-
<div className="relative overflow-hidden rounded-2xl border border-border bg-card p-8 shadow-sm">
121-
<div className="absolute inset-0 grid-pattern opacity-40" aria-hidden />
122-
<div className="relative">
123-
<div className="flex flex-wrap items-center gap-3">
124-
<h3 className="text-3xl font-bold tracking-tight">
125-
{oos.shortName} {next.edition}
126-
</h3>
127-
<span className="inline-flex items-center rounded-full border border-emerald-500/30 bg-emerald-500/10 px-2.5 py-1 text-xs font-medium text-emerald-700 dark:text-emerald-300">
128-
Upcoming
129-
</span>
130-
</div>
131-
<div className="mt-4 flex flex-col gap-2 text-sm sm:flex-row sm:gap-8">
132-
<span className="inline-flex items-center gap-2">
133-
<MapPin className="h-4 w-4 text-muted-foreground" />
134-
{next.venue} · {next.location}
135-
</span>
136-
<span className="inline-flex items-center gap-2">
137-
<CalendarDays className="h-4 w-4 text-muted-foreground" />
138-
{next.dates}
139-
</span>
140-
</div>
141-
{next.summary ? (
142-
<p className="mt-4 max-w-2xl text-sm leading-6 text-muted-foreground">
143-
{next.summary}
144-
</p>
145-
) : null}
146-
{next.recapUrl ? (
147-
<Link
148-
href={next.recapUrl}
149-
className="mt-6 inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline"
150-
>
151-
Read the announcement
152-
<ArrowRight className="h-4 w-4" />
153-
</Link>
154-
) : null}
155-
</div>
156-
</div>
157-
</section>
158-
) : null}
159-
160-
<section>
161-
<h2 className="mb-6 text-2xl font-bold tracking-tight">Past editions</h2>
162-
<div className="grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-3">
163-
{past.map((edition) => (
164-
<EditionCard key={edition.edition} edition={edition} />
165-
))}
166-
</div>
167-
</section>
168-
169-
<section className="rounded-2xl border border-border bg-muted/30 p-8">
170-
<h2 className="text-2xl font-bold tracking-tight">Get involved</h2>
171-
<p className="mt-3 max-w-2xl text-sm leading-6 text-muted-foreground">
172-
Want to speak, host a future edition, sponsor the conference, or just attend? Follow the
173-
conference on LinkedIn for announcements and calls for proposals, or get in touch with the
174-
OpenPrinting team.
175-
</p>
176-
<div className="mt-6 flex flex-wrap gap-3 text-sm">
177-
<a
178-
href={oos.linkedin}
179-
target="_blank"
180-
rel="noopener noreferrer"
181-
className="inline-flex items-center gap-2 rounded-full border border-border bg-background px-4 py-2 font-medium text-foreground hover:bg-accent"
182-
>
183-
<Linkedin className="h-4 w-4" />
184-
LinkedIn
185-
</a>
186-
<Link
187-
href="/contact"
188-
className="inline-flex items-center gap-2 rounded-full border border-border bg-background px-4 py-2 font-medium text-foreground hover:bg-accent"
189-
>
190-
Contact us
191-
</Link>
192-
<Link
193-
href="/gsoc"
194-
className="inline-flex items-center gap-2 rounded-full border border-border bg-background px-4 py-2 font-medium text-foreground hover:bg-accent"
195-
>
196-
Google Summer of Code
197-
</Link>
198-
<Link
199-
href="/sponsors"
200-
className="inline-flex items-center gap-2 rounded-full border border-border bg-background px-4 py-2 font-medium text-foreground hover:bg-accent"
201-
>
202-
Sponsors &amp; donations
203-
</Link>
204-
</div>
205-
</section>
44+
<main className="min-h-screen bg-background text-foreground pt-24 pb-16">
45+
<div className="max-w-4xl mx-auto px-4">
46+
<MarkdownRenderer content={raw} showMeta={false} noCard={true} />
20647
</div>
20748
</main>
20849
</>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
title: "Opportunity Open Source"
3+
permalink: /opportunity-open-source/
4+
author_profile: false
5+
---
6+
7+
Opportunity Open Source is OpenPrinting's annual free and open source software (FOSS) conference in India.
8+
9+
It is held every year at a university or institute in India to showcase free and open source software and to motivate students, professors, and researchers to take part in its development — by contributing code, design, documentation, and more. Each edition features talks and hands-on workshops across a wide range of FOSS topics, and often a hackathon. To give people all over India the chance to take part, every edition is held at a different location.
10+
11+
It grew out of the wish of OpenPrinting's Till Kamppeter and Aveek Basu to meet their Google Summer of Code contributors in person and to motivate more people to join the free and open source software community. The conferences have since become a major source of new OpenPrinting and GSoC contributors.
12+
13+
Follow the conference on [LinkedIn](https://www.linkedin.com/company/opportunityopensource/) for announcements and calls for proposals.
14+
15+
## Next edition
16+
17+
### Opportunity Open Source 4.0 — IIIT Allahabad
18+
19+
- **Location:** IIIT Allahabad, Prayagraj, Uttar Pradesh, India
20+
- **Dates:** August 28–30, 2026
21+
22+
The fourth edition, hosted together with the Google Developer Group (GDG) at IIIT Allahabad. Read the [announcement](/OpenPrinting-News-Opportunity-Open-Source-4.0/).
23+
24+
## Past editions
25+
26+
| Edition | Location | Dates | Links |
27+
| --- | --- | --- | --- |
28+
| 3.0 | IIT Kanpur, India | September 5–7, 2025 | [Recap](/OpenPrinting-News-Opportunity-Open-Source-3.0-in-the-IIT-Kanpur,-India/) · [Schedule](https://events.canonical.com/event/134/timetable/) |
29+
| 2.0 | IIT Kanpur, India | August 24–26, 2024 | [Recap](/OpenPrinting-News-August-2024/#opportunity-open-source-in-iit-kanpur) · [Schedule](https://events.canonical.com/event/89/) |
30+
| 1.0 | IIT Mandi, India | September 2023 | [Recap](/OpenPrinting-News-September-2023/#opportunitiy-open-source-in-the-iit-mandi-india) · [Schedule](https://events.canonical.com/event/35/) |
31+
32+
## Get involved
33+
34+
Want to speak, host a future edition, sponsor the conference, or just attend? Follow the conference on [LinkedIn](https://www.linkedin.com/company/opportunityopensource/), get in touch via the [Contact Us](/contact) page, or learn more about [Sponsors &amp; donations](/sponsors). Many of our [Google Summer of Code](/gsoc) contributors first joined us through this conference.

data/opportunity-open-source.ts

Lines changed: 0 additions & 68 deletions
This file was deleted.

0 commit comments

Comments
 (0)