Skip to content

Commit ac04dd0

Browse files
committed
Devconnect ARG ticket sharing + OG
1 parent 5c4cea6 commit ac04dd0

5 files changed

Lines changed: 347 additions & 0 deletions

File tree

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React from 'react'
2+
3+
import { Ticket } from 'lib/components/ticket'
4+
import { ShareTicket } from './index'
5+
6+
const TicketPage = (props: any) => {
7+
if (!props.params) return null
8+
9+
return <ShareTicket name={props.params.name} />
10+
}
11+
12+
export async function getStaticPaths() {
13+
return {
14+
paths: [],
15+
fallback: 'blocking',
16+
}
17+
}
18+
19+
export async function getStaticProps(context: any) {
20+
return {
21+
props: {
22+
params: context.params,
23+
},
24+
}
25+
}
26+
27+
export default TicketPage
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { colorKeys, colorMap, Ticket } from 'lib/components/ticket'
2+
import { useState } from 'react'
3+
import argentinaBg from 'assets/images/ba/hero.jpg'
4+
5+
export const ShareTicket = ({ name }: { name?: string }) => {
6+
const [color, setColor] = useState('blue')
7+
return (
8+
<div
9+
style={{
10+
backgroundImage: `url(${argentinaBg.src})`,
11+
backgroundBlendMode: 'difference',
12+
backgroundColor: '#74ACDF47',
13+
backgroundSize: 'cover',
14+
backgroundPosition: 'center',
15+
padding: '20px',
16+
minHeight: '100vh',
17+
display: 'flex',
18+
flexDirection: 'column',
19+
alignItems: 'center',
20+
justifyContent: 'center',
21+
}}
22+
>
23+
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', justifyContent: 'center' }}>
24+
Choose your vibe:{' '}
25+
{colorKeys.map(colorKey => {
26+
const isSelected = color === colorKey
27+
const primaryColor = colorMap[colorKey as keyof typeof colorMap].primary
28+
return (
29+
<button
30+
key={colorKey}
31+
onClick={() => setColor(colorKey)}
32+
style={{
33+
backgroundColor: primaryColor,
34+
border: isSelected ? `2px solid white` : '0px',
35+
padding: '10px 20px',
36+
borderRadius: '5px',
37+
margin: '10px',
38+
}}
39+
></button>
40+
)
41+
})}
42+
</div>
43+
<div style={{ width: '1200px', maxWidth: '100%', height: '630px', color: 'black' }}>
44+
<Ticket color={color} name={name} />
45+
</div>
46+
</div>
47+
)
48+
}
49+
50+
const TicketPage = () => {
51+
return <ShareTicket />
52+
}
53+
54+
export async function getStaticProps(context: any) {
55+
return {
56+
props: {},
57+
}
58+
}
59+
60+
export default TicketPage
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import React from "react";
2+
3+
interface TicketBgSvgProps {
4+
primaryColor: string;
5+
secondaryColor: string;
6+
className?: string;
7+
}
8+
9+
export const TicketBgSvg: React.FC<TicketBgSvgProps> = ({
10+
primaryColor,
11+
secondaryColor,
12+
className,
13+
}) => (
14+
<svg
15+
width="1200"
16+
height="630"
17+
viewBox="0 0 632 342"
18+
fill="none"
19+
xmlns="http://www.w3.org/2000/svg"
20+
className={className}
21+
>
22+
<path
23+
d="M631.956 26.0218V7.43481H0V26.0218H18.587V44.6087H0V63.1957H18.587V81.7826H0V100.37H18.587V118.957H0V137.544H18.587V156.13H37.1739V193.304H18.587V211.891H0V230.478H18.587V249.065H0V267.652H18.587V286.239H0V304.826H18.587V323.413H0V342H631.956V323.413H613.37V304.826H631.956V286.239H613.37V267.652H631.956V249.065H613.37V230.478H631.956V211.891H613.37V193.304H594.783V156.13H613.37V137.544H631.956V118.957H613.37V100.37H631.956V81.7826H613.37V63.1957H631.956V44.6087H613.37V26.0218H631.956ZM576.196 137.544V156.13H557.609V193.304H576.196V211.891H594.783V323.413H37.1739V211.891H55.7609V193.304H74.3478V156.13H55.7609V137.544H37.1739V26.0218H594.783V137.544H576.196Z"
24+
fill={secondaryColor}
25+
/>
26+
<path d="M594.784 18.5869H37.1758V315.978H594.784V18.5869Z" fill="white" />
27+
<path d="M594.784 18.5869H37.1758V315.978H594.784V18.5869Z" fill="white" />
28+
<path
29+
d="M631.956 18.587V0H0V18.587H18.587V37.1739H0V55.7609H18.587V74.3478H0V92.9348H18.587V111.522H0V130.109H18.587V148.696H37.1739V185.87H18.587V204.457H0V223.043H18.587V241.63H0V260.217H18.587V278.804H0V297.391H18.587V315.978H0V334.565H631.956V315.978H613.37V297.391H631.956V278.804H613.37V260.217H631.956V241.63H613.37V223.043H631.956V204.457H613.37V185.87H594.783V148.696H613.37V130.109H631.956V111.522H613.37V92.9348H631.956V74.3478H613.37V55.7609H631.956V37.1739H613.37V18.587H631.956ZM576.196 130.109V148.696H557.609V185.87H576.196V204.457H594.783V315.978H37.1739V204.457H55.7609V185.87H74.3478V148.696H55.7609V130.109H37.1739V18.587H594.783V130.109H576.196Z"
30+
fill={primaryColor}
31+
/>
32+
</svg>
33+
);

