First container working

This commit is contained in:
2022-01-02 22:48:24 +01:00
parent 9cb37db275
commit 7cffb316d9
12 changed files with 614 additions and 21 deletions

View File

@ -0,0 +1,138 @@
import * as React from "react"
import type { WeatherInfo } from "../lib/interfaces";
import * as styles from "../styles/containers/WeatherAndTime.module.css";
const WEATHER_REFRESH_INTERVAL = 15 * 60 * 1000;
function dowToString(dow: number) {
switch (dow) {
case 0: return "Sonntag";
case 1: return "Montag";
case 2: return "Dienstag";
case 3: return "Mittwoch";
case 4: return "Donnerstag";
case 5: return "Freitag";
case 6: return "Samstag";
default: return;
}
}
function monthToString(month: number) {
switch (month) {
case 0: return "Januar";
case 1: return "Februar";
case 2: return "März";
case 3: return "April";
case 4: return "Mail";
case 5: return "Juni";
case 6: return "Juli";
case 7: return "August";
case 8: return "September";
case 9: return "Oktober";
case 10: return "November";
case 11: return "Dezember";
default: return;
}
}
function getWeatherIcon(icon: string) {
const ImportedIcon = require(`../images/weather/${icon}.svg`);
return <ImportedIcon />
}
const WeatherAndTimeContainer = ({ apiKey, coords }) => {
const [date, setDate] = React.useState(new Date());
const [weather, setWeather] = React.useState<WeatherInfo>({
currently: {
icon: "clear-day",
temperature: 0,
summary: "No data loaded"
},
daily: {
data: [
{ icon: "clear-day", time: 0, temperatureHigh: 0, temperatureLow: 0 },
{ icon: "clear-day", time: 0, temperatureHigh: 0, temperatureLow: 0 },
{ icon: "clear-day", time: 0, temperatureHigh: 0, temperatureLow: 0 },
{ icon: "clear-day", time: 0, temperatureHigh: 0, temperatureLow: 0 },
]
}
});
React.useEffect(() => {
const dateInterval = setInterval(() => {
const date = new Date()
if (date.getHours() < 7) document.documentElement.setAttribute("data-theme", "night");
else document.documentElement.setAttribute("data-theme", "day");
setDate(date);
}, 1000);
pullWeather()
//TODO
//const weatherInterval = setInterval(pullWeather, WEATHER_REFRESH_INTERVAL);
return () => {
clearInterval(dateInterval);
//clearInterval(weatherInterval);
}
}, [])
const pullWeather = () => {
fetch(`https://api.pirateweather.net/forecast/${apiKey}/${coords}?exclude=minutely,hourly&lang=de&units=ca`)
.then(resp => resp.json())
.then(setWeather);
}
const time = `${date.getHours()}:${date.getMinutes().toString().padStart(2, "0")}`;
const dateString = `${dowToString(date.getDay())}, der ${date.getDate()}. ${monthToString(date.getMonth())} ${date.getFullYear()}`;
if (weather.currently.summary === "No data loaded") return (<div className={`container ${styles.container}`}>
<span id={styles.clock}>{time}</span>
<span id={styles.date}>{dateString}</span>
</div>);
return (<div className={`container ${styles.container}`}>
<span id={styles.clock}>{time}</span>
<span id={styles.date}>{dateString}</span>
<div id={styles.weatherIcon}>{getWeatherIcon(weather.currently.icon)}</div>
<span id={styles.temperature}>{weather.currently.temperature.toFixed(1)}°C</span>
<span id={styles.currentWeatherInfos}>{weather.currently.summary}</span>
<table id={styles.futureWeatherInfos}>
<thead>
<tr>
{(() => {
const rslt = []
for (let i = 0; i < 4; i++) {
const day = new Date((weather.daily.data[i].time * 1000));
rslt.push(<th colSpan={2} key={i}>{dowToString(day.getDay())}, {day.getDate()}. {day.getMonth() + 1}.</th>);
}
return rslt
})()}
</tr>
</thead>
<tbody>
<tr>
{(() => {
const rslt = []
for (let i = 0; i < 4; i++) {
const style = i > 0 ? { borderLeft: "1px solid var(--iconColor)" } : {}
rslt.push(<td key={`00${i}`} rowSpan={2} style={style}>{getWeatherIcon(weather.daily.data[i].icon)}</td>);
rslt.push(<td key={`10${i}`} className={styles.futureWeatherHighTemp}>{weather.daily.data[i].temperatureHigh.toFixed(1)}°C</td>);
}
return rslt
})()}
</tr>
<tr>
{(() => {
const rslt = []
for (let i = 0; i < 4; i++) {
rslt.push(<td key={i} className={styles.futureWeatherLowTemp}>{weather.daily.data[i].temperatureLow.toFixed(1)}°C</td>);
}
return rslt
})()}
</tr>
</tbody>
</table>
</div>)
}
export default WeatherAndTimeContainer;

