Skip to content

Commit 1b5e49f

Browse files
Merge pull request #229 from uidotdev/lf/reactgg-launch
Reactgg launch
2 parents c4ec69a + 329b094 commit 1b5e49f

File tree

5 files changed

+309
-3
lines changed

5 files changed

+309
-3
lines changed
1.49 KB
Loading
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
---
2+
import Button from "../components/Button.astro";
3+
---
4+
5+
<!-- Show this one on Day 2 of launch week --><!-- <section class="banner week">
6+
<h3><img src="/img/react-gg-logo-sticker.svg" width="358" height="86" alt="react.gg" /> Launch Week Sale</h3>
7+
<div class="countdown">
8+
<div class="number day">
9+
<span id="days" class="time">5</span>
10+
<span class="unit">days</span>
11+
</div>
12+
<div class="number hour">
13+
<span id="hours" class="time">22</span>
14+
<span class="unit">hours</span>
15+
</div>
16+
<div class="number minute">
17+
<span id="minutes" class="time">47</span>
18+
<span class="unit">minutes</span>
19+
</div>
20+
<div class="number second">
21+
<span id="seconds" class="time">12</span>
22+
<span class="unit">seconds</span>
23+
</div>
24+
</div>
25+
<p>
26+
Get up to <strong>25% off</strong><sup>1</sup> if you buy before this giant clock
27+
goes to zero.
28+
</p>
29+
<Button
30+
type="link"
31+
href="https://react.gg/#register"
32+
color="yellow"
33+
size="large"
34+
text="Get the course now"
35+
/>
36+
<ol class="footnotes">
37+
<li>Literally the cheapest this course will ever be</li>
38+
</ol>
39+
</section> --><!-- Show this one on Day 1 of launch week -->
40+
<section class="banner day-one">
41+
<h3>
42+
<img
43+
src="/img/react-gg-logo-sticker.svg"
44+
width="358"
45+
height="86"
46+
alt="react.gg"
47+
/> Launch Day Sale
48+
</h3>
49+
<div class="countdown">
50+
<div class="number day">
51+
<span id="days" class="time">--</span>
52+
<span id="days-label" class="unit">day(s)</span>
53+
</div>
54+
<div class="number hour">
55+
<span id="hours" class="time">--</span>
56+
<span id="hours-label" class="unit">hour(s)</span>
57+
</div>
58+
<div class="number minute">
59+
<span id="minutes" class="time">--</span>
60+
<span id="minutes-label" class="unit">minute(s)</span>
61+
</div>
62+
<div class="number second">
63+
<span id="seconds" class="time">--</span>
64+
<span id="seconds-label" class="unit">second(s)</span>
65+
</div>
66+
</div>
67+
<p>
68+
Want to learn how to build useHooks yourself? Get 25% off our brand new
69+
React course during our launch sale.
70+
</p>
71+
<Button
72+
type="link"
73+
href="https://react.gg/"
74+
color="yellow"
75+
size="large"
76+
text="Check it out"
77+
/>
78+
</section>
79+
80+
<style>
81+
.banner {
82+
margin-bottom: var(--body-padding);
83+
padding: var(--body-border);
84+
display: grid;
85+
gap: 1rem;
86+
background-color: var(--brand-blue);
87+
border-radius: 0.5rem;
88+
color: var(--charcoal);
89+
container-type: inline-size;
90+
}
91+
92+
.banner h3 {
93+
padding: 0.3em;
94+
display: flex;
95+
justify-content: center;
96+
align-items: center;
97+
gap: 0.5rem;
98+
background-color: var(--brand-pink);
99+
border: var(--border-dark);
100+
border-radius: 0.3rem;
101+
box-shadow: 2px 2px 0 var(--charcoal);
102+
text-align: center;
103+
font-size: clamp(1rem, 2.2vw, 1.5rem);
104+
}
105+
106+
.banner h3 img {
107+
width: auto;
108+
max-height: 30px;
109+
}
110+
111+
.banner p {
112+
text-align: center;
113+
max-width: 45ch;
114+
justify-self: center;
115+
margin-top: 8px;
116+
}
117+
118+
.info-main {
119+
justify-self: center;
120+
}
121+
122+
p {
123+
line-height: 1.3;
124+
font-size: 20px;
125+
}
126+
127+
p strong {
128+
margin: 0 0.1em;
129+
display: inline-block;
130+
font-size: 115%;
131+
}
132+
133+
p sup {
134+
margin-left: 0.2em;
135+
display: inline-block;
136+
font-weight: 400;
137+
font-size: 60%;
138+
transform: translateY(-0.2em);
139+
}
140+
141+
p a {
142+
color: var(--white);
143+
}
144+
145+
.button {
146+
margin: 1rem 0;
147+
justify-self: center;
148+
}
149+
150+
.day-one .button.large {
151+
position: relative;
152+
}
153+
154+
.footnotes {
155+
display: flex;
156+
justify-content: center;
157+
flex-wrap: wrap;
158+
gap: 0 0.5em;
159+
}
160+
161+
.footnotes li {
162+
list-style-type: number;
163+
list-style-position: inside;
164+
font-size: clamp(0.8rem, 1.4vw, 0.9rem);
165+
}
166+
167+
.countdown {
168+
padding: 0.6em;
169+
display: flex;
170+
gap: 0.6rem;
171+
background-color: var(--brand-charcoal);
172+
color: var(--brand-beige);
173+
border-radius: 0.4rem;
174+
text-align: center;
175+
}
176+
177+
.number {
178+
padding: 1rem 0.2rem;
179+
flex: 1;
180+
display: grid;
181+
gap: 0.1em 0.3em;
182+
line-height: 1;
183+
border: var(--border-light);
184+
border-color: var(--purple);
185+
border-radius: 0.2rem;
186+
color: var(--brand-beige);
187+
}
188+
189+
.time {
190+
display: flex;
191+
place-content: center;
192+
font-weight: bold;
193+
font-family: Fira Code;
194+
font-size: 2.3rem;
195+
font-size: clamp(1rem, 4vw, 2.3rem);
196+
visibility: hidden;
197+
}
198+
199+
.unit {
200+
font-size: 0.6em;
201+
line-height: 1;
202+
}
203+
</style>
204+
205+
<script>
206+
const countdownInterval = setInterval(updateCountdown, 1000);
207+
208+
// updateCountdown();
209+
showCountDown();
210+
211+
function updateCountdown() {
212+
const { days, hours, minutes, seconds, hasExpired } = timeUntilTargetPST(
213+
2023,
214+
9,
215+
7
216+
);
217+
218+
if (hasExpired) {
219+
// Countdown has ended, clear the interval and set all values to 0
220+
clearInterval(countdownInterval);
221+
// document.getElementById("days").textContent = "00";
222+
document.getElementById("hours").textContent = "00";
223+
document.getElementById("minutes").textContent = "00";
224+
document.getElementById("seconds").textContent = "00";
225+
return;
226+
}
227+
228+
// Uncomment when we move to the other banner
229+
document.getElementById("days").textContent = days.value;
230+
document.getElementById("days-label").textContent = days.label;
231+
document.getElementById("hours").textContent = hours.value;
232+
document.getElementById("hours-label").textContent = hours.label;
233+
document.getElementById("minutes").textContent = minutes.value;
234+
document.getElementById("minutes-label").textContent = minutes.label;
235+
document.getElementById("seconds").textContent = seconds.value;
236+
document.getElementById("seconds-label").textContent = seconds.label;
237+
}
238+
239+
function showCountDown() {
240+
const elements = document.querySelectorAll<HTMLElement>(".time");
241+
elements.forEach((element) => {
242+
element.style.visibility = "visible";
243+
});
244+
}
245+
246+
function timeUntilTargetPST(
247+
targetYear: number,
248+
targetMonth: number,
249+
targetDay: number
250+
) {
251+
const now = new Date();
252+
253+
// Extract the UTC year, month, day, hour, minute, and second
254+
const year = now.getUTCFullYear();
255+
const month = now.getUTCMonth();
256+
const date = now.getUTCDate();
257+
const hour = now.getUTCHours();
258+
const minute = now.getUTCMinutes();
259+
const second = now.getUTCSeconds();
260+
261+
// Create a current UTC date object
262+
const currentUTC = new Date(
263+
Date.UTC(year, month, date, hour, minute, second)
264+
) as any;
265+
266+
// Construct the target UTC date at 8 AM UTC (midnight PST)
267+
const targetUTC = new Date(
268+
Date.UTC(targetYear, targetMonth - 1, targetDay, 8, 0, 0)
269+
) as any;
270+
271+
let delta = (targetUTC - currentUTC) / 1000;
272+
273+
const days = Math.floor(delta / 86400);
274+
delta -= days * 86400;
275+
276+
const hours = Math.floor(delta / 3600) % 24;
277+
delta -= hours * 3600;
278+
279+
const minutes = Math.floor(delta / 60) % 60;
280+
delta -= minutes * 60;
281+
282+
const seconds = delta % 60;
283+
284+
return {
285+
days: {
286+
value: String(days).padStart(2, "0"),
287+
label: days === 1 ? "day" : "days",
288+
},
289+
hours: {
290+
value: String(hours).padStart(2, "0"),
291+
label: hours === 1 ? "hour" : "hours",
292+
},
293+
minutes: {
294+
value: String(minutes).padStart(2, "0"),
295+
label: minutes === 1 ? "minute" : "minutes",
296+
},
297+
seconds: {
298+
value: String(seconds).padStart(2, "0"),
299+
label: seconds === 1 ? "second" : "seconds",
300+
},
301+
hasExpired: targetUTC < currentUTC,
302+
};
303+
}
304+
</script>

