aboutsummaryrefslogtreecommitdiffstats
path: root/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'src/components')
-rw-r--r--src/components/Button/index.styled.ts23
-rw-r--r--src/components/Button/index.tsx19
-rw-r--r--src/components/Footer/index.styled.ts11
-rw-r--r--src/components/Footer/index.tsx17
-rw-r--r--src/components/Game/index.styled.ts8
-rw-r--r--src/components/Game/index.tsx65
-rw-r--r--src/components/Guess/index.styled.ts39
-rw-r--r--src/components/Guess/index.tsx32
-rw-r--r--src/components/Header/index.styled.ts49
-rw-r--r--src/components/Header/index.tsx26
-rw-r--r--src/components/InfoPopUp/index.styled.ts70
-rw-r--r--src/components/InfoPopUp/index.tsx36
-rw-r--r--src/components/Player/index.styled.ts48
-rw-r--r--src/components/Player/index.tsx97
-rw-r--r--src/components/Result/index.styled.ts33
-rw-r--r--src/components/Result/index.tsx74
-rw-r--r--src/components/Search/index.styled.ts88
-rw-r--r--src/components/Search/index.tsx67
-rw-r--r--src/components/YouTube/index.tsx24
-rw-r--r--src/components/index.ts10
20 files changed, 836 insertions, 0 deletions
diff --git a/src/components/Button/index.styled.ts b/src/components/Button/index.styled.ts
new file mode 100644
index 0000000..1bb964f
--- /dev/null
+++ b/src/components/Button/index.styled.ts
@@ -0,0 +1,23 @@
+import styled from "styled-components";
+import { theme } from "../../constants";
+
+export const Button = styled.button<{ variant?: keyof typeof theme }>`
+ background-color: ${({ theme, variant }) =>
+ variant ? theme[variant] : theme.background100};
+
+ border-radius: 5px;
+ border: none;
+
+ color: ${({ theme }) => theme.text};
+ font-size: 1rem;
+ font-weight: 800;
+
+ width: max-content;
+ padding: 12.5px 20px;
+
+ &:hover {
+ opacity: 0.8;
+ }
+
+ cursor: pointer;
+`;
diff --git a/src/components/Button/index.tsx b/src/components/Button/index.tsx
new file mode 100644
index 0000000..7e6fa5f
--- /dev/null
+++ b/src/components/Button/index.tsx
@@ -0,0 +1,19 @@
+import React, { CSSProperties } from "react";
+
+import * as Styled from "./index.styled";
+import { theme } from "../../constants";
+
+interface Props {
+ style?: CSSProperties;
+ variant?: keyof typeof theme;
+ children: React.ReactNode;
+ onClick?: () => void;
+}
+
+export function Button({ onClick, style, variant, children }: Props) {
+ return (
+ <Styled.Button onClick={onClick} variant={variant} style={style}>
+ {children}
+ </Styled.Button>
+ );
+}
diff --git a/src/components/Footer/index.styled.ts b/src/components/Footer/index.styled.ts
new file mode 100644
index 0000000..6caa7ff
--- /dev/null
+++ b/src/components/Footer/index.styled.ts
@@ -0,0 +1,11 @@
+import styled from "styled-components";
+
+export const Text = styled.p`
+ text-align: center;
+ color: ${({ theme }) => theme.text};
+ margin-top: 50px;
+`;
+
+export const Link = styled.a`
+ color: ${({ theme }) => theme.text};
+`;
diff --git a/src/components/Footer/index.tsx b/src/components/Footer/index.tsx
new file mode 100644
index 0000000..c5ad421
--- /dev/null
+++ b/src/components/Footer/index.tsx
@@ -0,0 +1,17 @@
+import React from "react";
+import { IoHeart } from "react-icons/io5";
+
+import * as Styled from "./index.styled";
+
+export function Footer() {
+ return (
+ <footer>
+ <Styled.Text>
+ Made with <IoHeart /> by{" "}
+ <Styled.Link href="https://twitter.com/synowski_maciej">
+ Maciej Synowski
+ </Styled.Link>
+ </Styled.Text>
+ </footer>
+ );
+}
diff --git a/src/components/Game/index.styled.ts b/src/components/Game/index.styled.ts
new file mode 100644
index 0000000..7860f98
--- /dev/null
+++ b/src/components/Game/index.styled.ts
@@ -0,0 +1,8 @@
+import styled from "styled-components";
+
+export const Buttons = styled.div`
+ margin-top: 5%;
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+`;
diff --git a/src/components/Game/index.tsx b/src/components/Game/index.tsx
new file mode 100644
index 0000000..84ca282
--- /dev/null
+++ b/src/components/Game/index.tsx
@@ -0,0 +1,65 @@
+import React from "react";
+
+import { GuessType } from "../../types/guess";
+import { Song } from "../../types/song";
+import { playTimes } from "../../constants";
+
+import { Button, Guess, Player, Search, Result } from "../";
+
+import * as Styled from "./index.styled";
+
+interface Props {
+ guesses: GuessType[];
+ todaysSolution: any;
+ currentTry: number;
+ didGuess: boolean;
+ setSelectedSong: React.Dispatch<React.SetStateAction<Song | undefined>>;
+ skip: () => void;
+ guess: () => void;
+}
+
+export function Game({
+ guesses,
+ todaysSolution,
+ currentTry,
+ didGuess,
+ setSelectedSong,
+ skip,
+ guess,
+}: Props) {
+ if (didGuess || currentTry === 6) {
+ return (
+ <Result
+ didGuess={didGuess}
+ currentTry={currentTry}
+ todaysSolution={todaysSolution}
+ guesses={guesses}
+ />
+ );
+ }
+ return (
+ <>
+ {guesses.map((guess: GuessType, index) => (
+ <Guess
+ key={index}
+ guess={guess}
+ isCorrect={guess.isCorrect}
+ active={index === currentTry}
+ />
+ ))}
+ <Player id={todaysSolution.youtubeId} currentTry={currentTry} />
+ <Search currentTry={currentTry} setSelectedSong={setSelectedSong} />
+
+ <Styled.Buttons>
+ <Button onClick={skip}>
+ {currentTry === 5
+ ? "Give Up"
+ : `Skip +${playTimes[currentTry] / 1000}s`}
+ </Button>
+ <Button variant="green" onClick={guess}>
+ Submit
+ </Button>
+ </Styled.Buttons>
+ </>
+ );
+}
diff --git a/src/components/Guess/index.styled.ts b/src/components/Guess/index.styled.ts
new file mode 100644
index 0000000..5118b70
--- /dev/null
+++ b/src/components/Guess/index.styled.ts
@@ -0,0 +1,39 @@
+import styled from "styled-components";
+
+export const Container = styled.div<{
+ active: boolean;
+ isCorrect: boolean | undefined;
+}>`
+ width: 100%;
+ height: 45px;
+
+ margin: 5px auto;
+
+ display: flex;
+ align-items: center;
+
+ border-color: ${({ theme, active, isCorrect }) => {
+ if (active) {
+ return theme.border;
+ } else if (isCorrect === false) {
+ return theme.red;
+ } else {
+ return theme.border100;
+ }
+ }};
+ border-width: 1px;
+ border-radius: 5px;
+ border-style: solid;
+
+ color: ${({ theme }) => theme.text};
+`;
+
+export const Text = styled.p`
+ width: 100%;
+ height: max-content;
+
+ padding: 0px 10px;
+
+ font-size: 1rem;
+ color: ${({ theme }) => theme.text};
+`;
diff --git a/src/components/Guess/index.tsx b/src/components/Guess/index.tsx
new file mode 100644
index 0000000..2afd35c
--- /dev/null
+++ b/src/components/Guess/index.tsx
@@ -0,0 +1,32 @@
+import React from "react";
+
+import { GuessType } from "../../types/guess";
+
+import * as Styled from "./index.styled";
+
+interface Props {
+ guess: GuessType;
+ isCorrect: boolean | undefined;
+ active: boolean;
+}
+
+export function Guess({ guess, isCorrect, active }: Props) {
+ const { song, skipped } = guess;
+ const [text, setText] = React.useState<string>("");
+
+ React.useEffect(() => {
+ if (song) {
+ setText(`${song.artist} - ${song.name}`);
+ } else if (skipped) {
+ setText("Skipped");
+ } else {
+ setText("");
+ }
+ }, [guess]);
+
+ return (
+ <Styled.Container active={active} isCorrect={isCorrect}>
+ <Styled.Text>{text}</Styled.Text>
+ </Styled.Container>
+ );
+}
diff --git a/src/components/Header/index.styled.ts b/src/components/Header/index.styled.ts
new file mode 100644
index 0000000..f06cb72
--- /dev/null
+++ b/src/components/Header/index.styled.ts
@@ -0,0 +1,49 @@
+import styled from "styled-components";
+
+export const Container = styled.header`
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ width: 100%;
+
+ border-color: ${({ theme }) => theme.border};
+ border-bottom-width: 0.5px;
+ border-bottom-style: solid;
+
+ margin-bottom: 15px;
+`;
+
+export const Content = styled.div`
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr;
+ align-items: center;
+ justify-content: space-between;
+
+ width: 40%;
+
+ @media (max-width: 768px) {
+ width: 95%;
+ }
+
+ max-width: 650px;
+
+ svg:hover {
+ cursor: pointer;
+ opacity: 0.8;
+ }
+
+ a {
+ color: ${({ theme }) => theme.text};
+ }
+`;
+
+export const Logo = styled.h1`
+ color: ${({ theme }) => theme.text};
+ font-family: "Roboto Serif", serif;
+ text-transform: uppercase;
+ width: max-content;
+
+ -webkit-touch-callout: none;
+ user-select: none;
+`;
diff --git a/src/components/Header/index.tsx b/src/components/Header/index.tsx
new file mode 100644
index 0000000..0c7f330
--- /dev/null
+++ b/src/components/Header/index.tsx
@@ -0,0 +1,26 @@
+import React from "react";
+import { IoInformationCircleOutline } from "react-icons/io5";
+
+import * as Styled from "./index.styled";
+
+interface Props {
+ openInfoPopUp: () => void;
+}
+
+export function Header({ openInfoPopUp }: Props) {
+ return (
+ <Styled.Container>
+ <Styled.Content>
+ <IoInformationCircleOutline
+ onClick={openInfoPopUp}
+ size={30}
+ width={30}
+ height={30}
+ />
+
+ <Styled.Logo>Heardle Template</Styled.Logo>
+ <a href="#"></a>
+ </Styled.Content>
+ </Styled.Container>
+ );
+}
diff --git a/src/components/InfoPopUp/index.styled.ts b/src/components/InfoPopUp/index.styled.ts
new file mode 100644
index 0000000..6431246
--- /dev/null
+++ b/src/components/InfoPopUp/index.styled.ts
@@ -0,0 +1,70 @@
+import styled from "styled-components";
+
+export const Container = styled.div`
+ position: absolute;
+ top: 0;
+ z-index: 2;
+
+ width: 100%;
+ height: 100%;
+
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ background-color: rgba(0, 0, 0, 0.75);
+`;
+
+export const PopUp = styled.div`
+ width: 90%;
+ max-width: 500px;
+ @media (max-width: 768px) {
+ width: 80%;
+ }
+ padding: 20px;
+
+ background-color: ${({ theme }) => theme.background100};
+
+ border-radius: 10px;
+
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+
+ h1 {
+ margin-bottom: 0;
+ }
+`;
+
+export const Spacer = styled.div`
+ width: 70%;
+ height: 0.2px;
+
+ margin: 20px 0;
+
+ background-color: ${({ theme }) => theme.text};
+ opacity: 0.5;
+`;
+
+export const Section = styled.div`
+ display: flex;
+ gap: 10px;
+ align-items: center;
+ justify-content: space-between;
+
+ a {
+ color: ${({ theme }) => theme.text};
+ }
+`;
+
+export const Contact = styled.p`
+ a {
+ color: ${({ theme }) => theme.text};
+ }
+ margin-top: 5%;
+
+ font-size: 0.9rem;
+ font-weight: bold;
+ opacity: 0.5;
+`;
diff --git a/src/components/InfoPopUp/index.tsx b/src/components/InfoPopUp/index.tsx
new file mode 100644
index 0000000..eb22b19
--- /dev/null
+++ b/src/components/InfoPopUp/index.tsx
@@ -0,0 +1,36 @@
+import React from "react";
+import { IoMusicalNoteOutline, IoHelpCircleOutline } from "react-icons/io5";
+import { Button } from "..";
+
+import * as Styled from "./index.styled";
+
+interface Props {
+ onClose: () => void;
+}
+
+export function InfoPopUp({ onClose }: Props) {
+ return (
+ <Styled.Container>
+ <Styled.PopUp>
+ <h1>HOW TO PLAY</h1>
+ <Styled.Spacer />
+ <Styled.Section>
+ {/* <IoMusicalNoteOutline size={50} /> */}
+ <p>
+ Listen to the intro, then find the correct Joywave song in the list.
+ </p>
+ </Styled.Section>
+ <Styled.Section>
+ {/* <IoHelpCircleOutline size={50} /> */}
+ <p>Skipped or incorrect attempts unlock more of the intro</p>
+ </Styled.Section>
+ <Styled.Section>
+ <p>Answer in as few tries as possible and share your score!</p>
+ </Styled.Section>
+ <Button variant="green" style={{ marginTop: 20 }} onClick={onClose}>
+ Play
+ </Button>
+ </Styled.PopUp>
+ </Styled.Container>
+ );
+}
diff --git a/src/components/Player/index.styled.ts b/src/components/Player/index.styled.ts
new file mode 100644
index 0000000..4200fe1
--- /dev/null
+++ b/src/components/Player/index.styled.ts
@@ -0,0 +1,48 @@
+import styled from "styled-components";
+
+export const ProgressBackground = styled.div`
+ position: relative;
+ z-index: -1;
+
+ width: 100%;
+ height: 20px;
+ background-color: ${({ theme }) => theme.gray};
+ border-radius: 2px;
+
+ margin-top: 5%;
+`;
+
+export const Progress = styled.div<{ value: number }>`
+ width: ${({ value }) => value * 6.25}%;
+ height: 20px;
+
+ align-self: flex-start;
+
+ background-color: ${({ theme }) => theme.green};
+
+ border-radius: 2px;
+
+ transition: width 0.5s;
+`;
+
+export const Separator = styled.div`
+ position: absolute;
+ top: 0;
+
+ width: 0.8px;
+ height: 100%;
+
+ background-color: ${({ theme }) => theme.border100};
+`;
+
+export const TimeStamps = styled.div`
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+
+ width: 100%;
+`;
+
+export const TimeStamp = styled.p`
+ color: ${({ theme }) => theme.text};
+`;
diff --git a/src/components/Player/index.tsx b/src/components/Player/index.tsx
new file mode 100644
index 0000000..82f600e
--- /dev/null
+++ b/src/components/Player/index.tsx
@@ -0,0 +1,97 @@
+import React from "react";
+import YouTube from "react-youtube";
+import { IoPlay } from "react-icons/io5";
+import { event } from "react-ga";
+
+import { playTimes } from "../../constants";
+
+import * as Styled from "./index.styled";
+
+interface Props {
+ id: string;
+ currentTry: number;
+}
+
+export function Player({ id, currentTry }: Props) {
+ const opts = {
+ width: "0",
+ height: "0",
+ };
+
+ // react-youtube doesn't export types for this
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const playerRef = React.useRef<any>(null);
+
+ const currentPlayTime = playTimes[currentTry];
+
+ const [play, setPlay] = React.useState<boolean>(false);
+
+ const [currentTime, setCurrentTime] = React.useState<number>(0);
+
+ const [isReady, setIsReady] = React.useState<boolean>(false);
+
+ React.useEffect(() => {
+ setInterval(() => {
+ playerRef.current?.internalPlayer
+ .getCurrentTime()
+ .then((time: number) => {
+ setCurrentTime(time);
+ });
+ }, 250);
+ }, []);
+
+ React.useEffect(() => {
+ if (play) {
+ if (currentTime * 1000 >= currentPlayTime) {
+ playerRef.current?.internalPlayer.pauseVideo();
+ playerRef.current?.internalPlayer.seekTo(0);
+ setPlay(false);
+ }
+ }
+ }, [play, currentTime]);
+
+ // don't call play video each time currentTime changes
+ const startPlayback = React.useCallback(() => {
+ playerRef.current?.internalPlayer.playVideo();
+ setPlay(true);
+ event({
+ category: "Player",
+ action: "Played song",
+ });
+ }, []);
+
+ const setReady = React.useCallback(() => {
+ setIsReady(true);
+ }, []);
+
+ return (
+ <>
+ <YouTube opts={opts} videoId={id} onReady={setReady} ref={playerRef} />
+ {isReady ? (
+ <>
+ <Styled.ProgressBackground>
+ {currentTime !== 0 && <Styled.Progress value={currentTime} />}
+ {playTimes.map((playTime) => (
+ <Styled.Separator
+ style={{ left: `${(playTime / 16000) * 100}%` }}
+ key={playTime}
+ />
+ ))}
+ </Styled.ProgressBackground>
+ <Styled.TimeStamps>
+ <Styled.TimeStamp>1s</Styled.TimeStamp>
+ <Styled.TimeStamp>16s</Styled.TimeStamp>
+ </Styled.TimeStamps>
+ <IoPlay
+ style={{ cursor: "pointer" }}
+ size={40}
+ color="#fff"
+ onClick={startPlayback}
+ />
+ </>
+ ) : (
+ <p>Loading player...</p>
+ )}
+ </>
+ );
+}
diff --git a/src/components/Result/index.styled.ts b/src/components/Result/index.styled.ts
new file mode 100644
index 0000000..92d51f5
--- /dev/null
+++ b/src/components/Result/index.styled.ts
@@ -0,0 +1,33 @@
+import styled from "styled-components";
+
+export const ResultTitle = styled.h1`
+ @media (max-width: 768px) {
+ text-align: center;
+ width: 100%;
+ }
+`;
+
+export const Tries = styled.h4`
+ @media (max-width: 768px) {
+ text-align: center;
+ width: 100%;
+ }
+
+ margin-top: 0;
+`;
+
+export const SongTitle = styled.h3`
+ @media (max-width: 768px) {
+ text-align: center;
+ width: 100%;
+ }
+
+ margin-top: 0;
+`;
+
+export const TimeToNext = styled.h4`
+ @media (max-width: 768px) {
+ text-align: center;
+ width: 100%;
+ }
+`;
diff --git a/src/components/Result/index.tsx b/src/components/Result/index.tsx
new file mode 100644
index 0000000..40a95fb
--- /dev/null
+++ b/src/components/Result/index.tsx
@@ -0,0 +1,74 @@
+import React from "react";
+
+import { Song } from "../../types/song";
+import { GuessType } from "../../types/guess";
+import { scoreToEmoji } from "../../helpers";
+
+import { Button } from "../Button";
+import { YouTube } from "../YouTube";
+
+import * as Styled from "./index.styled";
+
+interface Props {
+ didGuess: boolean;
+ currentTry: number;
+ todaysSolution: Song;
+ guesses: GuessType[];
+}
+
+export function Result({
+ didGuess,
+ todaysSolution,
+ guesses,
+ currentTry,
+}: Props) {
+ const hoursToNextDay = Math.floor(
+ (new Date(new Date().setHours(24, 0, 0, 0)).getTime() -
+ new Date().getTime()) /
+ 1000 /
+ 60 /
+ 60
+ );
+
+ const textForTry = ["Wow!", "Super!", "Congrats!", "Nice!"];
+
+ if (didGuess) {
+ const copyResult = React.useCallback(() => {
+ navigator.clipboard.writeText(scoreToEmoji(guesses));
+ }, [guesses]);
+
+ return (
+ <>
+ <Styled.ResultTitle>{textForTry[currentTry - 1]}</Styled.ResultTitle>
+ <Styled.SongTitle>
+ Todays song is {todaysSolution.artist} -{" "}
+ {todaysSolution.name}
+ </Styled.SongTitle>
+ <Styled.Tries>
+ You guessed it in {currentTry} {currentTry === 1 ? 'try' : 'tries'}
+ </Styled.Tries>
+ <YouTube id={todaysSolution.youtubeId} />
+ <Button onClick={copyResult} variant="green">
+ Copy results
+ </Button>
+ <Styled.TimeToNext>
+ Remember to come back in {hoursToNextDay}{" "} hours!
+ </Styled.TimeToNext>
+ </>
+ );
+ } else {
+ return (
+ <>
+ <Styled.ResultTitle>Unfortunately, thats wrong</Styled.ResultTitle>
+ <Styled.SongTitle>
+ Todays song is {todaysSolution.artist} -{" "}
+ {todaysSolution.name}
+ </Styled.SongTitle>
+ <YouTube id={todaysSolution.youtubeId} />
+ <Styled.TimeToNext>
+ Try again in {hoursToNextDay}{" "} hours
+ </Styled.TimeToNext>
+ </>
+ );
+ }
+}
diff --git a/src/components/Search/index.styled.ts b/src/components/Search/index.styled.ts
new file mode 100644
index 0000000..c1344d5
--- /dev/null
+++ b/src/components/Search/index.styled.ts
@@ -0,0 +1,88 @@
+import styled from "styled-components";
+
+export const Container = styled.div`
+ position: relative;
+
+ width: 100%;
+
+ margin-top: 5%;
+`;
+
+export const SearchContainer = styled.div`
+ display: flex;
+ align-items: center;
+
+ width: 100%;
+ height: 50px;
+
+ border-color: ${({ theme }) => theme.border};
+ border-width: 1px;
+ border-radius: 5px;
+ border-style: solid;
+
+ color: ${({ theme }) => theme.text};
+`;
+
+export const SearchPadding = styled.div`
+ display: flex;
+ align-items: center;
+
+ width: 100%;
+
+ padding: 0 15px;
+`;
+
+export const Input = styled.input`
+ width: 100%;
+ height: 100%;
+ margin: 0 10px;
+
+ background-color: transparent;
+ border: none;
+ outline: none !important;
+
+ color: ${({ theme }) => theme.text};
+ font-size: 1rem;
+`;
+
+export const ResultsContainer = styled.div`
+ position: absolute;
+ bottom: 50px;
+ z-index: 1;
+
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-end;
+
+ width: 100%;
+
+ overflow-y: scroll;
+`;
+
+export const Result = styled.div`
+ padding: 1px 15px;
+
+ background-color: ${({ theme }) => theme.background100};
+
+ border-color: ${({ theme }) => theme.border};
+ border-width: 1px;
+ border-radius: 5px;
+ border-style: solid;
+
+ color: ${({ theme }) => theme.text};
+
+ cursor: pointer;
+`;
+
+export const ResultText = styled.p`
+ width: 100%;
+
+ color: ${({ theme }) => theme.text};
+ font-size: 0.9rem;
+
+ user-select: none;
+
+ &:hover {
+ opacity: 0.8;
+ }
+`;
diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx
new file mode 100644
index 0000000..16f5c9e
--- /dev/null
+++ b/src/components/Search/index.tsx
@@ -0,0 +1,67 @@
+import React from "react";
+import { event } from "react-ga";
+import { IoSearch } from "react-icons/io5";
+import { searchSong } from "../../helpers";
+import { Song } from "../../types/song";
+
+import * as Styled from "./index.styled";
+
+interface Props {
+ currentTry: number;
+ setSelectedSong: React.Dispatch<React.SetStateAction<Song | undefined>>;
+}
+
+export function Search({ currentTry, setSelectedSong }: Props) {
+ const [value, setValue] = React.useState<string>("");
+ const [results, setResults] = React.useState<Song[]>([]);
+
+ React.useEffect(() => {
+ if (value) {
+ setResults(searchSong(value));
+ } else if (value === "") {
+ setResults([]);
+ }
+ }, [value]);
+
+ // clear value on selection
+ React.useEffect(() => {
+ setValue("");
+ }, [currentTry]);
+
+ return (
+ <Styled.Container>
+ <Styled.ResultsContainer>
+ {results.map((song) => (
+ <Styled.Result
+ key={song.youtubeId}
+ onClick={() => {
+ setSelectedSong(song);
+ setValue(`${song.artist} - ${song.name}`);
+ setResults([]);
+
+ event({
+ category: "Player",
+ action: "Chose song",
+ label: `${song.artist} - ${song.name}`,
+ });
+ }}
+ >
+ <Styled.ResultText>
+ {song.artist} - {song.name}
+ </Styled.ResultText>
+ </Styled.Result>
+ ))}
+ </Styled.ResultsContainer>
+ <Styled.SearchContainer>
+ <Styled.SearchPadding>
+ <IoSearch size={20} />
+ <Styled.Input
+ onChange={(e) => setValue(e.currentTarget.value)}
+ placeholder="Search"
+ value={value}
+ />
+ </Styled.SearchPadding>
+ </Styled.SearchContainer>
+ </Styled.Container>
+ );
+}
diff --git a/src/components/YouTube/index.tsx b/src/components/YouTube/index.tsx
new file mode 100644
index 0000000..13ffeaa
--- /dev/null
+++ b/src/components/YouTube/index.tsx
@@ -0,0 +1,24 @@
+import React from "react";
+import { default as YouTubePlayer } from "react-youtube";
+
+interface Props {
+ id: string;
+}
+
+export function YouTube({ id }: Props) {
+ return (
+ <div style={{ margin: "5% 0" }}>
+ <YouTubePlayer
+ videoId={id}
+ opts={{
+ width: "336",
+ height: "189",
+ playerVars: {
+ autoplay: 1,
+ playsinline: 1,
+ },
+ }}
+ />
+ </div>
+ );
+}
diff --git a/src/components/index.ts b/src/components/index.ts
new file mode 100644
index 0000000..75672f3
--- /dev/null
+++ b/src/components/index.ts
@@ -0,0 +1,10 @@
+export { Button } from "./Button";
+export { Footer } from "./Footer";
+export { Game } from "./Game";
+export { Guess } from "./Guess";
+export { Header } from "./Header";
+export { InfoPopUp } from "./InfoPopUp";
+export { Player } from "./Player";
+export { Result } from "./Result";
+export { Search } from "./Search";
+export { YouTube } from "./YouTube";
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage