giller.dev/index.html

399 lines
12 KiB
HTML
Raw Normal View History

2023-02-25 03:37:45 +01:00
<!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;
}
2023-12-26 23:49:10 +01:00
.profile {
margin-top: 150px;
2023-12-27 00:05:55 +01:00
margin-bottom: 100px;
2023-12-26 23:49:10 +01:00
margin-left: 45%;
margin-right: 45%;
}
2024-01-09 22:47:36 +01:00
.profile > img {
height: auto;
width: 10%;
min-width: 35px;
min-height: 35px;
}
2023-02-25 03:37:45 +01:00
.info {
color: #fff;
}
2023-12-27 00:41:05 +01:00
#status {
text-align: left;
}
#description {
font-size: small;
text-align: left;
}
2023-02-25 03:37:45 +01:00
#sleep {
margin-top: 2em;
}
2024-01-09 22:41:22 +01:00
.sleep-streak {
margin-top: 2em;
}
2023-02-25 03:37:45 +01:00
#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;
}
2023-02-25 04:47:11 +01:00
#settings {
2023-02-25 04:55:38 +01:00
max-width: 500px;
2023-02-25 04:47:11 +01:00
margin: 0 auto;
height: 60vh;
2023-02-25 04:55:38 +01:00
padding: 0 20px;
2023-02-25 04:47:11 +01:00
}
#settings-notice {
position: absolute;
bottom: 5vh;
width: 100vw;
text-align: center;
color: #444;
transition-duration: 0.5s;
transition-property: opacity;
}
.hide {
opacity: 0;
2024-01-09 22:41:22 +01:00
height: 0;
margin: 0 !important;
2023-02-25 04:47:11 +01:00
}
2023-02-25 04:55:38 +01:00
.settings-table td {
vertical-align: top;
border-style: none;
}
2023-03-29 03:06:23 +02:00
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;
}
2023-02-25 03:37:45 +01:00
</style>
2024-01-09 22:41:22 +01:00
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
2023-02-25 03:37:45 +01:00
</head>
<body>
2023-03-29 03:06:23 +02:00
<div id="settings-notice">Scroll down for more</div>
2023-02-25 03:37:45 +01:00
<div id="container">
<div id="vertical-center">
2023-12-27 00:41:05 +01:00
<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>
2023-02-25 03:37:45 +01:00
<div id="sleep"></div>
2024-01-09 22:41:22 +01:00
<div id="sleep-streak">
Going to bed before midnight
2024-01-09 22:41:22 +01:00
<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>
2023-02-25 03:37:45 +01:00
</div>
</div>
2023-02-25 04:47:11 +01:00
<div id="settings">
2023-12-06 23:55:44 +01:00
<a href="https://portfolio.giller.dev">About me</a>
2023-12-26 23:49:10 +01:00
<br />
2023-12-06 23:55:44 +01:00
<a href="https://blog.giller.dev">My blog</a>
2023-12-26 23:49:10 +01:00
<br />
2023-12-06 23:58:52 +01:00
<a href="https://code.giller.dev/m.giller">My repositories</a>
2023-12-26 23:49:10 +01:00
<br />
2023-12-06 23:55:44 +01:00
<a href="https://insta.giller.dev">My archived Instagram</a>
<br />
2024-01-29 16:22:43 +01:00
<a href="https://letterboxd.com/mgiller">Movies I watched</a>
<br />
2024-02-13 10:51:28 +01:00
<a href="https://maxuser.itch.io">Games I worked on</a>
<br />
<br />
2024-01-29 15:09:07 +01:00
<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>
2023-12-27 00:05:55 +01:00
<br />
<br />
<a href="mailto:max@giller.dev">Write me an e-mail</a>
2023-02-25 04:47:11 +01:00
<h1>Settings</h1>
2023-02-25 04:55:38 +01:00
<table class="settings-table">
<tr>
<td><input type="checkbox" id="notifications" name="notifications" value="notifications" /></td>
<td><label for="notifications">Enable wake up
notifications</label></td>
</tr>
</table>
2024-01-09 22:47:36 +01:00
<div class="profile">
<img title="Primary profile picture" src="profile.jpg" />
<img title="Secondary profile picture" src="secondary-profile.jpg" />
</div>
2023-02-25 04:47:11 +01:00
</div>
2023-02-25 03:37:45 +01:00
<script>
const url = "https://giller.dev/g/my-status";
2023-02-25 04:47:11 +01:00
const notifications = [];
let userOnPage = true;
let previousStatus = undefined;
let currentStatus = undefined;
let updateRoutine = undefined;
const updateInterval = 60 * 1000;
const notificationSettingName = "wake-up-notifications";
2023-02-25 03:37:45 +01:00
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";
2023-02-25 03:37:45 +01:00
} else if (hours > 0) {
return "More than " + hours + " hours remaining";
2023-02-25 03:37:45 +01:00
}
const minutes = Math.floor((totalSeconds - (hours * 3600)) / 60);
if (minutes > 0) {
return "More than " + minutes + " minutes remaining";
2023-02-25 03:37:45 +01:00
}
const seconds = totalSeconds - (hours * 3600) - (minutes * 60);
return "More than " + seconds + " seconds remaining";
2023-02-25 03:37:45 +01:00
}
2023-02-25 04:47:11 +01:00
function updateStatus() {
fetch(url)
.then(response => response.json())
.then(data => {
previousStatus = currentStatus;
currentStatus = data;
2023-03-08 00:16:50 +01:00
setText("status", data.title);
2023-12-27 00:41:05 +01:00
setText("description", data.description);
2023-02-25 04:47:11 +01:00
2024-01-09 22:41:22 +01:00
updateSleepStreak(data.streak);
2023-03-08 00:16:50 +01:00
if (data.title.toLowerCase() === "sleeping") {
const remainingText = formatRemainingTime(data.remainingDuration);
2023-02-25 04:47:11 +01:00
setText("sleep", "Time until wake up:<br><span class='info'>" + remainingText + "</span>");
} else {
setText("sleep", "");
}
});
}
function dismissNotifications() {
notifications.forEach(notification => notification.close());
notifications.length = 0;
}
function hasWakenUp() {
2023-03-08 00:16:50 +01:00
return previousStatus && previousStatus.title.toLowerCase() === "sleeping" && currentStatus.title.toLowerCase() !== "sleeping";
2023-02-25 04:47:11 +01:00
}
function enableNotifications() {
if (updateRoutine) {
return;
}
2023-02-25 03:37:45 +01:00
2023-02-25 04:47:11 +01:00
// Request permission to show notifications
Notification.requestPermission().then(function (result) {
if (result === "granted") {
// Save setting
localStorage.setItem(notificationSettingName, "true");
// Enable notifications
updateRoutine = setInterval(function () {
updateStatus();
if (hasWakenUp()) {
showNotification("Max Status", "Max has woken up!");
}
}, updateInterval);
2023-02-25 03:37:45 +01:00
}
});
2023-02-25 04:47:11 +01:00
}
function disableNotifications() {
if (!updateRoutine) {
return;
}
clearInterval(updateRoutine);
updateRoutine = undefined;
dismissNotifications();
// Save setting
localStorage.setItem(notificationSettingName, "false");
}
function showNotification(title, body) {
if (userOnPage) {
return;
}
const notification = new Notification(title, {
body: body,
icon: "https://giller.dev/favicon.ico"
});
notification.onclick = function () {
window.focus();
};
notifications.push(notification);
}
function loadNotificationSetting() {
if (localStorage.getItem(notificationSettingName) === "true") {
document.getElementById("notifications").checked = true;
enableNotifications();
} else {
document.getElementById("notifications").checked = false;
disableNotifications();
}
}
2024-01-09 22:41:22 +01:00
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);
2024-02-06 20:29:42 +01:00
const formattedDate = adjustedDate.getFullYear().toString() + "-" + (adjustedDate.getMonth() + 1).toString().padStart(2, "0") + "-" + adjustedDate.getDate().toString().padStart(2, "0");
2024-01-09 22:41:22 +01:00
let titleSuffix = ""
2024-01-09 22:41:22 +01:00
if (streakData.length > 0) {
if (streakData.includes(formattedDate)) {
classes.push("bi-circle-fill");
titleSuffix = " | Hit";
2024-01-09 22:41:22 +01:00
} else if (offset == 0) {
classes.push("bi-circle-half");
} else {
classes.push("bi-circle");
titleSuffix = " | Miss";
2024-01-09 22:41:22 +01:00
}
}
document.getElementById("day-" + offset).classList = classes.join(" ");
document.getElementById("day-" + offset).title = formattedDate + titleSuffix;
2024-01-09 22:41:22 +01:00
}
}
2023-02-25 04:47:11 +01:00
// On window focus, dismiss all notifications
window.onfocus = function () {
dismissNotifications();
userOnPage = true;
};
// On window blur, enable notifications
window.onblur = function () {
userOnPage = false;
};
// On page unload, dismiss all notifications
window.onbeforeunload = function () {
dismissNotifications();
};
// On checkbox change, enable/disable notifications
document.getElementById("notifications").onchange = function () {
if (this.checked) {
enableNotifications();
} else {
disableNotifications();
}
};
// 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();
loadNotificationSetting();
2023-02-25 03:37:45 +01:00
</script>
</body>
</html>