295 lines
No EOL
8.6 KiB
HTML
295 lines
No EOL
8.6 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Giller</title>
|
|
<style>
|
|
body {
|
|
background-color: #1a1a1a;
|
|
color: #aaa;
|
|
font-family: "Fira Code", "Fira Mono", "Roboto Mono", "Lucida Console", "Courier New", monospace;
|
|
font-size: 16px;
|
|
line-height: 1.5;
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
.profile {
|
|
margin-top: 150px;
|
|
margin-bottom: 100px;
|
|
margin-left: 45%;
|
|
margin-right: 45%;
|
|
}
|
|
|
|
.profile > img {
|
|
height: auto;
|
|
width: 10%;
|
|
min-width: 35px;
|
|
min-height: 35px;
|
|
}
|
|
|
|
.info {
|
|
color: #fff;
|
|
}
|
|
|
|
#status {
|
|
text-align: left;
|
|
}
|
|
|
|
#description {
|
|
font-size: small;
|
|
text-align: left;
|
|
}
|
|
|
|
#sleep {
|
|
margin-top: 2em;
|
|
}
|
|
|
|
.sleep-streak {
|
|
margin-top: 2em;
|
|
}
|
|
|
|
#container {
|
|
display: flex;
|
|
height: 100vh;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
|
|
#vertical-center {
|
|
display: flex;
|
|
flex-direction: column;
|
|
width: 100vw;
|
|
}
|
|
|
|
#vertical-center,
|
|
#vertical-center>* {
|
|
align-items: center;
|
|
text-align: center;
|
|
}
|
|
|
|
#settings {
|
|
max-width: 500px;
|
|
margin: 0 auto;
|
|
height: 60vh;
|
|
padding: 0 20px;
|
|
}
|
|
|
|
#settings-notice {
|
|
position: absolute;
|
|
bottom: 5vh;
|
|
width: 100vw;
|
|
text-align: center;
|
|
color: #444;
|
|
|
|
transition-duration: 0.5s;
|
|
transition-property: opacity;
|
|
}
|
|
|
|
.hide {
|
|
opacity: 0;
|
|
height: 0;
|
|
margin: 0 !important;
|
|
}
|
|
|
|
.settings-table td {
|
|
vertical-align: top;
|
|
border-style: none;
|
|
}
|
|
|
|
a {
|
|
color: inherit;
|
|
text-decoration: none;
|
|
padding: 5px 10px;
|
|
border-radius: 5px;
|
|
transition-duration: 0.2s;
|
|
}
|
|
|
|
a::before {
|
|
content: "> ";
|
|
}
|
|
|
|
a:hover {
|
|
background-color: #444;
|
|
}
|
|
|
|
a:active {
|
|
background-color: #222;
|
|
}
|
|
</style>
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
|
</head>
|
|
|
|
<body>
|
|
<div id="settings-notice">Scroll down for more</div>
|
|
<div id="container">
|
|
<div id="vertical-center">
|
|
<table>
|
|
<tr>
|
|
<td>Currently:</td>
|
|
<td style="width: 5px;"></td>
|
|
<td id="status" class="info">
|
|
...
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td></td>
|
|
<td></td>
|
|
<td id="description">
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<div id="sleep"></div>
|
|
|
|
<div id="sleep-streak">
|
|
Going to bed before midnight
|
|
<br />
|
|
<i id="day-7" class="bi"></i>
|
|
<i id="day-6" class="bi"></i>
|
|
<i id="day-5" class="bi"></i>
|
|
<i id="day-4" class="bi"></i>
|
|
<i id="day-3" class="bi"></i>
|
|
<i id="day-2" class="bi"></i>
|
|
<i id="day-1" class="bi"></i>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
<div id="settings">
|
|
<a href="https://portfolio.giller.dev">About me</a>
|
|
<br />
|
|
<a href="https://blog.giller.dev">My blog</a>
|
|
<br />
|
|
<a href="https://code.giller.dev/m.giller">My repositories</a>
|
|
<br />
|
|
<a href="https://insta.giller.dev">My archived Instagram</a>
|
|
<br />
|
|
<a href="https://letterboxd.com/mgiller">Movies I watched</a>
|
|
<br />
|
|
<a href="https://maxuser.itch.io">Games I worked on</a>
|
|
<br />
|
|
<br />
|
|
<a href="https://linu.sk/blog">My prefered literature</a>
|
|
<br />
|
|
<a href="https://tv.giller.dev">My prefered entertainment</a>
|
|
<br />
|
|
<a href="https://maps.giller.dev">My prefered navigation</a>
|
|
<br />
|
|
<br />
|
|
<a href="mailto:max@giller.dev">Write me an e-mail</a>
|
|
|
|
<div class="profile">
|
|
<img title="Primary profile picture" src="profile.png" />
|
|
<img title="Secondary profile picture" src="secondary-profile.jpg" />
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
const url = "https://giller.dev/g/my-status";
|
|
let previousStatus = undefined;
|
|
let currentStatus = undefined;
|
|
let updateRoutine = undefined;
|
|
const updateInterval = 60 * 1000;
|
|
|
|
function setText(id, text) {
|
|
document.getElementById(id).innerHTML = text;
|
|
}
|
|
|
|
function formatRemainingTime(totalSeconds) {
|
|
if (totalSeconds <= 0) {
|
|
return "should wake up anytime now"
|
|
}
|
|
|
|
const hours = Math.floor(totalSeconds / 3600);
|
|
if (hours > 24) {
|
|
return "Over a day";
|
|
} else if (hours > 0) {
|
|
return "More than " + hours + " hours remaining";
|
|
}
|
|
|
|
const minutes = Math.floor((totalSeconds - (hours * 3600)) / 60);
|
|
if (minutes > 0) {
|
|
return "More than " + minutes + " minutes remaining";
|
|
}
|
|
|
|
const seconds = totalSeconds - (hours * 3600) - (minutes * 60);
|
|
return "More than " + seconds + " seconds remaining";
|
|
}
|
|
|
|
function updateStatus() {
|
|
fetch(url)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
previousStatus = currentStatus;
|
|
currentStatus = data;
|
|
|
|
setText("status", data.title);
|
|
setText("description", data.description);
|
|
|
|
updateSleepStreak(data.streak);
|
|
|
|
if (data.title.toLowerCase() === "sleeping") {
|
|
const remainingText = formatRemainingTime(data.remainingDuration);
|
|
setText("sleep", "Time until wake up:<br><span class='info'>" + remainingText + "</span>");
|
|
} else {
|
|
setText("sleep", "");
|
|
}
|
|
});
|
|
}
|
|
|
|
function hasWakenUp() {
|
|
return previousStatus && previousStatus.title.toLowerCase() === "sleeping" && currentStatus.title.toLowerCase() !== "sleeping";
|
|
}
|
|
|
|
|
|
|
|
function updateSleepStreak(streakData) {
|
|
if (streakData.length == 0) {
|
|
document.getElementById("sleep-streak").classList = "hide";
|
|
return;
|
|
} else {
|
|
document.getElementById("sleep-streak").classList = "sleep-streak";
|
|
}
|
|
|
|
for (let offset = 1; offset < 8; offset++) {
|
|
let classes = ["bi"]
|
|
|
|
const adjustedDate = new Date((new Date()).getTime() - offset * 24 * 60 * 60 * 1000);
|
|
const formattedDate = adjustedDate.getFullYear().toString() + "-" + (adjustedDate.getMonth() + 1).toString().padStart(2, "0") + "-" + adjustedDate.getDate().toString().padStart(2, "0");
|
|
|
|
let titleSuffix = ""
|
|
if (streakData.length > 0) {
|
|
if (streakData.includes(formattedDate)) {
|
|
classes.push("bi-circle-fill");
|
|
titleSuffix = " | Hit";
|
|
} else if (offset == 0) {
|
|
classes.push("bi-circle-half");
|
|
} else {
|
|
classes.push("bi-circle");
|
|
titleSuffix = " | Miss";
|
|
}
|
|
}
|
|
|
|
document.getElementById("day-" + offset).classList = classes.join(" ");
|
|
document.getElementById("day-" + offset).title = formattedDate + titleSuffix;
|
|
}
|
|
}
|
|
|
|
// On scroll, hide settings notice
|
|
window.onscroll = function () {
|
|
const scrollPosition = window.scrollY;
|
|
if (scrollPosition > 0) {
|
|
document.getElementById("settings-notice").classList.add("hide");
|
|
} else {
|
|
document.getElementById("settings-notice").classList.remove("hide");
|
|
}
|
|
};
|
|
|
|
updateStatus();
|
|
</script>
|
|
</body>
|
|
|
|
</html> |