-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature - added countdown section #160
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
.paraboloid { | ||
position: relative; | ||
width: 100%; | ||
} | ||
|
||
.countdownWrapper { | ||
display: flex; | ||
align-items: center; | ||
flex-direction: column; | ||
position: relative; | ||
} | ||
|
||
.descriptiveText { | ||
top: 45px; | ||
left: 20px; | ||
position: absolute; | ||
min-width: 150px; | ||
transform: translateX(-50%); | ||
text-align: center; | ||
} | ||
|
||
.countdownMaterial { | ||
// margin-top: 10%; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Chore: remove commented styling |
||
position: absolute; | ||
top: 0px; | ||
left: 0px; | ||
width: 100%; | ||
height: 100%; | ||
display: flex; | ||
flex-direction: column; | ||
align-items: center; | ||
justify-content: center; | ||
} | ||
|
||
@media only screen and (max-width: 400px) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Chore (repeating): rather than writing out all these media queries, we can use Bootstrap's mixins to handle that for us (refer to other stylesheets using bootstrap.media-breakpoint-up) (thanks Taesung) |
||
.clockPos { | ||
margin-top: 45%; | ||
} | ||
.preCountdown { | ||
margin-top: 50%; | ||
} | ||
.endText { | ||
margin-top: 50%; | ||
} | ||
} | ||
|
||
@media only screen and (min-width: 401px) and (max-width: 600px) { | ||
.clockPos { | ||
margin-top: 30%; | ||
} | ||
.preCountdown { | ||
margin-top: 40%; | ||
} | ||
.endText { | ||
margin-top: 40%; | ||
} | ||
} | ||
|
||
@media only screen and (min-width: 601px) and (max-width: 1000px) { | ||
.clockPos { | ||
margin-top: 20%; | ||
} | ||
.preCountdown { | ||
margin-top: 20%; | ||
} | ||
.endText { | ||
margin-top: 20%; | ||
} | ||
} | ||
|
||
@media only screen and (min-width: 1001px) { | ||
.preCountdown { | ||
margin-top: 15%; | ||
} | ||
.endText { | ||
margin-top: 10%; | ||
} | ||
} | ||
|
||
.clockPos { | ||
width: 100%; | ||
display: flex; | ||
justify-content: center; | ||
} | ||
|
||
.boat { | ||
position: absolute; | ||
transform: translate(-50%, 40%); | ||
} | ||
|
||
.outerCircle { | ||
background-color: #ffffff; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Chore (repeating): The color here can be replaced with |
||
// border-color: #1a1840; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Chore: remove commented styling |
||
border: 5px solid #1a1840; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Chore (repeating): The color here can be replaced with |
||
width: 50px; | ||
height: 50px; | ||
border-radius: 50%; | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
z-index: 1; | ||
bottom: 0; | ||
position: absolute; | ||
} | ||
|
||
.innerCircle { | ||
background-color: #bd5a5a; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Chore (repeating): this red is also a theme color |
||
width: 30px; | ||
height: 30px; | ||
border-radius: 50%; | ||
} | ||
|
||
.descriptiveTextTop { | ||
position: absolute; | ||
top: -70px; | ||
width: 150px; | ||
text-align: center; | ||
p { | ||
margin: 0; | ||
padding: 0; | ||
} | ||
} | ||
|
||
.progressContainer { | ||
height: 200px; | ||
width: 60%; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,219 @@ | ||
"use client"; | ||
|
||
import bg_map from "@/assets/images/maps/countdown.svg"; | ||
import Image from "next/image"; | ||
import useWindow from "./useWindow"; | ||
|
||
import styles from "./Countdown.module.scss"; | ||
import CountdownClock from "./CountdownClock"; | ||
import { useEffect, useState } from "react"; | ||
|
||
import boat from "@/assets/icons/boat.png"; | ||
|
||
interface CountdownProps { | ||
schedule: { | ||
title: string; | ||
location?: string | undefined; | ||
virtual?: string | undefined; | ||
startTime: Date; | ||
endTime: Date; | ||
organization?: string | undefined; | ||
hosts?: string[] | undefined; | ||
description: any; | ||
}[]; | ||
} | ||
|
||
const Countdown: React.FC<CountdownProps> = ({ schedule }) => { | ||
const hackStartTime = new Date(2024, 10, 1, 14, 0, 0); // TBD, zothacks start time | ||
const hackEndTime = new Date(2024, 10, 2, 18, 0, 0); // TBD, zothacks end time | ||
|
||
const [curTime, setCurTime] = useState(new Date()); | ||
|
||
useEffect(() => { | ||
const i = setInterval(() => { | ||
setCurTime(new Date()); | ||
}, 1000); | ||
|
||
return () => clearInterval(i); | ||
}); | ||
|
||
const ended = schedule.filter((el) => el.endTime > curTime); | ||
|
||
const before = | ||
ended.length > 0 | ||
? ended[0] | ||
: { | ||
title: "That's a wrap~", | ||
location: "", | ||
startTime: new Date(0), | ||
endTime: new Date(0), | ||
}; | ||
|
||
const after = | ||
ended.length > 1 | ||
? ended[1] | ||
: { | ||
title: "That's a wrap~", | ||
location: "", | ||
startTime: new Date(0), | ||
endTime: new Date(0), | ||
}; | ||
|
||
const percentageCrossed = | ||
before.endTime.getTime() > 0 | ||
? (before.endTime.getTime() - curTime.getTime()) / | ||
(before.endTime.getTime() - before.startTime.getTime()) | ||
: 100; | ||
|
||
const [w, h] = useWindow(); | ||
|
||
const totalLines = Math.floor(w / 66) > 7 ? Math.floor(w / 66) : 7; | ||
|
||
const totals = Array(totalLines + 1).fill(0); | ||
|
||
function returnPosition(num: number) { | ||
// this is the parabola -(0.2x - 1.5)^2 + 2.25 | ||
let step = (20 / totalLines) * num; | ||
let prop_y = (-((0.15 * step - 1.5) * (0.15 * step - 1.5)) + 2.25) / 2.25; | ||
return [`${step * 5}%`, `${prop_y * 100}%`]; | ||
} | ||
|
||
function returnRotation(num: number) { | ||
// this is the derivative of the aforementioned parabola turned into degrees of rotation | ||
let step = (15 / totalLines) * num; | ||
return Math.atan(-(2 * step - 15) / 25); | ||
} | ||
|
||
if (curTime > hackEndTime) { | ||
return ( | ||
<div className={styles.countdownWrapper}> | ||
<Image src={bg_map} alt="bg_map" /> | ||
<div className={styles.countdownMaterial}> | ||
<h1 className={styles.endText}>Hacking has ended!</h1> | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
console.log(percentageCrossed); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Chore: Remove console logging |
||
|
||
return ( | ||
<div className={styles.countdownWrapper}> | ||
<Image src={bg_map} alt="bg_map" /> | ||
{w > 0 && ( | ||
<div className={styles.countdownMaterial}> | ||
{curTime >= hackStartTime ? ( | ||
<div className={styles.progressContainer}> | ||
<div style={{ height: `100px` }} className={styles.paraboloid}> | ||
{totals.map((_, i) => ( | ||
<div | ||
key={`line-segment-${i}`} | ||
style={{ | ||
left: returnPosition(i)[0], | ||
bottom: returnPosition(i)[1], | ||
position: "absolute", | ||
backgroundColor: `${i / totals.length > percentageCrossed ? "#DB9F42" : "#78cae3"}`, | ||
width: "18px", | ||
height: "5px", | ||
borderRadius: "6px", | ||
transform: `rotate(${-((returnRotation(i) * 180) / Math.PI)}deg)`, | ||
}} | ||
></div> | ||
))} | ||
<div | ||
className={styles.outerCircle} | ||
style={{ | ||
bottom: "-20px", | ||
left: "-20px", | ||
}} | ||
> | ||
<div className={styles.descriptiveTextTop}> | ||
{before.location && w <= 800 ? ( | ||
<p>{before.location}</p> | ||
) : null} | ||
{before.startTime.getTime() && w <= 800 ? ( | ||
<p>{`${before.startTime.getHours() % 12}${before.startTime.getHours() == 11 ? " am" : ""}-${before.endTime.getHours() % 12} ${before.endTime.getHours() < 12 ? "am" : "pm"}`}</p> | ||
) : null} | ||
</div> | ||
<div className={styles.innerCircle}></div> | ||
<div className={styles.descriptiveText}> | ||
<h5>{before.title}</h5> | ||
{before.location && w > 800 ? ( | ||
<p>{before.location}</p> | ||
) : null} | ||
{before.startTime.getTime() && w > 800 ? ( | ||
<p>{`${before.startTime.getHours() % 12}${before.startTime.getHours() == 11 ? " am" : ""}-${before.endTime.getHours() % 12} ${before.endTime.getHours() < 12 ? "am" : "pm"}`}</p> | ||
) : null} | ||
</div> | ||
</div> | ||
|
||
<div | ||
className={styles.outerCircle} | ||
style={{ | ||
bottom: "-20px", | ||
right: "-38px", | ||
}} | ||
> | ||
<div className={styles.descriptiveTextTop}> | ||
{after.location && w <= 800 ? ( | ||
<p>{after.location}</p> | ||
) : null} | ||
{after.startTime.getTime() && w <= 800 ? ( | ||
<p>{`${after.startTime.getHours() % 12}${after.startTime.getHours() == 11 ? " am" : ""}-${after.endTime.getHours() % 12} ${after.endTime.getHours() < 12 ? "am" : "pm"}`}</p> | ||
) : null} | ||
</div> | ||
<div className={styles.innerCircle}></div> | ||
<div className={styles.descriptiveText}> | ||
<h5>{after.title}</h5> | ||
{after.location && w > 800 ? <p>{after.location}</p> : null} | ||
{after.startTime.getTime() && w > 800 ? ( | ||
<p>{`${after.startTime.getHours() % 12}${after.startTime.getHours() == 11 ? " am" : ""}-${after.endTime.getHours() % 12} ${after.endTime.getHours() < 12 ? "am" : "pm"}`}</p> | ||
) : null} | ||
</div> | ||
</div> | ||
<div | ||
className={styles.boat} | ||
style={{ | ||
left: returnPosition( | ||
(percentageCrossed * totals.length) / 100, | ||
)[0], | ||
bottom: returnPosition( | ||
(percentageCrossed * totals.length) / 100, | ||
)[1], | ||
}} | ||
> | ||
<Image | ||
src={boat} | ||
alt="boat" | ||
style={{ | ||
transform: `rotate(${percentageCrossed < 30 ? -((returnRotation((Math.max(percentageCrossed, 1.6 * percentageCrossed ** 0.7 + 4) * totals.length) / 100) * 180) / Math.PI) : -((returnRotation((percentageCrossed * totals.length) / 100) * 180) / Math.PI)}deg)`, | ||
}} | ||
/> | ||
</div> | ||
</div> | ||
<div className={styles.clockPos}> | ||
<CountdownClock | ||
countdownTo={ | ||
curTime > hackStartTime ? hackEndTime : hackStartTime | ||
} | ||
isHackingStarted={curTime >= hackStartTime} | ||
/> | ||
</div> | ||
</div> | ||
) : ( | ||
<div className={styles.preCountdown}> | ||
<CountdownClock | ||
countdownTo={ | ||
curTime > hackStartTime ? hackEndTime : hackStartTime | ||
} | ||
isHackingStarted={curTime >= hackStartTime} | ||
/> | ||
</div> | ||
)} | ||
</div> | ||
)} | ||
</div> | ||
); | ||
}; | ||
|
||
export default Countdown; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: Because this class is used on a div, maybe change the name to
description-container
or something.Also, I don't know if camel case class names is standard or having dashes in between words is standard or if there even is a standard.