Skip to content

Commit d1e364b

Browse files
committed
Add SimpleOpengraphImage
1 parent 811a609 commit d1e364b

14 files changed

+539
-406
lines changed

next.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ export default withLess(
8585

8686
return config
8787
},
88+
/**
89+
* Comment this out if you're working on OG images.
90+
*/
8891
output: "export",
8992
images: {
9093
loader: "custom",

src/app/(development)/workroom/page.tsx

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
1-
import { SpeakerOpengraphImage } from "@/app/conf/2025/components/speaker-opengraph-image"
2-
import { SessionOpengraphImage } from "@/app/conf/2025/components/session-opengraph-image"
1+
import { SpeakerOpengraphImage } from "@/app/conf/2025/components/og-images/speaker-opengraph-image"
2+
import { SessionOpengraphImage } from "@/app/conf/2025/components/og-images/session-opengraph-image"
3+
import { GenericOpengraphImage } from "@/app/conf/2025/components/og-images/generic-opengraph-image"
34
import { SchedSpeaker } from "@/app/conf/2023/types"
45

56
/**
67
* This is cheaper than maintaining a Storybook config.
78
*/
89
export default function WorkroomPage() {
10+
const dateAndLocation = {
11+
date: "September 8-10",
12+
year: "2025",
13+
location: "Amsterdam, Netherlands",
14+
}
15+
916
const enisdenjo: SchedSpeaker = {
1017
name: "Denis Badurina",
1118
username: "enisdenjo",
@@ -35,12 +42,7 @@ export default function WorkroomPage() {
3542
return (
3643
<main className="gql-conf-section gql-conf-container [&>p]:pt-8 [&>p]:font-mono [&>p]:text-sm [&>p]:text-neu-600">
3744
<p>SpeakerOpengraphImage</p>
38-
<SpeakerOpengraphImage
39-
speaker={enisdenjo}
40-
date="September 8-10"
41-
year="2025"
42-
location="Amsterdam, Netherlands"
43-
/>
45+
<SpeakerOpengraphImage speaker={enisdenjo} {...dateAndLocation} />
4446

4547
<p>ScheduleOpengraphImage / no speakers</p>
4648
<SessionOpengraphImage
@@ -50,9 +52,7 @@ export default function WorkroomPage() {
5052
event_type: "",
5153
event_subtype: "",
5254
}}
53-
date="September 8-10"
54-
year="2025"
55-
location="Amsterdam, Netherlands"
55+
{...dateAndLocation}
5656
/>
5757

5858
<p>ScheduleOpengraphImage / single speaker</p>
@@ -63,9 +63,7 @@ export default function WorkroomPage() {
6363
event_type: "Keynote Sessions",
6464
event_subtype: "",
6565
}}
66-
date="September 8-10"
67-
year="2025"
68-
location="Amsterdam, Netherlands"
66+
{...dateAndLocation}
6967
/>
7068

7169
<p>ScheduleOpengraphImage / multiple speakers</p>
@@ -76,9 +74,7 @@ export default function WorkroomPage() {
7674
event_type: "Developer Experience",
7775
event_subtype: "Backend",
7876
}}
79-
date="September 8-10"
80-
year="2025"
81-
location="Amsterdam, Netherlands"
77+
{...dateAndLocation}
8278
/>
8379

8480
<p>SpeakerOpengraphImage / very long title</p>
@@ -107,10 +103,17 @@ export default function WorkroomPage() {
107103
event_type: "Keynote Sessions",
108104
event_subtype: "",
109105
}}
110-
date="September 8-10"
111-
year="2025"
112-
location="Amsterdam, Netherlands"
106+
{...dateAndLocation}
113107
/>
108+
109+
<p>GenericOpengraphImage / GraphQLConf 2025</p>
110+
<GenericOpengraphImage
111+
pageTitle="GraphQLConf 2025"
112+
{...dateAndLocation}
113+
/>
114+
115+
<p>GenericOpengraphImage / Sponsors</p>
116+
<GenericOpengraphImage pageTitle="Sponsors" {...dateAndLocation} />
114117
</main>
115118
)
116119
}
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
import { CalendarIcon } from "@/app/conf/_design-system/pixelarticons/calendar-icon"
2+
import { PinIcon } from "@/app/conf/_design-system/pixelarticons/pin-icon"
3+
4+
import { GraphQLLogo } from "../graphql-conf-logo-link"
5+
import { colors, fonts, RIGHT_COLUMN_WIDTH_PX } from "./speaker-opengraph-image"
6+
7+
export function ConferenceOpengraphImageHeader({
8+
year,
9+
date,
10+
location,
11+
style,
12+
}: {
13+
year: string
14+
date: string
15+
location: string
16+
style?: React.CSSProperties
17+
}) {
18+
return (
19+
<header
20+
style={{
21+
display: "flex",
22+
alignItems: "center",
23+
borderBottom: `2px solid ${colors.neu600}`,
24+
...style,
25+
}}
26+
>
27+
<div
28+
style={{
29+
display: "flex",
30+
flex: 1,
31+
alignItems: "center",
32+
gap: "1.5rem",
33+
borderRight: `2px solid ${colors.neu600}`,
34+
padding: "2.5rem",
35+
paddingRight: "4rem",
36+
height: "154px",
37+
}}
38+
>
39+
<div style={{ display: "flex", alignItems: "center", gap: "1rem" }}>
40+
<div
41+
style={{
42+
fontFamily: fonts.mono,
43+
display: "flex",
44+
fontWeight: "normal",
45+
textTransform: "uppercase",
46+
lineHeight: "1",
47+
color: colors.neu900,
48+
}}
49+
>
50+
<div
51+
style={{
52+
display: "flex",
53+
height: "74px",
54+
alignItems: "center",
55+
gap: "1rem",
56+
fontSize: "40px",
57+
lineHeight: "1",
58+
textTransform: "uppercase",
59+
}}
60+
>
61+
<GraphQLLogo
62+
style={{
63+
height: "3rem",
64+
width: "3rem",
65+
color: colors.priBase,
66+
/* hack: satori aligns this SVG differently than browsers, it will look off center in /workroom,
67+
but centered in the images */
68+
marginTop: "-6px",
69+
}}
70+
/>
71+
<span>/</span>
72+
<div
73+
style={{ display: "flex", alignItems: "center", gap: "0.5rem" }}
74+
>
75+
GraphQLConf{" "}
76+
<span style={{ color: colors.priBase }}>{year}</span>
77+
</div>
78+
</div>
79+
</div>
80+
</div>
81+
</div>
82+
83+
<div
84+
style={{
85+
display: "flex",
86+
height: "100%",
87+
flexShrink: 0,
88+
flexDirection: "column",
89+
justifyContent: "center",
90+
width: RIGHT_COLUMN_WIDTH_PX,
91+
}}
92+
>
93+
<div
94+
style={{
95+
display: "flex",
96+
alignItems: "center",
97+
gap: "1.5rem",
98+
borderBottom: `2px solid ${colors.neu600}`,
99+
paddingLeft: "1.5rem",
100+
paddingRight: "1.5rem",
101+
paddingTop: "26px",
102+
paddingBottom: "26px",
103+
}}
104+
>
105+
<div style={{ display: "flex", alignItems: "center", gap: "0.5rem" }}>
106+
<CalendarIcon
107+
width="24"
108+
height="24"
109+
style={{
110+
/* hack: different across satori and browsers */
111+
transform: "translateY(-3px)",
112+
color: colors.priBase,
113+
}}
114+
/>
115+
<span
116+
style={{
117+
fontFamily: fonts.mono,
118+
display: "flex",
119+
fontSize: "1.25rem",
120+
fontWeight: "normal",
121+
textTransform: "uppercase",
122+
lineHeight: "1.2",
123+
color: colors.neu900,
124+
}}
125+
>
126+
{date}, {year}
127+
</span>
128+
</div>
129+
</div>
130+
131+
<div
132+
style={{
133+
display: "flex",
134+
alignItems: "center",
135+
gap: "1.5rem",
136+
paddingLeft: "1.5rem",
137+
paddingRight: "1.5rem",
138+
paddingTop: "26px",
139+
paddingBottom: "26px",
140+
}}
141+
>
142+
<div style={{ display: "flex", alignItems: "center", gap: "0.5rem" }}>
143+
<PinIcon
144+
width="24"
145+
height="24"
146+
style={{
147+
/* hack: different across satori and browsers */
148+
transform: "translateY(-2px)",
149+
color: colors.priBase,
150+
}}
151+
/>
152+
<span
153+
style={{
154+
fontFamily: fonts.mono,
155+
fontSize: "1.25rem",
156+
fontWeight: "normal",
157+
textTransform: "uppercase",
158+
lineHeight: "1.2",
159+
color: colors.neu900,
160+
}}
161+
>
162+
{location}
163+
</span>
164+
</div>
165+
</div>
166+
</div>
167+
</header>
168+
)
169+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { colors, fonts } from "./speaker-opengraph-image"
2+
import { ConferenceOpengraphImageHeader } from "./conference-opengraph-image-header"
3+
import { normalizeProtocolRelativeUrl } from "./normalize-protocol-relative-url"
4+
5+
import graphqlLogoStripes from "./graphql-logo-stripes.png"
6+
7+
export interface GenericOpengraphImageProps
8+
extends React.HTMLAttributes<HTMLElement> {
9+
date: string
10+
year: string
11+
location: string
12+
pageTitle: string
13+
}
14+
15+
export function GenericOpengraphImage({
16+
date,
17+
location,
18+
year,
19+
pageTitle,
20+
...rest
21+
}: GenericOpengraphImageProps) {
22+
return (
23+
<article
24+
style={{
25+
display: "flex",
26+
height: "630px",
27+
width: "1200px",
28+
flexDirection: "column",
29+
overflow: "hidden",
30+
borderWidth: "2px",
31+
borderColor: colors.neu600,
32+
backgroundColor: colors.neu100,
33+
fontFamily: fonts.sans,
34+
}}
35+
{...rest}
36+
>
37+
<ConferenceOpengraphImageHeader
38+
year={year}
39+
date={date}
40+
location={location}
41+
/>
42+
43+
<div
44+
style={{
45+
display: "flex",
46+
flex: 1,
47+
flexDirection: "column",
48+
justifyContent: "end",
49+
padding: "2.5rem",
50+
position: "relative",
51+
}}
52+
>
53+
<h1
54+
style={{
55+
margin: 0,
56+
fontFamily: fonts.sans,
57+
lineHeight: "1.25",
58+
color: colors.neu900,
59+
fontSize: "96px",
60+
}}
61+
>
62+
{pageTitle}
63+
</h1>
64+
<img
65+
src={graphqlLogoStripes.src}
66+
style={{ position: "absolute", right: 0, bottom: -4 }}
67+
/>
68+
</div>
69+
</article>
70+
)
71+
}
189 KB
Loading
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export function normalizeProtocolRelativeUrl(url: string) {
2+
if (url.startsWith("//")) {
3+
return `https:${url}`
4+
}
5+
return url
6+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { colors, fonts } from "./speaker-opengraph-image"
2+
3+
export function OpengraphImageFooter({
4+
children,
5+
}: {
6+
children: React.ReactNode
7+
}) {
8+
return (
9+
<footer
10+
style={{
11+
display: "flex",
12+
alignItems: "center",
13+
borderTop: `2px solid ${colors.neu600}`,
14+
paddingLeft: "2.5rem",
15+
paddingRight: "4rem",
16+
paddingTop: "2rem",
17+
paddingBottom: "2rem",
18+
}}
19+
>
20+
<span
21+
style={{
22+
fontFamily: fonts.mono,
23+
fontSize: "1.5rem",
24+
fontWeight: "normal",
25+
textTransform: "uppercase",
26+
lineHeight: "1",
27+
color: colors.neu900,
28+
}}
29+
>
30+
{children}
31+
</span>
32+
</footer>
33+
)
34+
}

0 commit comments

Comments
 (0)