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;
|
|
|
|
}
|
|
|
|
|
|
|
|
.info {
|
|
|
|
color: #fff;
|
|
|
|
}
|
|
|
|
|
|
|
|
#sleep {
|
|
|
|
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;
|
|
|
|
}
|
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;
|
|
|
|
}
|
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>
|
|
|
|
</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">
|
|
|
|
Currently:
|
|
|
|
<span id="status" class="info">...</span>
|
|
|
|
|
|
|
|
<div id="sleep"></div>
|
|
|
|
|
|
|
|
</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-06 23:58:03 +01:00
|
|
|
<br/>
|
2023-12-06 23:55:44 +01:00
|
|
|
<a href="https://blog.giller.dev">My blog</a>
|
2023-12-06 23:58:03 +01:00
|
|
|
<br/>
|
2023-12-06 23:58:52 +01:00
|
|
|
<a href="https://code.giller.dev/m.giller">My repositories</a>
|
2023-12-06 23:58:03 +01:00
|
|
|
<br/>
|
2023-12-06 23:55:44 +01:00
|
|
|
<a href="https://insta.giller.dev">My archived Instagram</a>
|
2023-12-26 23:35:05 +01:00
|
|
|
<br />
|
|
|
|
<br />
|
|
|
|
<a href="https://tv.giller.dev">My prefered entertainment</a>
|
|
|
|
<br />
|
|
|
|
<a href="https://maps.giller.dev">My prefered navigation</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>
|
|
|
|
|
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";
|
|
|
|
} else if (hours > 0) {
|
|
|
|
return hours + " hours remaining";
|
|
|
|
}
|
|
|
|
|
|
|
|
const minutes = Math.floor((totalSeconds - (hours * 3600)) / 60);
|
|
|
|
if (minutes > 0) {
|
|
|
|
return minutes + " minutes remaining";
|
|
|
|
}
|
|
|
|
|
|
|
|
const seconds = totalSeconds - (hours * 3600) - (minutes * 60);
|
|
|
|
return seconds + " seconds remaining";
|
|
|
|
}
|
|
|
|
|
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-02-25 04:47:11 +01:00
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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>
|