diff --git a/gatsby-node.ts b/gatsby-node.ts
index dc54a44833..60d2dbb63d 100644
--- a/gatsby-node.ts
+++ b/gatsby-node.ts
@@ -1,10 +1,9 @@
-import { ScheduleSession } from "./src/components/Conf/Schedule/ScheduleList"
+import { ScheduleSession } from "./src/components/Conf/Schedule/session-list"
import { SchedSpeaker } from "./src/components/Conf/Speakers/Speaker"
import { GatsbyNode } from "gatsby"
import { createOpenGraphImage } from "gatsby-plugin-dynamic-open-graph-images"
import * as path from "path"
import { glob } from "glob"
-import _ from "lodash"
import { updateCodeData } from "./scripts/update-code-data/update-code-data"
import { organizeCodeData } from "./scripts/update-code-data/organize-code-data"
import { sortCodeData } from "./scripts/update-code-data/sort-code-data"
@@ -177,13 +176,21 @@ export const createPages: GatsbyNode["createPages"] = async ({
)) as SchedSpeaker[]
).filter(s => s.role.includes("speaker"))
- // Create schedule page
createPage({
path: "/conf/schedule",
component: path.resolve("./src/templates/schedule.tsx"),
context: { schedule },
})
+ // Create schedule page
+ createPage({
+ path: "/conf/sessions",
+ component: path.resolve("./src/templates/session.tsx"),
+ context: {
+ schedule: withSpeakerInfo(schedule.filter(session => session.speakers)),
+ },
+ })
+
// Create schedule events' pages
schedule.forEach(event => {
const eventSpeakers = speakers.filter(e =>
@@ -191,7 +198,7 @@ export const createPages: GatsbyNode["createPages"] = async ({
)
createPage({
- path: `/conf/schedule/${event.id}`,
+ path: `/conf/sessions/${event.id}`,
component: path.resolve("./src/templates/event.tsx"),
context: {
event,
@@ -222,6 +229,15 @@ export const createPages: GatsbyNode["createPages"] = async ({
}
})
+ function withSpeakerInfo(session: ScheduleSession[]) {
+ return session.map(session => ({
+ ...session,
+ speakers: session.speakers
+ .map(speaker => speakers.find(s => s.username === speaker.username))
+ .filter(Boolean),
+ }))
+ }
+
// Create speakers list page
createPage({
path: "/conf/speakers",
@@ -239,7 +255,10 @@ export const createPages: GatsbyNode["createPages"] = async ({
createPage({
path: `/conf/speakers/${speaker.username}`,
component: path.resolve("./src/templates/speaker.tsx"),
- context: { speaker, schedule: speakerSessions },
+ context: {
+ speaker,
+ schedule: withSpeakerInfo(speakerSessions),
+ },
})
if (!process.env.GATSBY_CLOUD && !process.env.GITHUB_ACTIONS) {
@@ -274,6 +293,11 @@ export const createPages: GatsbyNode["createPages"] = async ({
toPath: "/conf/schedule",
})
+ createRedirect({
+ fromPath: "/conf/schedule/*",
+ toPath: "/conf/sessions/*",
+ })
+
// redirect swapi with 200
createRedirect({
fromPath: `/swapi-graphql/*`,
diff --git a/package.json b/package.json
index ea4b5f79d3..ce920501f6 100644
--- a/package.json
+++ b/package.json
@@ -5,8 +5,8 @@
"scripts": {
"build": "gatsby build",
"develop": "gatsby develop",
- "format": "prettier --write \"**/*.{js,jsx,ts,tsx,json,md}\"",
- "format:check": "prettier --check \"**/*.{js,jsx,ts,tsx,json,md}\"",
+ "format": "yarn format:check --write",
+ "format:check": "prettier --cache --check \"**/*.{js,jsx,ts,tsx,json,md}\"",
"start": "yarn develop",
"serve": "gatsby serve",
"clean": "gatsby clean",
diff --git a/src/components/Conf/Header/index.tsx b/src/components/Conf/Header/index.tsx
index 25a3f6274b..a3eb98e9ba 100644
--- a/src/components/Conf/Header/index.tsx
+++ b/src/components/Conf/Header/index.tsx
@@ -10,6 +10,7 @@ interface LinkItem {
const links: LinkItem[] = [
{ text: "Speakers", href: "/conf/speakers/" },
+ { text: "Sessions", href: "/conf/sessions/" },
{ text: "Schedule", href: "/conf/schedule/" },
{ text: "FAQ", href: "/conf/faq/" },
]
diff --git a/src/components/Conf/Schedule/BackLink.tsx b/src/components/Conf/Schedule/BackLink.tsx
index 65bd16e200..365f280ef2 100644
--- a/src/components/Conf/Schedule/BackLink.tsx
+++ b/src/components/Conf/Schedule/BackLink.tsx
@@ -1,13 +1,13 @@
import React from "react"
-export const BackLink = ({ kind }: { kind: "speakers" | "schedule" }) => {
+export const BackLink = ({ kind }: { kind: "speakers" | "sessions" }) => {
return (
- {"<"} Back to {kind === "speakers" ? "Speakers" : "Schedule"}
+ < Back to {kind === "speakers" ? "Speakers" : "Sessions"}
)
diff --git a/src/components/Conf/Schedule/Filters.tsx b/src/components/Conf/Schedule/Filters.tsx
index 551f128fe2..86c32cc5f4 100644
--- a/src/components/Conf/Schedule/Filters.tsx
+++ b/src/components/Conf/Schedule/Filters.tsx
@@ -17,108 +17,93 @@ export default function Filters({
onReset,
}: FiltersProps) {
return (
-
-
-
-
- {Object.values(filterState).flat().length > 0 && (
-
- Reset filters
-
- )}
-
-
-
-
- {categories.map(option => (
-
- 0
- ? "font-medium text-gray-900"
- : "text-gray-500"
- )}
- >
- {option.name}
-
-
- ))}
-
-
-
-
+
+ {Object.values(filterState).flat().length > 0 && (
+
+ Reset filters
+
+ )}
+
+
+
+
+ {categories.map(option => (
+
+ 0
+ ? "font-medium text-gray-900"
+ : "text-gray-500"
+ )}
+ >
+ {option.name}
+
+
+ ))}
+
+
+
+
+
+ {categories.map((section, sectionIdx) => (
+
-
+ {option}
+
+
+ ))}
+
+
+
+ ))}
+
)
}
diff --git a/src/components/Conf/Schedule/session-list.tsx b/src/components/Conf/Schedule/session-list.tsx
new file mode 100644
index 0000000000..ceb0b7c17d
--- /dev/null
+++ b/src/components/Conf/Schedule/session-list.tsx
@@ -0,0 +1,289 @@
+import { compareAsc } from "date-fns"
+import React, { ComponentProps, FC, useEffect, useState } from "react"
+import { eventsColors } from "../../../utils/eventsColors"
+import Filters from "./Filters"
+import { SchedSpeaker } from "../Speakers/Speaker"
+
+export interface ScheduleSession {
+ id: string
+ audience: string
+ description: string
+ event_end: string
+ event_start: string
+ event_subtype: string
+ event_type: string
+ name: string
+ venue: string
+ speakers?: SchedSpeaker[] | string
+ files?: { name: string; path: string }[]
+}
+
+export interface ConcurrentSessions {
+ [date: string]: ScheduleSession[]
+}
+
+export interface ScheduleSessionsByDay {
+ [date: string]: ConcurrentSessions
+}
+
+export type CategoryName = "Audience" | "Talk category" | "Event type"
+
+const filterCategories: Array<{ name: CategoryName; options: string[] }> = [
+ {
+ name: "Audience",
+ options: ["Beginner", "Intermediate", "Advanced"],
+ },
+ {
+ name: "Talk category",
+ options: [
+ "Beyond Javascript",
+ "Spec Fusion",
+ "Platform and Backend",
+ "GraphQL and Data",
+ "GraphQL Security",
+ "GraphQL in Production",
+ "GraphQL Clients",
+ "GraphQL Core",
+ "Scaling",
+ "Emerging Community Trends",
+ ],
+ },
+ {
+ name: "Event type",
+ options: [
+ "Workshops",
+ "Unconference",
+ "Keynote Sessions",
+ "Sponsor Showcase",
+ "Session Presentations",
+ "Lightning Talks",
+ "Events & Experiences",
+ ],
+ },
+]
+
+function getSessionsByDay(
+ scheduleData: ScheduleSession[],
+ initialFilter:
+ | ((sessions: ScheduleSession[]) => ScheduleSession[])
+ | undefined,
+ filters: Record
+) {
+ const data = initialFilter ? initialFilter(scheduleData) : scheduleData
+ const filteredSortedSchedule = (data || []).sort((a, b) =>
+ compareAsc(new Date(a.event_start), new Date(b.event_start))
+ )
+
+ const concurrentSessions: ConcurrentSessions = {}
+ filteredSortedSchedule.forEach(session => {
+ const audienceFilter = filters.Audience
+ const talkCategoryFilter = filters["Talk category"]
+ const eventTypeFilter = filters["Event type"]
+
+ let include = true
+ if (audienceFilter.length > 0) {
+ include = include && audienceFilter.includes(session.audience)
+ }
+ if (talkCategoryFilter.length > 0) {
+ include = include && talkCategoryFilter.includes(session.event_subtype)
+ }
+ if (eventTypeFilter.length > 0) {
+ include = include && eventTypeFilter.includes(session.event_type)
+ }
+
+ if (!include) {
+ return
+ }
+
+ if (!concurrentSessions[session.event_start]) {
+ concurrentSessions[session.event_start] = []
+ }
+ concurrentSessions[session.event_start].push(session)
+ })
+
+ const sessionsByDay: ScheduleSessionsByDay = {}
+ Object.entries(concurrentSessions).forEach(([date, sessions]) => {
+ const day = date.split(" ")[0]
+ if (!sessionsByDay[day]) {
+ sessionsByDay[day] = {}
+ }
+ sessionsByDay[day] = {
+ ...sessionsByDay[day],
+ [date]: sessions.sort((a, b) => a.venue.localeCompare(b.venue)),
+ }
+ })
+
+ return sessionsByDay
+}
+
+interface Props {
+ showFilter?: boolean
+ scheduleData: ScheduleSession[]
+ filterSchedule?: (sessions: ScheduleSession[]) => ScheduleSession[]
+}
+
+const SessionList: FC = ({
+ showFilter = true,
+ filterSchedule,
+ scheduleData,
+}) => {
+ const [filtersState, setFiltersState] = useState<
+ Record
+ >({
+ Audience: [],
+ "Talk category": [],
+ "Event type": [],
+ })
+ const [sessionsState, setSessionState] = useState(() =>
+ getSessionsByDay(scheduleData, filterSchedule, filtersState)
+ )
+
+ useEffect(() => {
+ setSessionState(
+ getSessionsByDay(scheduleData, filterSchedule, filtersState)
+ )
+ }, [filtersState, scheduleData])
+
+ return (
+
+ {showFilter && (
+
{
+ setFiltersState(prev => ({
+ ...prev,
+ [category]: checked
+ ? [...prev[category as CategoryName], option]
+ : prev[category as CategoryName].filter(
+ option => option !== option
+ ),
+ }))
+ }}
+ onReset={() => {
+ setFiltersState({
+ Audience: [],
+ "Talk category": [],
+ "Event type": [],
+ })
+ }}
+ />
+ )}
+ {Object.entries(sessionsState).length === 0 ? (
+
+
No sessions found
+
+ ) : (
+
+ )}
+
+ )
+}
+
+function ClockIcon(props: ComponentProps<"svg">) {
+ return (
+
+
+
+
+ )
+}
+
+export default SessionList
diff --git a/src/components/Conf/Speakers/SocialMedia.tsx b/src/components/Conf/Speakers/SocialMedia.tsx
index 939d27f137..a09c7cb895 100644
--- a/src/components/Conf/Speakers/SocialMedia.tsx
+++ b/src/components/Conf/Speakers/SocialMedia.tsx
@@ -27,7 +27,7 @@ export const SocialMediaIcon = ({
switch (service) {
case "twitter":
- return
+ return
case "linkedin":
return
case "facebook":
diff --git a/src/components/Conf/Thanks/index.tsx b/src/components/Conf/Thanks/index.tsx
index 49343ae361..21ff3bf46b 100644
--- a/src/components/Conf/Thanks/index.tsx
+++ b/src/components/Conf/Thanks/index.tsx
@@ -3,39 +3,66 @@ import ButtonConf from "../Button"
const ThanksConf: React.FC = () => {
return (
-
-
- Thank you for Attending!
-
-
-
-
-
-
-
- Thank you to all who joined us for GraphQLConf 2023! We look
- forward to seeing you at future events.
-
-
- To experience the best of this year's event, be sure to watch
- session recordings and slides from speakers, available on the event
- schedule for each talk.
-
-
-
- Explore recordings and slides
-
+ <>
+ {/*
*/}
+ {/*
*/}
+ {/*
*/}
+ {/*
*/}
+ {/*
Thank you for Attending! */}
+ {/* */}
+ {/* Thank you to all who joined us for GraphQLConf 2023 ! We*/}
+ {/* look forward to seeing you at future events.To experience the*/}
+ {/* best of this year's event, be sure to watch session recordings*/}
+ {/* and slides from speakers, available on the event schedule for*/}
+ {/* each talk.*/}
+ {/* */}
+ {/* */}
+ {/*
*/}
+ {/*
*/}
+ {/*
hello
*/}
+ {/*
*/}
+ {/* Explore recordings and slides*/}
+ {/* */}
+ {/*
*/}
+ {/*
*/}
+
+
+ Thank you for Attending!
+
+
+
+
+
+
+
+ Thank you to all who joined us for GraphQLConf 2023! We
+ look forward to seeing you at future events.
+
+
+ To experience the best of this year's event, be sure to watch
+ session recordings and slides from speakers, available on the
+ event schedule for each talk.
+
+
+
+ Explore recordings and slides
+
+
-
-
+
+ >
)
}
diff --git a/src/pages/conf/faq.tsx b/src/pages/conf/faq.tsx
index 8db33f2dde..a79b9e77b8 100644
--- a/src/pages/conf/faq.tsx
+++ b/src/pages/conf/faq.tsx
@@ -2,7 +2,6 @@ import React, { ReactNode } from "react"
import FooterConf from "../../components/Conf/Footer"
import HeaderConf from "../../components/Conf/Header"
import LayoutConf from "../../components/Conf/Layout"
-import ButtonConf from "../../components/Conf/Button"
import SectionConf from "../../components/Conf/Section"
import SeoConf from "../../components/Conf/Seo"
diff --git a/src/pages/conf/index.tsx b/src/pages/conf/index.tsx
index 6dc876fc9c..56042dd11c 100644
--- a/src/pages/conf/index.tsx
+++ b/src/pages/conf/index.tsx
@@ -2,7 +2,6 @@ import React from "react"
import FooterConf from "../../components/Conf/Footer"
import HeaderConf from "../../components/Conf/Header"
import LayoutConf from "../../components/Conf/Layout"
-import ButtonConf from "../../components/Conf/Button"
import SpeakersConf from "../../components/Conf/Speakers"
import AboutConf from "../../components/Conf/About"
import ScheduleGlanceConf from "../../components/Conf/Schedule"
@@ -11,36 +10,22 @@ import { CalendarIcon, GlobeIcon } from "@radix-ui/react-icons"
import ThanksConf from "../../components/Conf/Thanks"
import GalleryConf from "../../components/Conf/Gallery"
-export default () => {
+export default function Page() {
return (
-
-
-
-
-
-
-
-
-
-
- September 19-21, 2023
-
-
-
- San Francisco Bay Area, CA
-
-
-
-
- View the Schedule
-
-
-
+
+
+
+
+
+ September 19-21, 2023
+
+
+ San Francisco Bay Area, CA
diff --git a/src/templates/EventOgImageTemplate.tsx b/src/templates/EventOgImageTemplate.tsx
index 4973c5a037..0ac48a1e58 100644
--- a/src/templates/EventOgImageTemplate.tsx
+++ b/src/templates/EventOgImageTemplate.tsx
@@ -1,6 +1,6 @@
import React from "react"
import { PageProps } from "gatsby"
-import { ScheduleSession } from "../components/Conf/Schedule/ScheduleList"
+import { ScheduleSession } from "../components/Conf/Schedule/session-list"
import { SchedSpeaker } from "../components/Conf/Speakers/Speaker"
import { format, parseISO } from "date-fns"
import { getEventTitle } from "../utils/eventTitle"
diff --git a/src/templates/event.tsx b/src/templates/event.tsx
index e25fab95a5..ae33537c0c 100644
--- a/src/templates/event.tsx
+++ b/src/templates/event.tsx
@@ -8,8 +8,7 @@ import HeaderConf from "../components/Conf/Header"
import LayoutConf from "../components/Conf/Layout"
import SeoConf from "../components/Conf/Seo"
import { SchedSpeaker } from "../components/Conf/Speakers/Speaker"
-import { ScheduleSession } from "../components/Conf/Schedule/ScheduleList"
-import { format, parseISO } from "date-fns"
+import { ScheduleSession } from "../components/Conf/Schedule/session-list"
import { Avatar } from "../components/Conf/Speakers/Avatar"
import clsx from "clsx"
import {
@@ -63,48 +62,20 @@ export const EventComponent: FC<{
- {!hideBackButton &&
}
-
-
-
-
- {/* */}
-
-
-
- {format(parseISO(event.event_start), "EEEE, MMM d")}
-
-
-
- {/* */}
-
-
+ {!hideBackButton && }
+ {recordingTitle.rating > 0.5 && (
+ VIDEO
-
-
Room: {event.venue}
+
@@ -114,26 +85,10 @@ export const EventComponent: FC<{
{eventTitle}
-
- {speakers?.map(speaker => (
-
-
- {speaker.name}
- {speaker.company && ", "}
-
- {speaker.company && speaker.company}
-
- ))}
-
-
{speakers?.map(speaker => (
-
+
+
- {recordingTitle.rating > 0.5 && (
-
-
- Recording
-
-
- VIDEO
- )}
-
- {event.files && (
-
-
- Assets
-
- {event.files?.map(({ name, path }) => (
- <>
-
- {name}
-
-
- >
- ))}
-
- )}
+
diff --git a/src/templates/session.tsx b/src/templates/session.tsx
new file mode 100644
index 0000000000..447ec6adeb
--- /dev/null
+++ b/src/templates/session.tsx
@@ -0,0 +1,32 @@
+import React, { FC } from "react"
+import FooterConf from "../components/Conf/Footer"
+import HeaderConf from "../components/Conf/Header"
+import LayoutConf from "../components/Conf/Layout"
+import SeoConf from "../components/Conf/Seo"
+import { PageProps } from "gatsby"
+import SessionList, {
+ ScheduleSession,
+} from "../components/Conf/Schedule/session-list"
+
+const SessionsTemplate: FC
> = ({
+ pageContext: { schedule },
+}) => {
+ return (
+
+
+
+
+
+
+ )
+}
+
+export function Head() {
+ return
+}
+
+export default SessionsTemplate
diff --git a/src/templates/speaker.tsx b/src/templates/speaker.tsx
index be06c5a6ef..9b4745c2dc 100644
--- a/src/templates/speaker.tsx
+++ b/src/templates/speaker.tsx
@@ -8,9 +8,9 @@ import LayoutConf from "../components/Conf/Layout"
import SeoConf from "../components/Conf/Seo"
import { HeadProps, PageProps } from "gatsby"
import { SchedSpeaker } from "../components/Conf/Speakers/Speaker"
-import ScheduleList, {
+import SessionList, {
ScheduleSession,
-} from "../components/Conf/Schedule/ScheduleList"
+} from "../components/Conf/Schedule/session-list"
import { Avatar } from "../components/Conf/Speakers/Avatar"
import {
SocialMediaIcon,
@@ -29,21 +29,19 @@ const SpeakersTemplate: FC<
-
-
+
+
{speaker.name}
-
- {speaker.company && speaker.company}
-
+ {speaker.company}
{speaker.company && ", "}
{speaker.position}
){2,}/g, "")}
rehypePlugins={[rehypeRaw]}
remarkPlugins={[remarkGfm]}
/>
@@ -75,14 +73,9 @@ const SpeakersTemplate: FC<
/>
-
-
Sessions
-
-
+
Sessions
+
+
diff --git a/src/utils/eventTitle.ts b/src/utils/eventTitle.ts
index cd8e397c66..bb1731bd9b 100644
--- a/src/utils/eventTitle.ts
+++ b/src/utils/eventTitle.ts
@@ -1,4 +1,4 @@
-import { ScheduleSession } from "../components/Conf/Schedule/ScheduleList"
+import { ScheduleSession } from "../components/Conf/Schedule/session-list"
export function getEventTitle(
event: ScheduleSession,
diff --git a/static/img/logos/twitter.svg b/static/img/logos/twitter.svg
index e74d0a7da1..447fc5d190 100644
--- a/static/img/logos/twitter.svg
+++ b/static/img/logos/twitter.svg
@@ -1 +1,3 @@
-
\ No newline at end of file
+
+
+