first working version

This commit is contained in:
Thomas Ruoff
2020-11-28 00:28:38 +01:00
parent 8762aef219
commit a17153759e
22 changed files with 1592 additions and 214 deletions

42
components/calendar.js Normal file
View File

@@ -0,0 +1,42 @@
import React, { useContext } from "react";
import AppContext from "../context/app";
const Calendar = () => {
const { loading, songs, openDoor } = useContext(AppContext);
if (loading || !songs) {
return null;
}
return (
<div>
<ul className="cal">
{songs.map((song, index) => {
const classes = ["calcard", song.locked && "calcard__locked"]
.filter(Boolean)
.join(" ");
return (
<li
className={classes}
data-id={index}
key={song.id}
onClick={() => !song.locked && openDoor(index)}
title={
song.locked &&
`Es ist noch nicht der ${new Date(
song.lockedUntil
).toLocaleDateString()}! Geduld, nur Gedult!` || index + 1
}
>
<span className="cardnumber">{index + 1}</span>
</li>
);
})}
</ul>
</div >
);
};
export default Calendar;

36
components/controls.js vendored Normal file
View File

@@ -0,0 +1,36 @@
import React, { useEffect, useState, Fragment } from "react";
export const ENDED = 0;
export const PLAYING = 1;
export const PAUSED = 2;
const Controls = ({ playerState, onPause, onPlay, onRestart }) => {
return (
<Fragment>
<div className="player-controls">
{playerState === PLAYING && (
<a onClick={onPause} title="Pause">
</a>
)}
{playerState === PAUSED && (
<a onClick={onPlay} title="Play">
</a>
)}
{[PLAYING, PAUSED].includes(playerState) && (
<a onClick={onRestart} title="Von Vorne">
</a>
)}
{playerState === ENDED && (
<a onClick={onPlay} title="Play">
</a>
)}
</div>
</Fragment>
);
};
export default Controls;

27
components/header.js Normal file
View File

@@ -0,0 +1,27 @@
import React, { useEffect, useState } from "react";
const Header = () => {
const [gifUrl, setGifUrl] = useState(null);
useEffect(() => {
async function getGif() {
const response = await fetch(
"//api.giphy.com/v1/gifs/random?tag=christmas&api_key=3ziHSa4ptYJdv2dOuawgzpBhhiW09Ss1"
);
const { data } = await response.json();
setGifUrl(data.image_mp4_url);
}
getGif();
}, []);
return (
<div className="header">
<h1>Bello's Adventskalender 2020</h1>
{gifUrl && (
<video className="yay-gif-video" src={gifUrl} autoPlay loop muted />
)}
</div>
);
};
export default Header;

28
components/nav.js Normal file
View File

@@ -0,0 +1,28 @@
import React from "react";
const links = [
{ href: "https://youtube.com", label: "Youtube" },
{ href: "https://www.discogs.com/", label: "Discog" },
{ href: "https://findmusicbylyrics.com/", label: "Find music by Lyrics" },
{ href: "https://musicbrainz.org/", label: "MusicBrainz" }
].map(link => {
link.key = `nav-link-${link.href}-${link.label}`;
return link;
});
const Nav = () => (
<nav className="ad-nav">
<ul>
<li>Für die Recherche:</li>
{links.map(({ key, href, label }) => (
<li key={key}>
<a href={href} target="_blank">
{label}
</a>
</li>
))}
</ul>
</nav>
);
export default Nav;

64
components/player.js Normal file
View File

@@ -0,0 +1,64 @@
import React, { useEffect, useState, Fragment, useContext } from "react";
import youtubePlayer from "youtube-player";
import AppContext from "../context/app";
import Controls, { ENDED, PLAYING, PAUSED } from "./controls";
let player;
const Player = ({ hidden }) => {
const [playerState, setPlayerState] = useState(-1);
const { openSong } = useContext(AppContext);
const onPause = () => player && player.pauseVideo();
const onPlay = () => player && player.playVideo();
const onRestart = () => {
player && player.seekTo(openSong.startSeconds || 0);
player && [PAUSED, ENDED].includes(playerState) && player.playVideo();
};
useEffect(onRestart, [!hidden]);
useEffect(() => {
const setState = ({ data }) => setPlayerState(data);
player = youtubePlayer("player", {
height: "390",
width: "640"
});
player.on("stateChange", setState);
player.loadVideoById({
videoId: openSong.id,
startSeconds: openSong.startSeconds,
endSeconds: openSong.endSeconds
});
return () => {
player = null;
setPlayerState(null);
};
}, []);
return (
<Fragment>
<div className={hidden ? "hidden" : undefined}>
<div id="player" />
</div>
{hidden && playerState === -1 && <span>🎶 Titel laden...</span>}
{hidden && playerState > -1 && (
<Fragment>
<span>🎶 Titel spielt</span>
<Controls
playerState={playerState}
onPause={onPause}
onPlay={onPlay}
onRestart={onRestart}
/>
</Fragment>
)}
</Fragment>
);
};
export default Player;

View File

@@ -0,0 +1,57 @@
import React, { useState, useContext } from "react";
import AppContext from "../context/app";
import Player from "./player";
const ShowDoorDialog = () => {
const { loading, openDoor, openSong, openSongIndex } = useContext(AppContext);
const [showSolution, setShowSolution] = useState(false);
const [showHint, setShowHint] = useState(false);
const handleClose = () => {
openDoor(null);
setShowSolution(false);
};
if (loading || !openSong) {
return null;
}
const { title, hint, id } = openSong;
return (
<div className="door-mask" onClick={handleClose}>
<div className="door" onClick={event => event.stopPropagation()}>
<a className="door-close" onClick={handleClose}>
</a>
<h1>Türchen {openSongIndex + 1}</h1>
<Player hidden={!showSolution} />
{!showSolution && (
<div>
{hint && !showHint && (
<p>
<a className="link" onClick={() => setShowHint(true)}>
Ich brauche einen Tip!
</a>
</p>
)}
{hint && showHint && (
<div className="hint">
<h4>Tip:</h4>
<p>{hint}</p>
</div>
)}
<p>
<a className="solve" onClick={() => setShowSolution(true)}>
Zeig mir die Lösung!
</a>
</p>
</div>
)}
</div>
</div>
);
};
export default ShowDoorDialog;