mirror of
https://github.com/wah-su/wah-su.github.io.git
synced 2025-04-06 08:14:40 +00:00
refactor: status indicator and page
add transition animation to status indicator icon refactor icon and text to be one element add Unknown and Loading status remove sticky class from header
This commit is contained in:
parent
9b9886a8d2
commit
62644e4c6f
4 changed files with 96 additions and 146 deletions
13
index.html
13
index.html
|
@ -36,20 +36,17 @@
|
|||
</head>
|
||||
|
||||
<body class="light dark:bg-slate-900" id="body">
|
||||
<header class="sticky top-0 left-0 pt-4 pb-6 shadow-lg bg-slate-50 dark:bg-slate-800">
|
||||
<header class="top-0 left-0 pt-4 pb-6 shadow-lg bg-slate-50 dark:bg-slate-800">
|
||||
<div
|
||||
class="flex flex-col md:flex-row gap-2 md:gap-0 items-center container max-w-[1440px] justify-between px-4">
|
||||
<div class="self-start"><img src="/public/images/logo-light.svg" alt="wah.su" id="logo" /></div>
|
||||
<div class="self-start md:self-auto">
|
||||
<!--noformat-->
|
||||
<a href="https://status.wah.su" class="flex flex-row items-center gap-2" target="_blank">
|
||||
<div class="hidden w-4 h-4 bg-green-500 rounded-full dark:bg-green-400" id="status-up-icon"></div>
|
||||
<div class="hidden w-4 h-4 bg-yellow-400 rounded-full dark:bg-yellow-200" id="status-degraded-icon">
|
||||
</div>
|
||||
<div class="hidden w-4 h-4 bg-red-600 rounded-full dark:bg-red-500" id="status-down-icon"></div>
|
||||
<p class="hidden dark:text-slate-50" id="status-up-text">All Systems Operational.</p>
|
||||
<p class="hidden dark:text-slate-50" id="status-degraded-text">Degraded Services.</p>
|
||||
<p class="hidden dark:text-slate-50" id="status-down-text">All Systems Down.</p>
|
||||
<div class="w-4 h-4 transition ease-in bg-gray-500 rounded-full duration-400" id="status-icon"></div>
|
||||
<p class="dark:text-slate-50" id="status-text">Fetching Services Status</p>
|
||||
</a>
|
||||
<!--noformat-->
|
||||
</div>
|
||||
<div class="flex flex-row items-center self-start justify-center gap-6 -ml-4">
|
||||
<label class="inline-flex items-center cursor-pointer">
|
||||
|
|
|
@ -1,63 +1,85 @@
|
|||
const statusIcon = document.getElementById("status-icon");
|
||||
const statusText = document.getElementById("status-text");
|
||||
|
||||
const serviceUp = {
|
||||
icon: document.getElementById("status-up-icon"),
|
||||
text: document.getElementById("status-up-text"),
|
||||
color: ["bg-green-500", "dark:bg-green-400"],
|
||||
text: "All Services Operational",
|
||||
};
|
||||
const serviceDegraded = {
|
||||
icon: document.getElementById("status-degraded-icon"),
|
||||
text: document.getElementById("status-degraded-text"),
|
||||
color: ["bg-yellow-400", "dark:bg-yellow-200"],
|
||||
text: "Degraded Services",
|
||||
};
|
||||
const serviceDown = {
|
||||
icon: document.getElementById("status-down-icon"),
|
||||
text: document.getElementById("status-down-text"),
|
||||
color: ["bg-red-600", "dark:bg-red-500"],
|
||||
text: "All Services Down",
|
||||
};
|
||||
const serviceUnknown = {
|
||||
color: ["bg-gray-500", "dark:bg-gray-400"],
|
||||
text: "Services Status Unknown",
|
||||
};
|
||||
|
||||
async function getServicesHealth() {
|
||||
const serviceStatus = await fetch(
|
||||
"https://status.wah.su/api/status-page/heartbeat/services"
|
||||
);
|
||||
|
||||
const services = await serviceStatus.json();
|
||||
const heartbeatDict = services.heartbeatList;
|
||||
let lastHeartbeats = [];
|
||||
|
||||
for (const [key, value] of Object.entries(heartbeatDict)) {
|
||||
lastHeartbeats.push(
|
||||
heartbeatDict[key][heartbeatDict[key].length - 1].status
|
||||
try {
|
||||
const serviceStatus = await fetch(
|
||||
"https://status.wah.su/api/status-page/heartbeat/services"
|
||||
);
|
||||
}
|
||||
|
||||
let status = "up";
|
||||
const count = lastHeartbeats.reduce((partialSum, a) => partialSum + a, 0);
|
||||
const services = await serviceStatus.json();
|
||||
const heartbeatDict = services.heartbeatList;
|
||||
let lastHeartbeats = [];
|
||||
|
||||
if (count === lastHeartbeats.length) {
|
||||
status = "up";
|
||||
} else if (count === 0) {
|
||||
status = "down";
|
||||
} else {
|
||||
status = "degraded";
|
||||
}
|
||||
for (const [key, value] of Object.entries(heartbeatDict)) {
|
||||
lastHeartbeats.push(
|
||||
heartbeatDict[key][heartbeatDict[key].length - 1].status
|
||||
);
|
||||
}
|
||||
|
||||
if (status === "up") {
|
||||
serviceUp.icon.classList.remove("hidden");
|
||||
serviceUp.text.classList.remove("hidden");
|
||||
serviceDegraded.icon.classList.add("hidden");
|
||||
serviceDegraded.text.classList.add("hidden");
|
||||
serviceDown.icon.classList.add("hidden");
|
||||
serviceDown.text.classList.add("hidden");
|
||||
} else if (status === "degraded") {
|
||||
serviceUp.icon.classList.add("hidden");
|
||||
serviceUp.text.classList.add("hidden");
|
||||
serviceDegraded.icon.classList.remove("hidden");
|
||||
serviceDegraded.text.classList.remove("hidden");
|
||||
serviceDown.icon.classList.add("hidden");
|
||||
serviceDown.text.classList.add("hidden");
|
||||
} else if (status === "down") {
|
||||
serviceUp.icon.classList.add("hidden");
|
||||
serviceUp.text.classList.add("hidden");
|
||||
serviceDegraded.icon.classList.add("hidden");
|
||||
serviceDegraded.text.classList.add("hidden");
|
||||
serviceDown.icon.classList.remove("hidden");
|
||||
serviceDown.text.classList.remove("hidden");
|
||||
let status = "up";
|
||||
const count = lastHeartbeats.reduce((partialSum, a) => partialSum + a, 0);
|
||||
|
||||
if (count === lastHeartbeats.length) {
|
||||
status = "up";
|
||||
} else if (count === 0) {
|
||||
status = "down";
|
||||
} else {
|
||||
status = "degraded";
|
||||
}
|
||||
|
||||
if (status === "up") {
|
||||
statusIcon.classList.add(...serviceUp.color);
|
||||
statusIcon.classList.remove(
|
||||
...serviceDegraded.color,
|
||||
...serviceDown.color,
|
||||
...serviceUnknown.color
|
||||
);
|
||||
statusText.textContent = serviceUp.text;
|
||||
} else if (status === "degraded") {
|
||||
statusIcon.classList.add(...serviceDegraded.color);
|
||||
statusIcon.classList.remove(
|
||||
...serviceUp.color,
|
||||
...serviceDown.color,
|
||||
...serviceUnknown.color
|
||||
);
|
||||
statusText.textContent = serviceDegraded.text;
|
||||
} else if (status === "down") {
|
||||
statusIcon.classList.add(...serviceDown.color);
|
||||
statusIcon.classList.remove(
|
||||
...serviceUp.color,
|
||||
...serviceDegraded.color,
|
||||
...serviceUnknown.color
|
||||
);
|
||||
statusText.textContent = serviceDown.text;
|
||||
}
|
||||
} catch (error) {
|
||||
statusIcon.classList.add(...serviceUnknown.color);
|
||||
statusIcon.classList.remove(
|
||||
...serviceUp.color,
|
||||
...serviceDegraded.color,
|
||||
...serviceDown.color
|
||||
);
|
||||
statusText.textContent = serviceUnknown.text;
|
||||
console.log("Failed to fetch services status: " + error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1093,10 +1093,6 @@ input:checked + .toggle-bg {
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.sticky {
|
||||
position: sticky;
|
||||
}
|
||||
|
||||
.inset-0 {
|
||||
inset: 0px;
|
||||
}
|
||||
|
@ -1141,31 +1137,15 @@ input:checked + .toggle-bg {
|
|||
z-index: 50;
|
||||
}
|
||||
|
||||
.col-span-2 {
|
||||
grid-column: span 2 / span 2;
|
||||
}
|
||||
|
||||
.col-span-3 {
|
||||
grid-column: span 3 / span 3;
|
||||
}
|
||||
|
||||
.col-span-1 {
|
||||
grid-column: span 1 / span 1;
|
||||
}
|
||||
|
||||
.row-span-1 {
|
||||
grid-row: span 1 / span 1;
|
||||
}
|
||||
|
||||
.row-span-2 {
|
||||
grid-row: span 2 / span 2;
|
||||
}
|
||||
|
||||
.mx-auto {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.-ml-4 {
|
||||
margin-left: -1rem;
|
||||
}
|
||||
|
||||
.mb-1 {
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
@ -1186,8 +1166,8 @@ input:checked + .toggle-bg {
|
|||
margin-inline-end: 0.5rem;
|
||||
}
|
||||
|
||||
.ml-8 {
|
||||
margin-left: 2rem;
|
||||
.ml-2 {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.mr-4 {
|
||||
|
@ -1214,18 +1194,6 @@ input:checked + .toggle-bg {
|
|||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.ml-2 {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.ml-4 {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
.-ml-4 {
|
||||
margin-left: -1rem;
|
||||
}
|
||||
|
||||
.block {
|
||||
display: block;
|
||||
}
|
||||
|
@ -1396,10 +1364,6 @@ input:checked + .toggle-bg {
|
|||
grid-template-columns: repeat(7, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-cols-2 {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.flex-row {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
@ -1452,14 +1416,6 @@ input:checked + .toggle-bg {
|
|||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.gap-4 {
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.gap-8 {
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.space-x-2 > :not([hidden]) ~ :not([hidden]) {
|
||||
--tw-space-x-reverse: 0;
|
||||
margin-right: calc(0.5rem * var(--tw-space-x-reverse));
|
||||
|
@ -1555,6 +1511,11 @@ input:checked + .toggle-bg {
|
|||
background-color: rgb(229 231 235 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.bg-gray-500 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(107 114 128 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.bg-gray-800 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(31 41 55 / var(--tw-bg-opacity));
|
||||
|
@ -1653,21 +1614,6 @@ input:checked + .toggle-bg {
|
|||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.px-2\.5 {
|
||||
padding-left: 0.625rem;
|
||||
padding-right: 0.625rem;
|
||||
}
|
||||
|
||||
.py-1 {
|
||||
padding-top: 0.25rem;
|
||||
padding-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.py-1\.5 {
|
||||
padding-top: 0.375rem;
|
||||
padding-bottom: 0.375rem;
|
||||
}
|
||||
|
||||
.pb-6 {
|
||||
padding-bottom: 1.5rem;
|
||||
}
|
||||
|
@ -1824,6 +1770,10 @@ input:checked + .toggle-bg {
|
|||
transition-duration: 150ms;
|
||||
}
|
||||
|
||||
.ease-in {
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 1, 1);
|
||||
}
|
||||
|
||||
.ease-out {
|
||||
transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
|
||||
}
|
||||
|
@ -2000,36 +1950,11 @@ input:checked + .toggle-bg {
|
|||
--tw-ring-color: rgb(164 202 254 / var(--tw-ring-opacity));
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.sm\:block {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.sm\:px-5 {
|
||||
padding-left: 1.25rem;
|
||||
padding-right: 1.25rem;
|
||||
}
|
||||
|
||||
.sm\:py-2 {
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.sm\:py-2\.5 {
|
||||
padding-top: 0.625rem;
|
||||
padding-bottom: 0.625rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.md\:ml-0 {
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
.md\:flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.md\:flex-row {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
@ -2101,6 +2026,11 @@ input:checked + .toggle-bg {
|
|||
background-color: rgb(28 100 242 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.dark\:bg-gray-400:where(.dark, .dark *) {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(156 163 175 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.dark\:bg-gray-600:where(.dark, .dark *) {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(75 85 99 / var(--tw-bg-opacity));
|
||||
|
|
|
@ -5,6 +5,7 @@ module.exports = {
|
|||
"./index.html",
|
||||
"./src/**/*.{html,js}",
|
||||
"./public/js/cards.js",
|
||||
"./public/js/status.js",
|
||||
"./node_modules/flowbite/**/*.js",
|
||||
],
|
||||
theme: {
|
||||
|
|
Loading…
Add table
Reference in a new issue