2 Commits

Author SHA1 Message Date
f76294ad5f fix code style, use names from api instead of hardcoding for flatmates users 2025-08-28 21:47:44 +02:00
6418cf882a Merge pull request 'windows95-zwischen-merge' (#1) from windows95-zwischen-merge into main
All checks were successful
CI / lint (push) Successful in 12s
CI / build (push) Successful in 10s
CI / build-and-push-docker (push) Successful in 16s
Reviewed-on: #1
2025-08-28 21:15:23 +02:00
13 changed files with 116 additions and 199 deletions

View File

@@ -16,7 +16,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install Biome - name: Install Biome
run: bun install -g biome run: bun install -g biome
- name: Biome CI - name: Biome Check
run: biome ci run: biome ci
build: build:

View File

@@ -24,6 +24,13 @@ export default function Dashboard() {
</div> </div>
</div> </div>
<div className={style.card}>
<div className={style.cardHeaderInactive}>🧹 Flatastic</div>
<div className={style.cardContent}>
<Flatastic />
</div>
</div>
<div className={style.card}> <div className={style.card}>
<div className={style.terminal}> <div className={style.terminal}>
<div className={style.cardHeader}>🔔 Terminal</div> <div className={style.cardHeader}>🔔 Terminal</div>
@@ -31,12 +38,14 @@ export default function Dashboard() {
</div> </div>
</div> </div>
<div className={style.card}> {/* <div className={style.card}> */}
<div className={style.cardHeaderInactive}>🧹 Flatastic</div> {/* <div className={style.cardHeaderInactive}> */}
<div className={style.cardContent}> {/* 🏠 HomeAssistant [Tent] */}
<Flatastic /> {/* </div> */}
</div> {/* <div className={style.cardContent}> */}
</div> {/* <HomeAssistant /> */}
{/* </div> */}
{/* </div> */}
</div> </div>
<div className={style.footer}> <div className={style.footer}>

View File

@@ -20,8 +20,11 @@ export default function Datetime() {
year: "numeric", year: "numeric",
}); });
const hour = today.getHours().toString().padStart(2, "0"); const time = today.toLocaleTimeString(locale, {
const minute = today.getMinutes().toString().padStart(2, "0"); hour: "numeric",
hour12: false,
minute: "numeric",
});
return ( return (
<div className={style.container}> <div className={style.container}>
@@ -29,11 +32,7 @@ export default function Datetime() {
<img src="src/assets/clock.png" alt="Clock" /> <img src="src/assets/clock.png" alt="Clock" />
</div> </div>
<div className={style.textContainer}> <div className={style.textContainer}>
<div className={style.time}> <div className={style.time}>{time}</div>
{hour}
<span className={style.divider}>:</span>
{minute}
</div>
<div className={style.date}>{date}</div> <div className={style.date}>{date}</div>
</div> </div>
</div> </div>

View File

@@ -17,13 +17,3 @@ img {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.divider {
animation: blink 3s step-end infinite;
}
@keyframes blink {
50% {
opacity: 0;
}
}

View File

@@ -8,11 +8,7 @@ import style from "./style.module.css";
export default function Flatastic() { export default function Flatastic() {
const fetchFlatasticData = useFlatasticStore((state) => state.fetch); const fetchFlatasticData = useFlatasticStore((state) => state.fetch);
const flatasticData = useFlatasticStore((state) => state.flatasticData); const flatasticData = useFlatasticStore((state) => state.flatasticData);
const chores = (flatasticData?.chores as FlatasticChore[]) || []; const chores = flatasticData?.chores;
chores.sort(
(a, b) =>
a.timeLeftNext - b.timeLeftNext && b.rotationTime - a.rotationTime,
);
const users = flatasticData?.users; const users = flatasticData?.users;
const idToNameMap: Record<number, string> = {}; const idToNameMap: Record<number, string> = {};
users.forEach((user: FlatasticUser) => { users.forEach((user: FlatasticUser) => {
@@ -27,38 +23,19 @@ export default function Flatastic() {
return () => clearInterval(interval); return () => clearInterval(interval);
}, [fetchFlatasticData]); }, [fetchFlatasticData]);
const choresRender = chores.map((chore) => {
let className = "";
let timeLeftInDays = null;
if (chore.rotationTime === -1) {
className = "irregular";
} else {
className = chore.timeLeftNext <= 0 ? "due" : "notDue";
timeLeftInDays = <span className={style.timeLeft}>
{Math.abs(
Math.floor(chore.timeLeftNext / (60 * 60 * 24)),
)}d
</span>;
}
return (
<li
key={chore.id}
className={[style.chore, style[className]].join(" ")}
>
<span className={style.userName}>
{`${idToNameMap[chore.currentUser]}`}
</span>
: {chore.title} {timeLeftInDays} {"🪙".repeat(chore.points)}
</li>
);
});
return ( return (
<div> <div>
<h1>Chores</h1> <h1>Chores</h1>
<ul className={style.choreList}>{choresRender}</ul> <ul className={style.choreList}>
{chores.map((chore: FlatasticChore) => (
<li key={chore.id} className={style.chore}>
<span className={style.userName}>
{idToNameMap[chore.currentUser]}
</span>
: {chore.title} - {"🪙".repeat(chore.points)}
</li>
))}
</ul>
</div> </div>
); );
} }

View File

@@ -20,19 +20,3 @@
.userName { .userName {
font-weight: bold; font-weight: bold;
} }
.irregular {
background-color: #aaaaaa;
}
.due {
background-color: #e4877e;
}
.notDue {
background-color: #a6cfa6;
}
.timeLeft {
font-weight: bold;
}

View File

@@ -5,6 +5,21 @@ import pasta from "./pasta.ts";
import style from "./style.module.css"; import style from "./style.module.css";
export default function Footer() { export default function Footer() {
const [index, setIndex] = useState(0);
// random shitpost every minute
useEffect(() => {
const timer = setInterval(() => {
setIndex(Math.floor(Math.random() * pasta.length));
console.log("sus!");
}, 60 * 1000);
return () => {
clearInterval(timer);
};
}, []);
const text = pasta[index];
return ( return (
<div className={style.container}> <div className={style.container}>
<div className={style.taskbar}> <div className={style.taskbar}>
@@ -18,10 +33,16 @@ export default function Footer() {
</div> </div>
<span className={style.divider}></span> <span className={style.divider}></span>
<div className={style.windows}> <div className={style.windows}>
<span className={style.window}>🚊 Timetable</span>
<span className={style.window}>🕐 Clock</span>
<span className={style.windowActive}>🔔 Terminal</span>
<span className={style.window}>🧹 Flatastic</span> <span className={style.window}>🧹 Flatastic</span>
<span className={style.window}>🚊 Timetable</span>
<span className={style.window}>🏠 HomeAssistant</span>
</div>
</div>
<div className={style.newsticker}>
<div className={style.info}>BREAKING</div>
<div className={style.marquee}>
<Marquee>{text}</Marquee>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -57,13 +57,19 @@
border-right: 2px solid #828282; border-right: 2px solid #828282;
} }
.windowActive { .newsticker {
min-width: 150px; display: flex;
padding-left: 10px; flex-direction: row;
display: inline-flex;
align-items: center; align-items: center;
border-bottom: 2px solid white; border-top: 2px solid white;
border-right: 2px solid white; border-left: 2px solid white;
border-left: 2px solid #828282; border-bottom: 2px solid #828282;
border-top: 2px solid #828282; border-right: 2px solid #828282;
}
.info {
background-color: red;
color: white;
font-weight: bold;
padding: 5px;
} }

View File

@@ -1,24 +1,10 @@
import { useEffect } from "react";
import { useHomeAssistantStore } from "@/store/homeAssistant"; import { useHomeAssistantStore } from "@/store/homeAssistant";
import { useEffect, useState } from "react";
import style from "./style.module.css";
import pasta from "./pasta.ts"; import pasta from "./pasta.ts";
import style from "./style.module.css";
export default function Terminal() { export default function Terminal() {
const [index, setIndex] = useState(0);
// random shitpost every minute
useEffect(() => {
const timer = setInterval(() => {
setIndex(Math.floor(Math.random() * pasta.length));
}, 60 * 1000);
return () => {
clearInterval(timer);
};
}, []);
const text = pasta[index];
const fetchHomeAssistantData = useHomeAssistantStore( const fetchHomeAssistantData = useHomeAssistantStore(
(state) => state.fetch, (state) => state.fetch,
); );
@@ -37,57 +23,19 @@ export default function Terminal() {
return ( return (
<div className={style.container}> <div className={style.container}>
<div className={style.input}> <span className={style.title}>
<span className={style.prompt}>[sus@home ~/hallway]{"$"}</span>{" "} -[#rauchen]---muehlburger-bubatz-buben.de-
tentfetch
</div>
<div className={style.fetch}>
<span>
<pre>
{" "}-///:.{" "}
<span className={style.username}>tent</span>@
<span className={style.hostname}>home</span>
</pre>
</span> </span>
<span> <span className={style.infoMessage}>
<pre> <span className={style.bubatzBot}>[BubatzBot]:</span>
{" "}smhhhhmh\`{" "}os{" "}Arch Linux **UPDATE** Tent: <b>{tentTemperature}°C</b>,{" "}
</pre> <b>{tentHumidity}%</b>
</span> </span>
<span>
<pre> <span className={style.message}>
{" "}:N{" "}Ns{" "}temp{" "} <span className={style.pastaBot}>[anonymous]:</span>
<span className={style.temp}>{tentTemperature}°C</span> <span className={style.pasta}>{pasta[0]}</span>
</pre>
</span> </span>
<span>
<pre>
{" "}hNNmmmmNNN{" "}humidity{" "}
<span className={style.humidity}>{tentHumidity}%</span>
</pre>
</span>
<span>
<pre>
{" "}NNssussNNN{" "}plants{" "}
<span className={style.plants}>4</span>
</pre>
</span>
<span>
<pre>
{" "}sNn:{" "}sNNo
</pre>
</span>
</div>
<div className={style.input}>
<span className={style.prompt}>[sus@home ~/hallway]{"$"}</span>{" "}
cat msg.txt
</div>
<div className={style.msg}>{text}</div>
<div className={style.input}>
<span className={style.prompt}>
[sus@home ~/hallway]{"$"}
</span>{" "}
</div>
</div> </div>
); );
} }

View File

@@ -2,48 +2,30 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
font-family: monospace; font-family: monospace;
font-size: 10pt; font-size: 12pt;
background-color: black; background-color: black;
color: white; color: white;
display: flex;
flex-direction: column;
width: 100%; width: 100%;
height: 290px; height: 285px;
overflow: hidden; overflow: hidden;
} }
.fetch { .title {
display: flex; color: thistle;
flex-direction: column; margin-bottom: 12pt;
padding-bottom: 10px;
} }
.prompt { .bubatzBot {
color: skyblue;
padding-right: 5px;
}
.pastaBot {
color: bisque;
padding-right: 5px;
}
.infoMessage {
color: lightgreen; color: lightgreen;
} }
.username {
color: violet;
}
.hostname {
color: skyblue;
}
.temp {
color: pink;
font-weight: bold;
}
.humidity {
color: skyblue;
font-weight: bold;
}
.plants {
color: lightgreen;
}
pre {
margin: 0;
}

View File

@@ -20,14 +20,8 @@ export default function Timetable() {
return ( return (
<div className={style.wrapper}> <div className={style.wrapper}>
<h1>Departures</h1> <h1>Departures</h1>
<DepartureList <DepartureList departures={pStreet.departureList} name="P-Street" />
departures={pStreet.departureList} <DepartureList departures={hStreet.departureList} name="H-Street" />
name="Philippstraße"
/>
<DepartureList
departures={hStreet.departureList}
name="Händelstraße"
/>
</div> </div>
); );
} }

View File

@@ -28,6 +28,8 @@ const useFlatasticStore = create(
const data = await flatastic.getTaskList(); const data = await flatastic.getTaskList();
const dataB = await flatastic.getInformation(); const dataB = await flatastic.getInformation();
console.log("Flatastic chores fetched:", data);
console.log("Flatastic information fetched:", dataB);
set({ set({
flatasticData: { flatasticData: {
chores: data as FlatasticChore[], chores: data as FlatasticChore[],

View File

@@ -16,6 +16,11 @@ const useKVVStore = create(
const hStreetJson = await hStreetData.json(); const hStreetJson = await hStreetData.json();
const pStreetJson = await pStreetData.json(); const pStreetJson = await pStreetData.json();
console.log("KVV departures fetched:", {
hStreet: hStreetJson,
pStreet: pStreetJson,
});
set({ set({
hStreet: hStreetJson as DepartureType[], hStreet: hStreetJson as DepartureType[],
pStreet: pStreetJson as DepartureType[], pStreet: pStreetJson as DepartureType[],