blob: f28c853d9f06fb0253e130dd784b159206e5fbb7 [file] [log] [blame]
pineafanb7c79742022-11-06 18:08:36 +00001import React, { useEffect, useState } from "react";
pineafane0283a82022-02-13 10:05:56 +00002import Styles from '../styles/Components/header.module.css';
pineafanb18f0192022-10-27 22:08:36 +01003import NavStyles from '../styles/Components/navbar.module.css';
pineafan876af7d2021-10-14 20:31:21 +01004import Head from 'next/head';
pineafanff3d4522022-05-06 19:51:02 +01005import { useReward } from "react-rewards";
6import ScrollContainer from 'react-indiana-drag-scroll'
TheCodedProf1713ed52023-03-01 15:53:31 -05007import { Paragraph } from "./Texttools.js"
pineafana5ce9102021-09-02 17:21:31 +01008
pineafanb7c79742022-11-06 18:08:36 +00009const positive = [
10 "https://raw.githubusercontent.com/twitter/twemoji/master/assets/svg/1f389.svg",
11 "https://raw.githubusercontent.com/twitter/twemoji/master/assets/svg/1f388.svg",
12 "https://raw.githubusercontent.com/twitter/twemoji/master/assets/svg/1f973.svg",
13];
14
15const negative = [
16 "https://raw.githubusercontent.com/twitter/twemoji/master/assets/svg/1f614.svg",
17 "https://raw.githubusercontent.com/twitter/twemoji/master/assets/svg/1f61e.svg",
18 "https://raw.githubusercontent.com/twitter/twemoji/master/assets/svg/1f613.svg",
19 "https://raw.githubusercontent.com/twitter/twemoji/master/assets/svg/1f625.svg",
20 "https://raw.githubusercontent.com/twitter/twemoji/master/assets/svg/1f623.svg",
21];
22
23function preloadImage (src) {
24 return new Promise((resolve, reject) => {
25 const img = new Image()
26 img.onload = function() {
27 resolve(img)
28 }
29 img.onerror = img.onabort = function() {
30 reject(src)
31 }
32 img.src = src
33 })
34}
35
pineafanff3d4522022-05-06 19:51:02 +010036function Header(props) {
pineafan74f16742022-11-07 21:57:55 +000037 const keys = Object.keys(props.effects ?? {});
pineafanff3d4522022-05-06 19:51:02 +010038
39 const { reward: reward, isAnimating: isAnimating } = useReward('headerConfetti', 'confetti', {
40 elementSize: 10,
41 elementCount: 150,
42 startVelocity: 35,
43 lifetime: 300,
44 decay: 0.95,
45 spread: 170,
46 position: "absolute",
47 colors: ["#F27878", "#E5AB71", "#E5DC71", "#A1CC65", "#68D49E", "#71AFE5", "#6576CC", "#8D58B2", "#BF5E9F"]
48 });
49 const { reward: disappointment, isAnimating: isDisappointmentAnimating } = useReward('disappointmentConfetti', 'confetti', {
50 elementSize: 25,
51 elementCount: 1,
52 startVelocity: 25,
53 lifetime: 350,
54 decay: 0.95,
55 spread: 0,
56 position: "absolute",
57 colors: ["#E5AB71"]
58 });
59
pineafanb7c79742022-11-06 18:08:36 +000060 const all = positive.concat(negative)
61 const [imagesPreloaded, setImagesPreloaded] = useState(false)
PineaFan93f540e2022-12-04 22:05:57 +000062 const [clickTotal, setClickTotal] = useState(0)
pineafanb7c79742022-11-06 18:08:36 +000063 useEffect(() => {
64 let isCancelled = false
65 async function effect() {
66 if (isCancelled) { return }
67 const imagesPromiseList = []
68 for (const i of all) { imagesPromiseList.push(preloadImage(i)) }
69 await Promise.all(imagesPromiseList)
70 if (isCancelled) { return }
71 setImagesPreloaded(true)
72 };
73 effect()
74 return () => { isCancelled = true }
75 }, [all])
76
pineafanb18f0192022-10-27 22:08:36 +010077 function showSubBarWithUrl(url) {
78 const screenWidth = window.innerWidth;
79 let amount = screenWidth - 50;
80 amount = Math.floor(amount / 42) - 1;
81 props.showSubBar(
82 <div className={NavStyles.container}>
83 {
84 Array.from(Array(amount)).map((i, index) => {
85 return (
pineafanb7c79742022-11-06 18:08:36 +000086 <a className={NavStyles.icon} key={index}><img alt="" className={NavStyles.icon} src={
pineafanb18f0192022-10-27 22:08:36 +010087 url[Math.floor(Math.random() * url.length)]
88 } /></a>
89 )
90 })
91 }
92 </div>,
pineafanb7c79742022-11-06 18:08:36 +000093 5, "center"
pineafanb18f0192022-10-27 22:08:36 +010094 );
95 }
96
pineafanff3d4522022-05-06 19:51:02 +010097 function confetti() {
98 if (!isAnimating && !isDisappointmentAnimating && props.index) {
99 setClickTotal(clickTotal + 1);
pineafan9babd752022-10-21 21:47:52 +0100100 if (clickTotal > 0 && Math.floor(Math.random() * 3) === 0) {
pineafanb7c79742022-11-06 18:08:36 +0000101 showSubBarWithUrl(negative);
pineafanff3d4522022-05-06 19:51:02 +0100102 disappointment();
103 } else {
pineafanb7c79742022-11-06 18:08:36 +0000104 showSubBarWithUrl(positive);
pineafanff3d4522022-05-06 19:51:02 +0100105 reward();
106 }
107 }
pineafan9b1b68c2021-11-05 17:47:27 +0000108 }
pineafanf5dd1872023-02-28 17:33:16 +0000109 const season = props.season ?? { season: "normal", filePath: "normal" };
pineafana5ce9102021-09-02 17:21:31 +0100110
pineafanff3d4522022-05-06 19:51:02 +0100111 return (
PineaFana465f352023-02-05 16:45:01 +0000112 <div className={Styles.header} style={{
pineafanff3d4522022-05-06 19:51:02 +0100113 margin: "0",
114 minHeight: props.fullscreen ? "calc(100vh - 42px)" : "calc(100vh - (4 * max(2em, 4vw)) - 1em)",
pineafanf5dd1872023-02-28 17:33:16 +0000115 transform: season.season === "aprilFools" ? "rotate(2.5deg)" : "none",
PineaFana465f352023-02-05 16:45:01 +0000116 transition: "transform 1s cubic-bezier(.47,1.64,.41,.8), background-color 0.3s ease-in-out"
pineafanff3d4522022-05-06 19:51:02 +0100117 }} id={props.id ? props.id : null}>
PineaFana465f352023-02-05 16:45:01 +0000118 <div className={Styles.container} style={{minHeight: props.fullscreen ? "calc(100vh - 42px)" : "calc(100vh - (4 * max(2em, 4vw)) - 1em)"}}>
pineafan74f16742022-11-07 21:57:55 +0000119 {imagesPreloaded}
120 <div className={Styles.backgroundGradient} style={{
121 backgroundImage: `linear-gradient(69.44deg, #${props.gradient[0]} 0%, #${props.gradient[1]} 100%)`,
122 }} />
123 <Head>
124 <title>{props.name}</title>
pineafanff3d4522022-05-06 19:51:02 +0100125
pineafan74f16742022-11-07 21:57:55 +0000126 <meta name="apple-mobile-web-app-capable" content="yes" />
127 <meta name="mobile-web-app-capable" content="yes" />
128 <meta name="viewport" content="width=device-width, minimal-ui" />
pineafanff3d4522022-05-06 19:51:02 +0100129
pineafan74f16742022-11-07 21:57:55 +0000130 <meta name="title" content={props.name} />
131 <meta name="og:title" content={props.name} />
132 <meta name="description" content={props.embedDescription ? props.embedDescription : props.subtext} />
133 <meta name="og:description" content={props.embedDescription ? props.embedDescription : props.subtext} />
134 <meta name="author" content="Clicks" />
135 <meta name="og:author" content="Clicks" />
136 <meta name="image" content={props.embedImage} />
137 <meta name="og:image" content={props.embedImage} />
pineafanff3d4522022-05-06 19:51:02 +0100138
pineafan74f16742022-11-07 21:57:55 +0000139 <meta name="theme-color" content={"#000000"} />
140 <meta name="og-color" content={"#" + props.gradient[1]} />
141 <meta name="msapplication-TileColor" content={"#000000"} />
142 </Head>
143 <img draggable={false} alt="" className={Styles.backgroundImage} src={`https://assets.clicks.codes/${props.wave}.svg`} />
144 <div id="headerConfetti" />
145 <div id="disappointmentConfetti" />
146 <div className={Styles.panel}>
147 <div className={Styles.titleContainer}>
148 <div onClick={confetti}>
149 {
150 props.customImage ?
151 <img height="64px" width="64px" alt={props.name} className={Styles.headerImage} style={{borderRadius: props.roundImage ? "100vw" : "0"}} src={props.customImage} />
152 : <></>
153 }
154 </div>
155 <h1 className={Styles.title}>{props.name}</h1>
pineafana5ce9102021-09-02 17:21:31 +0100156 </div>
pineafan74f16742022-11-07 21:57:55 +0000157 <div className={Styles.textBar}>
pineafanf5dd1872023-02-28 17:33:16 +0000158 {
TheCodedProf1713ed52023-03-01 15:53:31 -0500159 typeof props.subtext === "string" ?
pineafanf5dd1872023-02-28 17:33:16 +0000160 <p className={Styles.subtext + " " + (props.buttons.length ? Styles.subtextExtra : null)}>{props.subtext}</p> :
161 props.subtext
162 }
pineafan74f16742022-11-07 21:57:55 +0000163 </div>
164 <a href="#skipNav" id="skipNav" style={{display: "none"}} />
165 { props.buttons.length ?
166 <div className={Styles.buttonOverflow}>
167 <img className={Styles.indicator + " " + Styles.leftArrow} draggable={false} alt="" src={`https://assets.clicks.codes/web/icons/arrow.svg`}/>
168 <ScrollContainer
169 vertical={false}
170 horizontal={true}
171 hideScrollbars={true}
172 nativeMobileScroll={true}
173 style={{borderRadius: "10px", height: "fit-content"}}
174 >
175 <div className={Styles.buttonLayout}>
176 {
177 props.buttons ? props.buttons.map((button, index) => {
178 return <a
179 key={index}
180 className={Styles.button}
181 style={{ backgroundColor: `#${button.color}`, color: `#${button.buttonText}` }}
182 href={button.link}
183 onClick={
184 button.onClick ? button.onClick : () => { if (button.id) { props.callback(button.id) } }}
185 target={button.target ? "_blank" : null}
186 draggable={false}
187 rel="noreferrer">
188 {button.text}
189 </a>
190 }) : null
191 }
192 </div>
193 </ScrollContainer>
194 <img className={Styles.indicator + " " + Styles.rightArrow} draggable={false} alt="" src={`https://assets.clicks.codes/web/icons/arrow.svg`}/>
195 </div> : <></>
196 }
pineafana5ce9102021-09-02 17:21:31 +0100197 </div>
pineafana5ce9102021-09-02 17:21:31 +0100198 </div>
pineafanff3d4522022-05-06 19:51:02 +0100199 </div>
200 )
pineafana5ce9102021-09-02 17:21:31 +0100201}
202
203export default Header;