usehooks.com/src/pages/index.astro

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
import { getCollection } from "astro:content";
33
import Layout from "../layouts/Layout.astro";
4+
import CountdownBanner from "../components/CountdownBanner.astro";
45
import NavMain from "../sections/NavMain.astro";
56
import HomeHero from "../sections/HomeHero.astro";
67
import HooksList from "../components/search/HooksList";
@@ -13,6 +14,7 @@ const hooks = await getCollection("hooks");
1314
title="useHooks – The React Hooks Library"
1415
description="A collection of modern, server-safe React hooks – from the ui.dev team"
1516
>
17+
<CountdownBanner />
1618
<NavMain />
1719
<HomeHero />
1820
<HooksList client:load hooks={hooks} />

usehooks.com/src/styles/globals.css

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ video {
152152
--brand-pink: #f38ba3;
153153
--brand-green: #0ba95b;
154154
--brand-purple: #7b5ea7;
155-
--brand-biege: #f9f4da;
155+
--brand-beige: #f9f4da;
156156
--brand-blue: #12b5e5;
157157
--brand-orange: #fc7428;
158158
--brand-red: #ed203d;
@@ -161,7 +161,7 @@ video {
161161
--magesticPurple: #9d7dce;
162162

163163
--red: var(--brand-red);
164-
--white: var(--brand-biege);
164+
--white: var(--brand-beige);
165165
--purple: var(--brand-purple);
166166
--black: var(--brand-coal);
167167
--blue: var(--brand-blue);
@@ -248,7 +248,6 @@ h2 {
248248
font-size: var(--font-md);
249249
}
250250

251-
252251
small {
253252
font-size: var(--font-sm);
254253
}

0 commit comments

Comments
 (0)