lib/components/ticket/index.tsx

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
import React from "react";
2+
import { TicketBgSvg } from "./TicketBgSvg";
3+
4+
export const colorMap = {
5+
blue: { primary: "#74ACDF", secondary: "#417FB8" },
6+
yellow: { primary: "#F6B40E", secondary: "#B2820A" },
7+
pink: { primary: "#FF85A6", secondary: "#BF4465" },
8+
};
9+
10+
export const colorKeys = Object.keys(colorMap);
11+
12+
export const Ticket = ({
13+
name = "Anon",
14+
color = "blue",
15+
}: {
16+
name?: string;
17+
color?: string;
18+
}) => {
19+
if (!colorMap[color as keyof typeof colorMap]) {
20+
return (
21+
<div
22+
style={{
23+
display: "flex",
24+
width: "100%",
25+
height: "100%",
26+
position: "relative",
27+
top: 0,
28+
left: 0,
29+
}}
30+
>
31+
Invalid color
32+
</div>
33+
);
34+
}
35+
36+
const { primary, secondary } =
37+
colorMap[color as keyof typeof colorMap] || colorMap.blue;
38+
39+
return (
40+
<div
41+
style={{
42+
display: "flex",
43+
width: "100%",
44+
height: "100%",
45+
position: "relative",
46+
top: 0,
47+
left: 0,
48+
}}
49+
>
50+
<div
51+
style={{
52+
display: "flex",
53+
flexDirection: "column",
54+
width: "100%",
55+
height: "100%",
56+
position: "absolute",
57+
top: 0,
58+
left: 0,
59+
overflow: "hidden",
60+
// padding: "10px 0",
61+
}}
62+
>
63+
<TicketBgSvg primaryColor={primary} secondaryColor={secondary} />
64+
<div
65+
style={{
66+
display: "flex",
67+
flexDirection: "column",
68+
justifyContent: "space-between",
69+
height: "100%",
70+
position: "absolute",
71+
top: 0,
72+
left: 0,
73+
right: 0,
74+
bottom: 0,
75+
}}
76+
>
77+
<img
78+
src="https://devconnect.org/devconnect-arg/devconnect-arg-logo.png"
79+
alt="Devconnect ARG"
80+
style={{
81+
display: "flex",
82+
position: "absolute",
83+
top: "64px",
84+
left: "129px",
85+
width: "169px",
86+
height: "54px",
87+
}}
88+
/>
89+
<img
90+
src="https://devconnect.org/devconnect-arg/stamp.svg"
91+
alt="Devconnect ARG"
92+
style={{
93+
display: "flex",
94+
position: "absolute",
95+
top: "19px",
96+
right: "149px",
97+
width: "176px",
98+
height: "174px",
99+
}}
100+
/>
101+
<img
102+
src={`https://devconnect.org/devconnect-arg/ETH-${color}.png`}
103+
alt="Devconnect ARG"
104+
style={{
105+
display: "flex",
106+
position: "absolute",
107+
bottom: "68px",
108+
right: "131px",
109+
width: "112px",
110+
height: "178px",
111+
}}
112+
/>
113+
<div
114+
style={{
115+
display: "flex",
116+
flexDirection: "column",
117+
gap: "18px",
118+
textAlign: "center",
119+
position: "absolute",
120+
top: "50%",
121+
left: "50%",
122+
width: "1200px",
123+
marginLeft: "-600px",
124+
marginTop: "-50px",
125+
}}
126+
>
127+
<div
128+
style={{
129+
display: "flex",
130+
justifyContent: "center",
131+
fontSize: "48px",
132+
color: "#8855CC",
133+
fontWeight: 500,
134+
}}
135+
>
136+
{name}
137+
</div>
138+
<div
139+
style={{
140+
display: "flex",
141+
justifyContent: "center",
142+
fontSize: "32px",
143+
color: "#222",
144+
}}
145+
>
146+
is going to Devconnect ARG –
147+
</div>
148+
<div
149+
style={{
150+
display: "flex",
151+
justifyContent: "center",
152+
fontSize: "32px",
153+
color: "#222",
154+
}}
155+
>
156+
the Ethereum World's Fair
157+
</div>
158+
</div>
159+
<div
160+
style={{
161+
display: "flex",
162+
justifyContent: "center",
163+
alignItems: "center",
164+
gap: "32px",
165+
fontSize: "24px",
166+
position: "absolute",
167+
bottom: "100px",
168+
left: "125px",
169+
flexDirection: "column",
170+
}}
171+
>
172+
<div
173+
style={{
174+
display: "flex",
175+
fontSize: "24px",
176+
color: "#1e293b",
177+
}}
178+
>
179+
<span
180+
style={{
181+
fontWeight: "700",
182+
color: "#376894",
183+
}}
184+
>
185+
17 — 22 Nov
186+
</span>{" "}
187+
2025
188+
</div>
189+
<div
190+
style={{
191+
display: "flex",
192+
fontSize: "24px",
193+
color: "#475569",
194+
}}
195+
>
196+
Buenos Aires, Argentina
197+
</div>
198+
</div>
199+
</div>
200+
</div>
201+
</div>
202+
);
203+
};
204+
205+
export default Ticket;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { ImageResponse } from "next/og";
2+
import { Ticket } from "../../../../../../lib/components/ticket";
3+
4+
// Route segment config
5+
export const runtime = "edge";
6+
7+
// Image metadata
8+
export const alt = "Devconnect ARG Tickets";
9+
export const size = { width: 1200, height: 630 };
10+
export const contentType = "image/png";
11+
12+
export default async function Image({
13+
params,
14+
}: {
15+
params: { name: string; color: string };
16+
}) {
17+
const name = params.name || "Anon";
18+
const color = params.color || "blue";
19+
return new ImageResponse(<Ticket name={name} color={color} />, {
20+
...size,
21+
});
22+
}

0 commit comments

Comments
 (0)