Skip to content

new conf design — speakers and schedule #20

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 48 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
9a8f6b4
Switch to current sponsors
hasparus May 14, 2025
22be565
Restyle the Sponsorship perks section
hasparus May 15, 2025
121691b
Run Prettier on SVGs
hasparus May 15, 2025
850675b
Change dl to ul in WhatToExpectSection
hasparus May 15, 2025
32981d8
Add Board Meeting Summary (#1997)
jorydotcom May 19, 2025
b5fa458
Show previous edition speakers in the top minds section
hasparus May 20, 2025
c029ff3
Merge pull request #23 from hasparus/new-conf-design--prev-speakers
hasparus May 20, 2025
5c3e9c9
Restyle Resources
hasparus May 20, 2025
8da1227
Restyle Resources
hasparus May 20, 2025
ccd66a8
Unify widths per @saihaj's suggestion
hasparus May 20, 2025
3edf2b3
Unify more widths per @saihaj's suggestion
hasparus May 20, 2025
5a74403
Tweak styles
hasparus May 20, 2025
b7ab00d
new conf design — landing (#1995)
hasparus May 20, 2025
223a166
Draft new Speakers and Schedule pages
hasparus May 13, 2025
ee9566f
Bring styles closer to the design
hasparus May 13, 2025
93e40fb
Improve styles
hasparus May 14, 2025
f90f70b
Improve schedule grid styles
hasparus May 14, 2025
0257f0e
Add [See the speakers] link
hasparus May 15, 2025
08d1050
Add comboboxes to filters
hasparus May 15, 2025
0776147
Improve dark mode styles
hasparus May 15, 2025
2f6835d
Merge branch 'source' into new-conf-design---landing
hasparus May 20, 2025
84ab9f6
Merge branch 'new-conf-design---landing' into new-conf-design--speakers
hasparus May 20, 2025
6f52538
new conf design — cta section (#1998)
hasparus May 20, 2025
80267e4
new conf design — close mobile menu (#2000)
hasparus May 21, 2025
f92ea0d
new conf design — gallery strip (#1999)
hasparus May 21, 2025
f192c30
Stop marquees in prefers-reduced-motion (#2001)
hasparus May 22, 2025
f308a24
Merge branch 'source' into new-conf-design--speakers
hasparus May 26, 2025
50e37bd
Add variant=tertiary to Button
hasparus May 26, 2025
b6e8cbe
Reuse Hero component
hasparus May 26, 2025
2a169f4
Improve [Clear Filters] button
hasparus May 26, 2025
77ca7a5
Fix the background color
hasparus May 26, 2025
344114c
Improve hover style
hasparus May 26, 2025
29887b1
Improve the backlink
hasparus May 26, 2025
351a819
Actually improve the backlink
hasparus May 26, 2025
0800a08
Bring styles closer to the design
hasparus May 26, 2025
95489a8
Add SpeakerCard
hasparus May 26, 2025
d6b974f
Add a speaker name above the title
hasparus May 27, 2025
6ede3e1
Fix the TS target (match Node version)
hasparus May 28, 2025
4c3ae62
Remove (now redundant) @ts-ignore comments
hasparus May 28, 2025
e5c31da
Display socials in consistent order
hasparus May 28, 2025
df39f5f
Bring the schedule page closer to the design
hasparus May 28, 2025
e857f5e
Improve UI
hasparus May 28, 2025
1f21ec6
Format
hasparus May 29, 2025
cce8bf4
Stop showing socials on speaker cards
hasparus May 29, 2025
89590e7
Improve styles
hasparus May 29, 2025
1f79ce8
Remove [View full PDF] button
hasparus May 29, 2025
d4ec48d
Improve the UI of session page
hasparus May 29, 2025
865cf80
Add a footer to speakers page
hasparus May 29, 2025
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
2 changes: 1 addition & 1 deletion src/app/conf/2023/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export default function ConfPage() {

function Hero() {
return (
<div className="bg-black/20 bg-[url('/img/conf/graphql-conf-bg.png')] bg-cover text-white bg-blend-multiply max-md:text-base">
<div className="bg-blk/20 bg-[url('/img/conf/graphql-conf-bg.png')] bg-cover text-white bg-blend-multiply max-md:text-base">
<div className="container py-16 md:py-20">
<div className="flex items-center gap-6">
<GraphQLConf className="h-14" />
Expand Down
85 changes: 85 additions & 0 deletions src/app/conf/2025/_data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import "server-only"
import { stripHtml } from "string-strip-html"
import { SchedSpeaker, ScheduleSession } from "@/app/conf/2023/types"
import pLimit from "p-limit"

async function fetchData<T>(url: string): Promise<T> {
try {
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
"User-Agent": "GraphQL Conf / GraphQL Foundation",
},
})
const data = await response.json()
return data
} catch (error) {
throw new Error(
`Error fetching data from ${url}: ${(error as Error).message || (error as Error).toString()}`,
)
}
}

const token = process.env.SCHED_ACCESS_TOKEN_2024

async function getUsernames(): Promise<string[]> {
const response = await fetchData<{ username: string }[]>(
`https://graphqlconf2024.sched.com/api/user/list?api_key=${token}&format=json&fields=username`,
)
return response.map(user => user.username)
}

const limit = pLimit(40) // rate limit is 30req/min

async function getSpeakers(): Promise<SchedSpeaker[]> {
const usernames = await getUsernames()

const users = await Promise.all(
usernames.map(username =>
limit(() => {
return fetchData<SchedSpeaker>(
`https://graphqlconf2024.sched.com/api/user/get?api_key=${token}&by=username&term=${username}&format=json&fields=username,company,position,name,about,location,url,avatar,role,socialurls`,
)
}),
),
)

const result = users
.filter(speaker => speaker.role.includes("speaker"))
.map(user => {
return {
...user,
about: stripHtml(user.about).result,
}
})

return result
}

async function getSchedule(): Promise<ScheduleSession[]> {
const sessions = await fetchData<ScheduleSession[]>(
`https://graphqlconf2024.sched.com/api/session/export?api_key=${token}&format=json`,
)

const result = sessions.map(session => {
const { description } = session
if (description?.includes("<")) {
// console.log(`Found HTML element in about field for session "${session.name}"`)
}

// TODO: Preserve formatting??

return {
...session,
description: description && stripHtml(description).result,
}
})

return result
}

export const speakers = await getSpeakers()

// TODO: Collect tags from schedule for speakers.
export const schedule = await getSchedule()
10 changes: 10 additions & 0 deletions src/app/conf/2025/_videos.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const videos: {
id: string
title: string
}[] = [
// temporary
{
id: "fA81OFu9BVY",
title: `Top 10 GraphQL Security Checks for Every Developer - Ankita Gupta, Ankush Jain - Akto.io`,
},
]
144 changes: 112 additions & 32 deletions src/app/conf/2025/assets/graphql-foundation-wordmark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
125 changes: 125 additions & 0 deletions src/app/conf/2025/components/become-a-sponsor/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import clsx from "clsx"

import { Button } from "../../../_design-system/button"

import blurBlob from "./blur-blob.webp"
import { StripesDecoration } from "@/app/conf/_design-system/stripes-decoration"

export function BecomeASponsor() {
return (
<section id="sponsors" className="relative overflow-hidden">
<Stripes />
<div className="gql-conf-container gql-conf-section xl:py-16">
<header className="flex flex-col gap-x-48 gap-y-4 md:flex-row md:items-end md:justify-between">
<div>
<h2 className="typography-h2">Become a Sponsor</h2>
<p className="mt-6 text-pretty typography-body-lg">
Connect with the global GraphQL community and showcase your brand
to industry leaders and decision-makers.
</p>
</div>
<Button
variant="primary"
href="https://events.linuxfoundation.org/sponsor-GraphQLConf-25?utm_source=graphql_conf_2025&utm_medium=website&utm_campaign=sponsor_section"
target="_blank"
rel="noreferrer"
className="shrink-0"
>
Download the Prospectus
</Button>
</header>
<dl className="relative z-10 mt-10 border border-neu-300 md:backdrop-blur-[6.4px] xl:mt-16">
<DefinitionListItem
term="Brand Visibility"
definition="Showcase your brand to thousands of GraphQL enthusiasts and decision-makers."
/>
<DefinitionListItem
term="Lead Generation"
definition="Connect with potential customers and partners in the GraphQL ecosystem."
/>
<DefinitionListItem
term="Thought Leadership"
definition="Position your company as a leader in the GraphQL space."
/>
<DefinitionListItem
term="Talent Acquisition"
definition="Meet and recruit top GraphQL developers and engineers."
/>
<DefinitionListItem
term="Product Feedback"
definition="Gather valuable feedback from the GraphQL community."
/>
<DefinitionListItem
term="Community Impact"
definition="Support and shape the future of GraphQL technology."
/>
</dl>
</div>
</section>
)
}

function DefinitionListItem({
className,
term,
definition,
}: {
className?: string
term: string
definition: string
}) {
return (
<div
className={clsx(
className,
"flex border-b border-neu-300 last:border-b-0 max-sm:flex-col",
)}
>
<dt className="flex min-w-[320px] shrink-0 items-center whitespace-pre border-b border-neu-300 p-4 typography-body-lg max-sm:w-full sm:border-b-0 sm:border-r">
{term}
</dt>
<dd className="flex items-center p-4 typography-body-md">{definition}</dd>
</div>
)
}

function Stripes() {
return (
<div
role="presentation"
// prettier-ignore
// false positive
// eslint-disable-next-line tailwindcss/no-contradicting-classname
className="pointer-events-none absolute inset-0
[--start-1:hsl(var(--color-sec-lighter))]
[--end-1:hsl(hsl(320deg_100%_96%/.8)]
dark:[--start-1:hsl(var(--color-sec-lighter))]
dark:[--end-1:hsl(var(--color-pri-lighter)/.2)]

[--start-2:#FFEAF8]
[--end-2:hsl(var(--color-neu-0))]
dark:[--start-2:rgba(255,204,239,.1)]
dark:[--end-2:hsl(var(--color-pri-lighter)/.4)]

translate-y-12

[mask-size:120%]
3xl:[mask-size:2000px] 2xl:opacity-50
max-md:[mask-size:600%] max-md:opacity-50
"
style={{
maskImage: `url(${blurBlob.src})`,
WebkitMaskImage: `url(${blurBlob.src})`,
maskPosition: "center",
WebkitMaskPosition: "center",
maskRepeat: "no-repeat",
WebkitMaskRepeat: "no-repeat",
}}
>
<StripesDecoration
evenClassName="bg-[linear-gradient(180deg,var(--start-1)_-200%,var(--end-1)_100%)]"
oddClassName="bg-[linear-gradient(180deg,var(--start-2)_0%,var(--end-2)_100%)]"
/>
</div>
)
}
21 changes: 11 additions & 10 deletions src/app/conf/2025/components/call-for-proposals.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ function DefinitionListItem({
definition: string
}) {
return (
<div className={clsx(className, "flex typography-body-md max-sm:flex-col")}>
<div className={clsx(className, "typography-body-md flex max-sm:flex-col")}>
<dt className="flex w-[184.5px] shrink-0 items-center whitespace-pre border-neu-300 bg-white/[0.79] px-3 py-2 max-sm:w-full sm:border-r sm:p-4">
{term}
</dt>
Expand Down Expand Up @@ -139,7 +139,7 @@ function NotesTab() {
event.
</li>
</ul>
<h3 className="mt-6 typography-h3">Preparing to Submit Your Proposal</h3>
<h3 className="typography-h3 mt-6">Preparing to Submit Your Proposal</h3>
<p className="mt-2">
While it is not our intention to provide you with strict instructions on
how to prepare your proposal, we hope you will take a moment to review
Expand All @@ -160,7 +160,7 @@ function NotesTab() {
letting you share your experiences, educate the community about an
issue, or generate interest in a project.
</p>
<h3 className="mt-6 typography-h3">How to Give a Great Talk</h3>
<h3 className="typography-h3 mt-6">How to Give a Great Talk</h3>
<p className="mt-2">
We want to make sure submitters receive resources to help put together a
great submission and if accepted, give the best presentation possible.
Expand All @@ -175,7 +175,7 @@ function NotesTab() {
</a>
.
</p>
<h3 className="mt-6 typography-h3">
<h3 className="typography-h3 mt-6">
Have More Questions? First Time Submitting? Don't Feel Intimidated
</h3>
<p className="mt-2">
Expand Down Expand Up @@ -237,7 +237,7 @@ function ProcessTab() {
<li>The new Subject Matter Experts initiative (SMEs)</li>
<li>The Program Committee</li>
</ul>
<h3 className="mt-6 typography-h3">The Technical Steering Committee</h3>
<h3 className="typography-h3 mt-6">The Technical Steering Committee</h3>
<p className="mt-2">
The TSC are a group of 11 individuals who are elected to serve a two
year term to provide technical oversight of all GraphQL development
Expand All @@ -251,7 +251,7 @@ function ProcessTab() {
<li>Quality of Presentation</li>
<li>Importance</li>
</ul>
<h3 className="mt-6 typography-h3">Subject Matter Experts</h3>
<h3 className="typography-h3 mt-6">Subject Matter Experts</h3>
<p className="mt-2">
The SME initiative is new for 2025. This will be a panel of volunteers
drawn from industry experts, working group members, security and
Expand All @@ -265,7 +265,7 @@ function ProcessTab() {
<li>Originality</li>
<li>Audience Engagement</li>
</ul>
<h3 className="mt-6 typography-h3">The Program Committee</h3>
<h3 className="typography-h3 mt-6">The Program Committee</h3>
<p className="mt-2">
The Program Committee is made up of representatives from the GraphQL
Foundation board and interested members of the GraphQL community who
Expand All @@ -275,7 +275,7 @@ function ProcessTab() {
demographics, to ensure a varied and well-rounded representation of the
GraphQL ecosystem.
</p>
<h3 className="mt-6 typography-h3">
<h3 className="typography-h3 mt-6">
Have More Questions? First Time Submitting? Don't Feel Intimidated
</h3>
<p className="mt-2">
Expand Down Expand Up @@ -348,7 +348,7 @@ export function CallForProposals() {
</a>
.
</p>
<p className="mt-6 typography-body-sm md:mt-10">
<p className="typography-body-sm mt-6 md:mt-10">
Please be aware that the Linux Foundation uses Sessionize for CFP
submissions. Sessionize is a cloud-based event content management
software designed to be intuitive and user-friendly. If you need
Expand Down Expand Up @@ -382,6 +382,7 @@ export function CallForProposals() {
>
{tabsInOrder.map((tab, i) => (
<TabButton
key={tab}
tab={tab}
tabIndex={i === 0 ? 0 : -1}
activeTab={activeTab}
Expand Down Expand Up @@ -441,7 +442,7 @@ function TabButton({
tabIndex={tabIndex}
aria-selected={activeTab === tab}
className={clsx(
"gql-focus-visible flex items-center justify-between px-3 py-4 typography-body-lg hover:bg-sec-light focus:outline-none max-lg:border-b max-lg:border-sec-dark max-lg:first:border-t lg:[--collapsible:1] lg:aria-selected:bg-sec-light",
"gql-focus-visible typography-body-lg flex items-center justify-between px-3 py-4 hover:bg-sec-light focus:outline-none max-lg:border-b max-lg:border-sec-dark max-lg:first:border-t lg:[--collapsible:1] lg:aria-selected:bg-sec-light",
className,
)}
onFocus={() => {
Expand Down
66 changes: 66 additions & 0 deletions src/app/conf/2025/components/cta-card-section/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { StripesDecoration } from "@/app/conf/_design-system/stripes-decoration"

import logoMask from "./logo-mask.webp"

export interface CtaCardSectionProps
extends Omit<React.HTMLAttributes<HTMLElement>, "title"> {
title: React.ReactNode
description: string
children: React.ReactNode
}

export function CtaCardSection({
className,
title: heading,
description,
children,
...rest
}: CtaCardSectionProps) {
return (
<div className="gql-conf-section">
<section
className="relative overflow-hidden bg-gradient-to-r from-pri-dark to-pri-base p-6 dark:from-pri-darker dark:to-pri-dark sm:p-16"
{...rest}
>
<div className="relative z-10 flex flex-col gap-10 sm:items-start [@media(max-width:420px)]:text-center">
<div className="flex flex-col gap-6">
<h2 className="typography-d1 text-neu-0 dark:text-neu-900">
{heading}
</h2>
<p className="typography-body-lg max-w-[555px] text-pretty text-neu-50 dark:text-neu-800">
{description}
</p>
</div>

{children}
</div>

<div
role="presentation"
// prettier-ignore
className="
pointer-events-none absolute
sm:bottom-[-277px] inset-0 sm:left-1/3 xl:left-1/2 sm:top-[-107px] xl:right-[-391px]
[--start:hsl(var(--color-sec-base))]
[--end:hsl(var(--color-sec-lighter))]
dark:[--start:hsl(var(--color-sec-dark))]
dark:[--end:hsl(var(--color-sec-base))]

[mask-size:cover]
max-sm:[mask-position:center] max-sm:opacity-50
sm:[mask-size:1117px]
"
style={{
maskImage: `url(${logoMask.src})`,
maskRepeat: "no-repeat",
}}
>
<StripesDecoration
thin
oddClassName="bg-[linear-gradient(180deg,var(--start)_0%,var(--end)_100%)]"
/>
</div>
</section>
</div>
)
}
Binary file not shown.
Loading
Loading