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
5 changes: 3 additions & 2 deletions app/ambassador-program/page.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import type { Metadata } from "next"
import { Button, Card, Eyebrow, PageHero, Panel, Section, SectionHeading } from "@/components/site/page-kit"
import { withSocial } from "@/lib/seo"

export const metadata: Metadata = {
export const metadata: Metadata = withSocial({
alternates: { canonical: "/ambassador-program" },
title: "Campus Ambassador Program",
description:
"Lead Dev Weekends on your campus. Activate your university community, unlock mentor access and deliver career outcomes with playbooks, support and recognition.",
}
})

const APPLICATION_URL = "https://forms.gle/k8JtSqSh2SWVMwJ4A"
const CONTACT_EMAIL = "info@devweekends.com"
Expand Down
5 changes: 3 additions & 2 deletions app/ambassadors/page.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import type { Metadata } from "next"
import AmbassadorsClient from "./ambassadorsClient"
import { withSocial } from "@/lib/seo"

export const metadata: Metadata = {
export const metadata: Metadata = withSocial({
alternates: { canonical: "/ambassadors" },
title: "Ambassadors",
description:
"Meet the people who represent and grow the Dev Weekends community around the world.",
}
})

export default function AmbassadorsPage() {
return <AmbassadorsClient />
Expand Down
9 changes: 9 additions & 0 deletions app/api-docs/page.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
import type { Metadata } from "next"
import { withSocial } from "@/lib/seo"

export const metadata: Metadata = withSocial({
title: "API documentation",
description: "Where to find the machine-readable API description and health status for devweekends.com.",
alternates: { canonical: "/api-docs" },
})

export default function ApiDocsPage() {
return (
<section className="mx-auto max-w-3xl px-4 py-16">
Expand Down
26 changes: 24 additions & 2 deletions app/blog/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,20 @@ import Link from "next/link";
import { ArticleBody } from "@/components/content/article-body";
import { formatDate } from "@/components/content/format-date";
import { Button, Eyebrow, container } from "@/components/site/page-kit";
import { SITE_NAME, blogPostingJsonLd, jsonLdString, withSocial } from "@/lib/seo";

const backLink =
"inline-flex min-h-11 items-center text-[15px] font-medium text-[#5C5C5C] transition-colors hover:text-[#0A0A0A]";

export function generateStaticParams() {
const dir = path.join(process.cwd(), "content", "blog");
if (!fs.existsSync(dir)) return [];
return fs
.readdirSync(dir)
.filter((f) => f.endsWith(".md"))
.map((f) => ({ slug: f.replace(/\.md$/, "") }));
}

export async function generateMetadata({
params,
}: {
Expand All @@ -21,19 +31,22 @@ export async function generateMetadata({
if (!fs.existsSync(filePath)) return { title: "Post not found", robots: { index: false } };
const { data } = matter(fs.readFileSync(filePath, "utf-8"));
const date = data.date ? new Date(data.date) : undefined;
return {
return withSocial({
title: data.title,
description: data.description,
alternates: { canonical: `/blog/${slug}` },
openGraph: {
type: "article",
siteName: SITE_NAME,
locale: "en_US",
title: data.title,
description: data.description,
url: `/blog/${slug}`,
publishedTime: date && !Number.isNaN(date.getTime()) ? date.toISOString() : undefined,
images: data.image ? [{ url: data.image }] : undefined,
},
};
twitter: data.image ? { images: [data.image] } : undefined,
});
}

export default async function BlogPost({
Expand Down Expand Up @@ -76,8 +89,17 @@ export default async function BlogPost({
const fit: "cover" | "contain" =
data.imageFit ?? (slug === "gsoc" ? "contain" : "cover");

const jsonLd = blogPostingJsonLd({
slug,
title: data.title,
description: data.description,
date: data.date,
image: data.image,
});

return (
<main className="bg-white">
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: jsonLdString(jsonLd) }} />
<div className={`${container} pb-20 pt-8 md:pb-24`}>
<Link href="/blog" className={backLink}>
<span aria-hidden="true" className="mr-2">&larr;</span>
Expand Down
5 changes: 3 additions & 2 deletions app/blog/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import fs from "fs";
import path from "path";
import matter from "gray-matter";
import BlogClient from "./blogClient";
import { withSocial } from "@/lib/seo";

export const metadata = {
export const metadata = withSocial({
title: "Blog",
description: "News and stories from Dev Weekends: fellowship updates, Google Summer of Code results and community highlights.",
alternates: { canonical: "/blog" },
}
})

export type Post = {
slug: string;
Expand Down
104 changes: 100 additions & 4 deletions app/brand/page.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import Image from "next/image";
import { Download, ExternalLink } from "lucide-react";

import { BrandLogo } from "@/components/home/brand-logo";
import { Card, Eyebrow, PageHero, Panel, Section, SectionHeading } from "@/components/site/page-kit";
import { withSocial } from "@/lib/seo";

export const metadata = {
export const metadata = withSocial({
alternates: { canonical: "/brand" },
title: "Brand Kit & Speaker Resources",
description:
"Download Dev Weekends logos and the official session slide template. Designed for speakers, mentors, and community partners.",
};
});

type Logo = {
name: string;
Expand All @@ -21,6 +23,22 @@ type Logo = {
};

const logos: Logo[] = [
{
name: "Logo with the week, black",
description: "The wordmark with the seven week bars. The main logo for light surfaces.",
file: "/brand/dw-logo-week-black.png",
download: "dev-weekends-logo-black.png",
kind: "png",
tile: "bg-[#F7F7F7]",
},
{
name: "Logo with the week, white",
description: "The same logo in white. For dark surfaces and photos.",
file: "/brand/dw-logo-week-white.png",
download: "dev-weekends-logo-white.png",
kind: "png",
tile: "bg-[#0A0A0A]",
},
{
name: "Logo on dark badge",
description: "White wordmark on a black circle. Works on light or dark backgrounds.",
Expand Down Expand Up @@ -56,11 +74,20 @@ const logos: Logo[] = [
];

const guidelines = [
"Keep the seven bars under the wordmark. The last two are the weekend, and they stay taller.",
"The tagline, Great engineers. Greater impact., goes next to the logo, never inside it.",
"Keep clear space around the logo equal to the height of the wordmark.",
"Do not stretch, recolor, or add effects to the logo.",
"Use the dark badge version when the background is busy or photographic.",
];

const badges = [
{ name: "In partnership with, light", file: "/brand/dw-badge-partnership-light.svg", tile: "bg-[#F7F7F7]" },
{ name: "In partnership with, dark", file: "/brand/dw-badge-partnership-dark.svg", tile: "bg-[#F7F7F7]" },
{ name: "Community partner of, light", file: "/brand/dw-badge-community-partner-light.svg", tile: "bg-[#F7F7F7]" },
{ name: "Community partner of, dark", file: "/brand/dw-badge-community-partner-dark.svg", tile: "bg-[#F7F7F7]" },
];

const focusRing =
"focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#0A0A0A]";
const outlineBtn = `inline-flex min-h-11 items-center justify-center gap-2 rounded-xl border border-[#D4D4D4] px-5 text-[15px] font-semibold text-[#0A0A0A] transition-colors hover:bg-[#F7F7F7] ${focusRing}`;
Expand All @@ -80,7 +107,7 @@ export default function BrandKitPage() {
title="Download the logo."
intro="Pick the version that fits your background."
/>
<ul className="grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-4">
<ul className="grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-3">
{logos.map((logo) => (
<li key={logo.file}>
<Card tone="bordered" className="h-full overflow-hidden !p-0">
Expand Down Expand Up @@ -159,9 +186,78 @@ export default function BrandKitPage() {
</div>
</Panel>

<Section id="partners" tone="gray">
<SectionHeading
eyebrow="For partner communities"
title="Show that you work with us."
intro="Running an event, a program or a campus chapter with Dev Weekends? Use these on posters, slides and your website."
/>

<div className="grid grid-cols-1 gap-5 lg:grid-cols-[1.1fr_0.9fr]">
<Card tone="white" className="gap-6">
<Eyebrow>Co-branded lockup</Eyebrow>
<div className="flex flex-wrap items-center justify-center gap-6 rounded-[16px] border border-[#E6E6E6] px-6 py-10 sm:gap-8">
<BrandLogo height={64} />
<span aria-hidden="true" className="text-[32px] font-light text-[#8A8A8A]">
×
</span>
<span className="flex h-[76px] min-w-[150px] items-center justify-center rounded-xl border-2 border-dashed border-[#D4D4D4] px-5 text-[15px] font-semibold text-[#8A8A8A]">
Your logo
</span>
</div>
<ul className="space-y-2 text-[15px] leading-[1.6] text-[#404040]">
<li>Put both logos at the same height, with a thin × between them.</li>
<li>Use our black logo on light backgrounds and the white one on dark backgrounds.</li>
<li>Keep the seven bars under our wordmark; do not crop or recolor them.</li>
</ul>
</Card>

<Card tone="white" className="gap-4">
<Eyebrow>Describe us in one line</Eyebrow>
<p className="text-[19px] font-semibold leading-[1.45] tracking-[-0.01em]">
Dev Weekends is a free, international community where engineers learn, build and grow together.
</p>
<p className="text-[15px] leading-[1.6] text-[#5C5C5C]">
Tagline, if you have room: Great engineers. Greater impact.
</p>
<p className="mt-auto text-[15px] leading-[1.6] text-[#404040]">
Send your draft to{" "}
<a
href="mailto:info@devweekends.com?subject=Co-branded%20material%20for%20review"
className={`font-semibold text-[#0A0A0A] underline underline-offset-4 hover:text-[#404040] ${focusRing}`}
>
info@devweekends.com
</a>{" "}
before it goes public.
</p>
</Card>
</div>

<h3 className="mt-12 text-[13px] font-semibold uppercase tracking-[0.14em] text-[#5C5C5C]">Partner badges</h3>
<ul className="mt-5 grid grid-cols-1 gap-5 sm:grid-cols-2">
{badges.map((badge) => (
<li key={badge.file}>
<Card tone="white" className="h-full gap-4 p-5">
<div className="flex items-center justify-center rounded-[14px] bg-[#F7F7F7] p-5">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img src={badge.file} alt={`${badge.name} badge`} width={560} height={168} loading="lazy" decoding="async" className="h-auto w-full max-w-[360px]" />
</div>
<div className="flex flex-wrap items-center justify-between gap-3">
<span className="text-[15px] font-semibold">{badge.name}</span>
<a href={badge.file} download className={outlineBtn}>
<Download className="h-4 w-4" aria-hidden="true" />
SVG
</a>
</div>
</Card>
</li>
))}
</ul>
</Section>

<Section>
<SectionHeading eyebrow="Usage" title="Usage guidelines." />
<ul className="grid grid-cols-1 gap-5 md:grid-cols-3">
<ul className="grid grid-cols-1 gap-5 md:grid-cols-2 lg:grid-cols-3">
{guidelines.map((rule, index) => (
<li key={rule}>
<Card tone="gray" className="h-full">
Expand Down
14 changes: 14 additions & 0 deletions app/careers/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { Metadata } from "next"
import type { ReactNode } from "react"

export const metadata: Metadata = {
title: "Careers",
description:
"Hand-picked opportunities for students and professionals across Dev Weekends and Dev Weekends partner companies.",
alternates: { canonical: "/careers" },
robots: { index: false },
}

export default function CareersLayout({ children }: { children: ReactNode }) {
return children
}
Loading
Loading