Skip to content

Commit a787ce7

Browse files
committed
feat: Implement HomeWTC section displaying event information and a live countdown.
1 parent d55f877 commit a787ce7

File tree

11 files changed

+468
-2
lines changed

11 files changed

+468
-2
lines changed

public/images/wtc-gemini-1.webp

96.4 KB
Loading

public/images/wtc-gemini-2.webp

119 KB
Loading

public/images/wtc-gemini-3.webp

110 KB
Loading

src/styles/colors.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export enum Color {
1313
PURPLE = "#b000d0",
1414
RED = "#ff0000b0",
1515
SKY_BLUE = "#93d6ff",
16+
TRANSPARENT = "transparent",
1617
WHITE = "#fffcf9",
1718
YELLOW = "#ffd166",
1819
}

src/views/Home/HomeWrapper.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { BIG_BREAKPOINT } from "@constants/BreakPoints";
22
import React, { FC } from "react";
33
import Faqs from "./components/Faqs/Faqs";
4-
import Home from "./components/Home/Home";
4+
;
55
import Sponsors from "./components/Sponsors/Sponsors";
66
import { styled } from "styled-components";
77
import conferenceData from "@data/2026.json";
@@ -10,6 +10,7 @@ import { useLocation } from "react-router";
1010
import SpeakersCarousel from "@components/Swiper/SpeakersCarousel";
1111
import { ROUTE_2026_SPEAKERS } from "@constants/routes";
1212
import { useDocumentTitleUpdater } from "@hooks/useDocumentTitleUpdate";
13+
import HomeWTC from "./components/HomeWTC/HomeWTC";
1314