0
src/images/.gitkeep Normal file
View File

15
src/lib/interfaces.ts Normal file
View File

@ -0,0 +1,15 @@
export interface WeatherInfo {
currently: {
icon: string;
temperature: number;
summary: string;
},
daily: {
data: {
time: number; // Epoch without ms
icon: string;
temperatureHigh: number;
temperatureLow: number;
}[]
}
}

4
src/lib/types.d.ts vendored Normal file
View File

@ -0,0 +1,4 @@
declare module '*.css' {
const content: {[className: string]: string};
export = content;
}

View File

@ -1,7 +1,36 @@
import * as React from "react"
import secrets from "../../secrets.json"
import WeatherAndTimeContainer from "../components/WeatherAndTime"
function importAll(r) {
return r.keys().map(r);
}
const images = importAll(require.context('../images/bg/', false, /\.(png|jpe?g|svg)$/));
const IndexPage = () => {
return (<>Hello World</>)
const [currentBg, setCurrentBg] = React.useState(0);
React.useEffect(() => {
// This effect is executed onload
updateBackground()
const interval = setInterval(() => {
updateBackground();
}, 30 * 60 * 1000);
// Return will be executed onunload
return () => clearInterval(interval);
}, [])
const updateBackground = () => {
let nextBg = Math.floor(Math.random() * images.length)
while (nextBg == currentBg) nextBg = Math.floor(Math.random() * images.length)
setCurrentBg(nextBg)
}
return (<main style={{ backgroundImage: `url(${images[currentBg].default})` }}>
<WeatherAndTimeContainer apiKey={secrets.weather.apiKey} coords={secrets.weather.coords}/>
</main>)
}
export default IndexPage

View File

@ -0,0 +1,73 @@
.container {
grid-area: date-weather;
display: grid;
grid-template-areas:
"time currentIcon currentTemp"
"date currentCondition currentCondition"
"forecast forecast forecast";
grid-template-columns: auto min-content min-content;
grid-template-rows: min-content min-content auto;
column-gap: 1vw;
row-gap: 0;
align-items: stretch;
justify-content: stretch;
padding: 10px;
text-align: center;
}
#clock {
grid-area: time;
font-size: 14vh;
}
#weatherIcon {
grid-area: currentIcon;
height: 15vh;
}
.container svg {
height: 100%;
fill: var(--iconColor);
}
#temperature {
grid-area: currentTemp;
font-size: 12vh;
}
#date {
grid-area: date;
font-size: 2.5vh;
padding-bottom: 10px;
}
#currentWeatherInfos {
grid-area: currentCondition;
font-size: 2.5vh;
padding-bottom: 10px;
}
#futureWeatherInfos {
border-top: 1px solid var(--iconColor);
grid-area: forecast;
height: 100%;
width: 100%;
}
#futureWeatherInfos th {
text-align: center;
font-size: 3vh;
font-weight: bold;
}
#futureWeatherInfos .futureWeatherHighTemp,
#futureWeatherInfos .futureWeatherLowTemp {
text-align: right;
padding-right: 10px;
vertical-align: middle;
font-size: 3.5vh;
}
#futureWeatherInfos td {
padding-right: 5px;
}

57
src/styles/global.css Normal file
View File

@ -0,0 +1,57 @@
* {
box-sizing: border-box;
}
:root, :root[data-theme="day"] {
--containerBg: rgba(255,255,255,0.5);
--textColor: #000000;
color: #000000;
--iconColor: #000000;
}
:root[data-theme="night"] {
--containerBg: rgba(20,20,20,0.8);
--textColor: #b0b0b0;
color: #b0b0b0;
--iconColor: #b0b0b0;
}
body, main {
background: #000;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
main {
display: grid;
grid-template-areas:
"date-weather date-weather calendar"
"date-weather date-weather calendar"
"map dvb news"
"map spotify news";
grid-template-columns: 28vw auto 28vw;
grid-template-rows: 18vh 19vh 19vh 19vh;
column-gap: 3vw;
row-gap: 5vh;
padding: 5vh 3vw;
align-items: stretch;
justify-content: stretch;
max-width: 100%;
font-family: Arial;
transition: background-image 1s linear;
background-repeat: no-repeat;
background-size: cover;
background-position: center center;
}
:root[data-theme="night"] main {
background-image: url("../images/bg/3.jpg") !important;
}
.container {
box-shadow: 0 0 1rem 0 rgba(0, 0, 0, .2);
border-radius: 10px;
background: var(--containerBg);
backdrop-filter: blur(5px);
padding:10px;
overflow:hidden;
}