1415
const StyledContainer = styled.div`
1516
padding-bottom: 10rem;
@@ -33,7 +34,7 @@ export const HomeWrapper: FC<React.PropsWithChildren<unknown>> = () => {
3334

3435
return (
3536
<StyledContainer id="home-wrapper">
36-
<Home />
37+
<HomeWTC />
3738
{conferenceData?.carrousel.enabled && (
3839
<SpeakersCarousel
3940
sessionizeUrl={"default"}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { format } from "date-fns";
2+
3+
export function formatDateRange(startDate: Date, endDate: Date): string {
4+
const sameMonthAndYear =
5+
startDate.getMonth() === endDate.getMonth() &&
6+
startDate.getFullYear() === endDate.getFullYear();
7+
8+
if (sameMonthAndYear) {
9+
return `${format(startDate, "MMMM do")} - ${format(endDate, "do, yyyy")}`;
10+
} else {
11+
return `${format(startDate, "MMMM do, yyyy")} - ${format(
12+
endDate,
13+
"MMMM do, yyyy",
14+
)}`;
15+
}
16+
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import Countdown from "react-countdown";
2+
import React, { FC } from "react";
3+
import { SectionWrapper } from "@components/SectionWrapper/SectionWrapper";
4+
import TimeCountDown from "./components/TimeCountdown";
5+
import { useWindowSize } from "react-use";
6+
import { useDateInterval } from "@hooks/useDateInterval";
7+
// @ts-expect-error some quirky import
8+
import { motion } from "motion/react";
9+
import {
10+
StyledDevBcnLogo,
11+
StyledHomeImage,
12+
StyledLogoDiv,
13+
StyledSubtitle,
14+
StyledTitle,
15+
StyledTitleContainer,
16+
StyleHomeContainer,
17+
} from "./Style.Home";
18+
import ActionButtons from "../ActionButtons/ActionButtons";
19+
import { Color } from "@styles/colors";
20+
import InfoButtons from "../InfoButtons/InfoButtons";
21+
import { formatDateRange } from "./DateUtil";
22+
import { Link } from "react-router";
23+
import edition from "@data/2026.json";
24+
import CountDownCompleted from "./components/CountDownCompleted";
25+
26+
const HomeWTC: FC<React.PropsWithChildren<unknown>> = () => {
27+
const { width } = useWindowSize();
28+
const { isTicketsDisabled, isSponsorDisabled, isCfpDisabled } =
29+
useDateInterval(new Date(), edition);
30+
31+
return (
32+
<StyledHomeImage>
33+
<SectionWrapper color="transparent">
34+
<StyleHomeContainer>
35+
<StyledLogoDiv
36+
initial={{ opacity: 0, scale: 0.5 }}
37+
animate={{ opacity: 1, scale: 1 }}
38+
transition={{ duration: 0.8 }}
39+
>
40+
<StyledDevBcnLogo src="images/logo.png" alt="DevBcn logo" />
41+
</StyledLogoDiv>
42+
<StyledTitleContainer color={Color.TRANSPARENT}
43+
initial={{ opacity: 0, y: 50 }}
44+
animate={{ opacity: 1, y: 0 }}
45+
transition={{ duration: 0.6, delay: 0.3 }}
46+
>
47+
<StyledTitle
48+
initial={{ opacity: 0 }}
49+
animate={{ opacity: 1 }}
50+
transition={{ duration: 0.5, delay: 0.6 }}
51+
>
52+
The Barcelona Developers Conference {edition?.edition}
53+
</StyledTitle>
54+
<StyledSubtitle fontWeight={600}
55+
initial={{ opacity: 0 }}
56+
animate={{ opacity: 1 }}
57+
transition={{ duration: 0.5, delay: 0.8 }}
58+
>
59+
{edition?.trackNumber} tracks with the following topics: <br />
60+
{edition?.tracks}
61+
</StyledSubtitle>
62+
<StyledSubtitle shadow={true}
63+
initial={{ opacity: 0 }}
64+
animate={{ opacity: 1 }}
65+
transition={{ duration: 0.5, delay: 1 }}
66+
>
67+
<small>
68+
Past events: <Link to="/2025">2025 edition</Link> |{" "}
69+
<Link to="/2024">2024 edition</Link> |{" "}
70+
<Link to="/2023">2023 edition</Link>
71+
</small>
72+
</StyledSubtitle>
73+
</StyledTitleContainer>
74+
<motion.img
75+
src="/images/devBcn-sponsorship.png"
76+
alt="DevBcn sponsorship value"
77+
width="635"
78+
height="125"
79+
style={{ aspectRatio: "127:25", maxWidth: "100%" }}
80+
initial={{ opacity: 0, x: -50 }}
81+
animate={{ opacity: 1, x: 0 }}
82+
transition={{ duration: 0.7, delay: 1.2 }}
83+
/>
84+
<StyledTitleContainer
85+
color={Color.TRANSPARENT}
86+
initial={{ opacity: 0, y: 30 }}
87+
animate={{ opacity: 1, y: 0 }}
88+
transition={{ duration: 0.6, delay: 1.5 }}
89+
>
90+
<StyledSubtitle fontWeight={600}>
91+
{edition?.startDay &&
92+
edition.endDay &&
93+
formatDateRange(
94+
new Date(edition.startDay),
95+
new Date(edition.endDay),
96+
)}
97+
</StyledSubtitle>
98+
<StyledSubtitle fontWeight={600}>
99+
World Trade Center, Barcelona
100+
</StyledSubtitle>
101+
</StyledTitleContainer>
102+
<motion.div
103+
initial={{ opacity: 0, scale: 0.9 }}
104+
animate={{ opacity: 1, scale: 1 }}
105+
transition={{ duration: 0.8, delay: 1.8 }}
106+
>
107+
<Countdown
108+
date={edition?.startDay}
109+
onComplete={CountDownCompleted}
110+
renderer={TimeCountDown}
111+
/>
112+
</motion.div>
113+
{edition?.actionButtons && (
114+
<ActionButtons
115+
isTicketsDisabled={isTicketsDisabled}
116+
isCfpDisabled={isCfpDisabled}
117+
isSponsorDisabled={isSponsorDisabled}
118+
ticketsStartDay={edition.tickets.startDay}
119+
cfpStartDay={edition.cfp.startDay}
120+
cfpLink={edition.cfp.link}
121+
edition={edition.edition}
122+
/>
123+
)}
124+
{edition?.showInfoButtons && <InfoButtons />}
125+
</StyleHomeContainer>
126+
</SectionWrapper>
127+
</StyledHomeImage>
128+
);
129+
};
130+
131+
export default HomeWTC;
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
import { styled } from "styled-components";
2+
import { Color } from "@styles/colors";
3+
// @ts-expect-error some quirky import
4+
import { motion } from "motion/react";
5+
import { BIG_BREAKPOINT, BIGGER_BREAKPOINT } from "@constants/BreakPoints";
6+
7+
// By © Alice Wiegand / CC-BY-SA-3.0 (via Wikimedia Commons), CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=30463612
8+
// By © Felix König / CC-BY-3.0 (via Wikimedia Commons), CC BY-SA 3.0, https://commons.wikimedia.org/wiki/File:World_Trade_Center_Barcelona_2013_1.jpg
9+
// By © Felix König / CC-BY-SA-3.0 (via Wikimedia Commons), CC BY-SA 4.0, https://commons.wikimedia.org/wiki/File:015_Port_Vell_%28Barcelona%29,_World_Trade_Center,_torre_de_Jaume_I_i_cobert_de_l%27America%27s_Cup.jpg
10+
11+
const images = [
12+
"/images/wtc-gemini-2.webp",
13+
"/images/wtc-gemini-1.webp",
14+
"/images/wtc-gemini-3.webp",
15+
];
16+
17+
export const StyledHomeImage = styled.div`
18+
padding: 70px 0 40px;
19+
background-image:
20+
linear-gradient(-45deg, ${Color.LIGHT_BLUE}70, ${Color.MAGENTA}70, ${Color.DARK_BLUE}70, ${Color.GREEN}70),
21+
url(${images[Math.floor(Math.random() * images.length)]});
22+
background-size: 400% 400%, cover;
23+
background-position: 0 50%, center;
24+
background-repeat: no-repeat;
25+
animation: gradient 15s ease infinite;
26+
27+
@keyframes gradient {
28+
0% {
29+
background-position: 0 50%, center;
30+
}
31+
50% {
32+
background-position: 100% 50%, center;
33+
}
34+
100% {
35+
background-position: 0 50%, center;
36+
}
37+
}
38+
`;
39+
export const StyleHomeContainer = styled.div`
40+
position: relative;
41+
width: 100%;
42+
height: 100%;
43+
display: flex;
44+
align-items: center;
45+
justify-content: center;
46+
flex-direction: column;
47+
`;
48+
49+
export const StyledTitleContainer = styled(motion.div)`
50+
background-color: ${(props) => props.color ?? Color.DARK_BLUE}95;
51+
border-radius: 10px;
52+
width: 70%;
53+
margin-bottom: 1rem;
54+
padding: 10px 5px;
55+
56+
@media (max-width: ${BIG_BREAKPOINT}px) {
57+
width: 80%;
58+
}
59+
`;
60+
61+
export const StyledTitle = styled(motion.h1)`
62+
padding: 0.5rem 1rem;
63+
color: ${Color.WHITE};
64+
font-family: "Square 721 Regular", sans-serif;
65+
`;
66+
67+
export const StyledSubtitle = styled(motion.h2)`
68+
color: ${(props: { color: string }) => props.color ?? Color.WHITE};
69+
font-family: "DejaVu Sans ExtraLight", sans-serif;
70+
font-size: 1.25rem;
71+
font-weight: ${(props: { fontWeight: number }) => props.fontWeight ?? 400};
72+
text-shadow: ${(props: { shadow: boolean }) => props.shadow ? '2px 2px 2px rgba(0, 0, 0, 0.5)' : 'none'};
73+
74+
padding: 0.25rem;
75+
76+
a {
77+
text-decoration: none;
78+
color: ${Color.LIGHT_BLUE};
79+
}
80+
`;
81+
82+
export const StyledLessThan = styled(motion.img)`
83+
height: 7rem;
84+
position: absolute;
85+
top: 50%;
86+
left: 5rem;
87+
animation: StyledLessThanAnimation 6s infinite linear;
88+
89+
@keyframes StyledLessThanAnimation {
90+
0% {
91+
transform: rotate(0deg) translate(-20px) rotate(0deg);
92+
}
93+
80% {
94+
transform: rotate(360deg) translate(-20px) rotate(-360deg);
95+
}
96+
90% {
97+
transform: translate(-5px);
98+
}
99+
100% {
100+
transform: translate(-20px);
101+
}
102+
}
103+
`;
104+
105+
export const StyledBottomSlash = styled(motion.div)`
106+
position: absolute;
107+
bottom: 0;
108+
left: 0;
109+
width: 40%;
110+
height: 2rem;
111+
`;
112+
113+
export const StyledTopSlash = styled(motion.div)`
114+
position: absolute;
115+
bottom: 25%;
116+
right: 0;
117+
height: 2rem;
118+
width: 25%;
119+
`;
120+
121+
export const StyledGreenSlash = styled(motion.p)`
122+
font-family: "Square 721 Regular", sans-serif;
123+
color: ${Color.DARK_BLUE};
124+
font-size: 2rem;
125+
overflow-y: hidden;
126+
height: 100%;
127+
`;
128+
129+
export const StyledBlueSlash = styled(motion.p)`
130+
font-family: "Square 721 Regular", sans-serif;
131+
color: ${Color.BLUE};
132+
font-size: 2rem;
133+
overflow-y: hidden;
134+
height: 100%;
135+
`;
136+
export const StyledDevBcnLogo = styled.img`
137+
margin: 20px;
138+
height: 13rem;
139+
aspect-ratio: 800/327;
140+
transition: height 0.2s ease-in-out;
141+
@media (max-width: ${BIGGER_BREAKPOINT}px) {
142+
height: 15rem;
143+
}
144+
@media (max-width: ${BIG_BREAKPOINT}px) {
145+
height: 8rem;
146+
}
147+
`;
148+
export const StyledKcdLogo = styled.img`
149+
margin-top: 4em;
150+
margin-left: 2em;
151+
height: 13rem;
152+
transition: height 0.2s ease-in-out;
153+
aspect-ratio: 800/327;
154+
@media (max-width: ${BIGGER_BREAKPOINT}px) {
155+
height: 12rem;
156+
margin: 0;
157+
}
158+
@media (max-width: ${BIG_BREAKPOINT}px) {
159+
margin-top: 0;
160+
margin-left: 2.5em;
161+
margin-right: 2.5em;
162+
padding: 1em;
163+
height: 10rem;
164+
}
165+
`;
166+
export const StyledPlusSign = styled.span`
167+
color: white;
168+
font-size: 5em;
169+
display: block;
170+
padding-top: 1.5em;
171+
text-shadow: 3px 3px #000;
172+
transition: height 0.2s ease-in-out;
173+
@media (max-width: ${BIGGER_BREAKPOINT}px) {
174+
margin: 0;
175+
padding: 0;
176+
font-size: 3em;
177+
}
178+
@media (max-width: ${BIG_BREAKPOINT}px) {
179+
font-size: 1.5rem;
180+
padding: 0;
181+
margin: 0;
182+
}
183+
`;
184+
export const StyledLogoDiv = styled(motion.div)`
185+
padding-top: 4rem;
186+
padding-bottom: 2rem;
187+
display: flex;
188+
189+
@media (max-width: ${BIGGER_BREAKPOINT}px) {
190+
flex-direction: column;
191+
}
192+
193+
@media (max-width: ${BIG_BREAKPOINT}px) {
194+
flex-direction: column;
195+
}
196+
`;

0 commit comments

Comments
 (0)