Compare commits

..
2 Commits
Author SHA1 Message Date
esef e6ab024bf5 kuma added 2026-10-11 20:57:44 +03:00
esefandClaude Opus 5.5 59d226f283 Replace Bot Status tab with the VEGA status page
The Status tab embeds status.userevolt.app (VEGA) in an iframe that loads
on first open, with a VEGA-coloured top bar. Old /yuukabot links go to
/status. Removes the Firebase bot dashboard (yuukabot.js/css).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 15:20:26 +03:00
6 changed files with 58 additions and 323 deletions

No files matched your search

+12 -68
View File
@@ -7,7 +7,6 @@
<link rel="stylesheet" href="style/styles.css"> <link rel="stylesheet" href="style/styles.css">
<link rel="stylesheet" href="style/gallery.css"> <link rel="stylesheet" href="style/gallery.css">
<link rel="stylesheet" href="style/comments.css"> <link rel="stylesheet" href="style/comments.css">
<link rel="stylesheet" href="style/yuukabot.css">
<link rel="stylesheet" href="style/calendar.css"> <link rel="stylesheet" href="style/calendar.css">
<link rel="stylesheet" href="style/bucketlist.css"> <link rel="stylesheet" href="style/bucketlist.css">
<link rel="stylesheet" href="style/services.css"> <link rel="stylesheet" href="style/services.css">
@@ -34,7 +33,7 @@
<button id="about-btn">About This Website</button> <button id="about-btn">About This Website</button>
<button id="gallery-btn">Gallery</button> <button id="gallery-btn">Gallery</button>
<button id="bucketlist-btn">Bucketlist</button> <button id="bucketlist-btn">Bucketlist</button>
<button id="yuukabot-btn">Bot Status</button> <button id="status-btn">Status</button>
<button id="calendar-btn">Calendar</button> <button id="calendar-btn">Calendar</button>
<button id="services-btn">Services</button> <button id="services-btn">Services</button>
</nav> </nav>
@@ -117,71 +116,9 @@
<section id="bucketlist" class="tab-content"></section> <section id="bucketlist" class="tab-content"></section>
<section id="yuukabot" class="tab-content"> <!-- VEGA status page (status.userevolt.app), src is set by tabs.js on first open -->
<header class="dash-header"> <section id="status" class="tab-content">
<h1><span class="status-dot pending" id="dash-status-dot"></span>Yuuka Bot</h1> <iframe id="status-frame" title="yuuka status"></iframe>
</header>
<div class="dash-grid">
<div class="dash-card span2">
<div class="card-top"><span class="card-label">Uptime</span></div>
<p class="card-value" id="dash-uptime">—</p>
<span class="card-detail" id="dash-bot-uptime"></span>
</div>
<div class="dash-card span2">
<div class="card-top"><span class="card-label">Disk</span></div>
<p class="card-value" id="dash-disk-val">—</p>
<div class="card-bar-wrap">
<div class="card-bar-fill disk" id="dash-disk-bar" style="width:0%"></div>
</div>
<span class="card-detail" id="dash-disk-detail"></span>
</div>
<div class="dash-card span2">
<div class="card-top"><span class="card-label">Load Average</span></div>
<p class="card-value" id="dash-load">—</p>
<span class="card-detail">1m / 5m / 15m</span>
</div>
<div class="dash-card span2">
<div class="card-top"><span class="card-label">Network</span></div>
<p class="card-value" id="dash-net">—</p>
<span class="card-detail" id="dash-net-detail"></span>
</div>
<div class="dash-card span2">
<div class="card-top"><span class="card-label">Processes</span></div>
<p class="card-value" id="dash-procs">—</p>
<span class="card-detail">running</span>
</div>
<div class="dash-card span2">
<div class="card-top"><span class="card-label">Swap</span></div>
<p class="card-value" id="dash-swap-val">—</p>
<div class="card-bar-wrap">
<div class="card-bar-fill swap" id="dash-swap-bar" style="width:0%"></div>
</div>
<span class="card-detail" id="dash-swap-detail"></span>
</div>
<div class="dash-card span3">
<div class="card-top"><span class="card-label">CPU</span></div>
<p class="card-value" id="dash-cpu-val">—</p>
<div class="card-bar-wrap">
<div class="card-bar-fill cpu" id="dash-cpu-bar" style="width:0%"></div>
</div>
</div>
<div class="dash-card span3">
<div class="card-top"><span class="card-label">Memory</span></div>
<p class="card-value" id="dash-ram-val">—</p>
<div class="card-bar-wrap">
<div class="card-bar-fill ram" id="dash-ram-bar" style="width:0%"></div>
</div>
<span class="card-detail" id="dash-ram-detail"></span>
</div>
<div class="dash-card span6">
<div class="card-top"><span class="card-label">System Info</span></div>
<pre class="card-fetch" id="dash-fetch">—</pre>
</div>
</div>
</section> </section>
<section id="calendar" class="tab-content"> <section id="calendar" class="tab-content">
@@ -235,6 +172,14 @@
</div> </div>
<a class="svc-btn" href="https://git.userevolt.app" target="_blank" rel="noopener">Visit &rarr;</a> <a class="svc-btn" href="https://git.userevolt.app" target="_blank" rel="noopener">Visit &rarr;</a>
</article> </article>
<article class="svc-banner" style="--brand: #4bbbe8">
<img class="svc-logo" src="textures/vega_emblem.svg" alt="">
<div class="svc-info">
<h2 class="svc-name">VEGA</h2>
<p class="svc-desc">Uptime and status page for my home server.</p>
</div>
<a class="svc-btn" href="https://status.userevolt.app" target="_blank" rel="noopener">Visit &rarr;</a>
</article>
</div> </div>
</section> </section>
@@ -252,7 +197,6 @@
<script src="https://www.gstatic.com/firebasejs/10.12.0/firebase-app-compat.js"></script> <script src="https://www.gstatic.com/firebasejs/10.12.0/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/10.12.0/firebase-firestore-compat.js"></script> <script src="https://www.gstatic.com/firebasejs/10.12.0/firebase-firestore-compat.js"></script>
<script src="js/comments.js"></script> <script src="js/comments.js"></script>
<script src="js/yuukabot.js"></script>
<script src="js/calendar.js"></script> <script src="js/calendar.js"></script>
<script src="js/bucketlist.js"></script> <script src="js/bucketlist.js"></script>
</body> </body>
+10 -2
View File
@@ -8,9 +8,10 @@ document.addEventListener('DOMContentLoaded', () => {
function pathToTab(path) { function pathToTab(path) {
const slug = path.replace(/^\/+|\/+$/g, '') || 'about'; const slug = path.replace(/^\/+|\/+$/g, '') || 'about';
const valid = ['about', 'gallery', 'bucketlist', 'yuukabot', 'calendar', 'services']; const valid = ['about', 'gallery', 'bucketlist', 'status', 'calendar', 'services'];
// old links // old links
if (slug === 'ahmet') return 'bucketlist'; if (slug === 'ahmet') return 'bucketlist';
if (slug === 'yuukabot') return 'status';
return valid.includes(slug) ? slug : 'about'; return valid.includes(slug) ? slug : 'about';
} }
@@ -24,7 +25,7 @@ document.addEventListener('DOMContentLoaded', () => {
const tabVideos = { const tabVideos = {
calendar: calVideo, calendar: calVideo,
bucketlist: bucketlistVideo, bucketlist: bucketlistVideo,
yuukabot: botVideo, status: botVideo,
services: botVideo services: botVideo
}; };
@@ -45,6 +46,7 @@ document.addEventListener('DOMContentLoaded', () => {
if (topLine) { if (topLine) {
topLine.classList.toggle('cal-theme', tabId === 'calendar'); topLine.classList.toggle('cal-theme', tabId === 'calendar');
topLine.classList.toggle('bucketlist-theme', tabId === 'bucketlist'); topLine.classList.toggle('bucketlist-theme', tabId === 'bucketlist');
topLine.classList.toggle('status-theme', tabId === 'status');
} }
} }
@@ -56,6 +58,12 @@ document.addEventListener('DOMContentLoaded', () => {
if (target) target.style.display = 'block'; if (target) target.style.display = 'block';
setBgForTab(tabId); setBgForTab(tabId);
// VEGA polls every 2s, so only load it once someone opens the tab
const statusFrame = document.getElementById('status-frame');
if (tabId === 'status' && statusFrame && !statusFrame.src) {
statusFrame.src = 'https://status.userevolt.app/';
}
// tab name next to the hamburger on mobile // tab name next to the hamburger on mobile
const btn = document.getElementById(tabId + '-btn'); const btn = document.getElementById(tabId + '-btn');
if (navCurrent && btn) navCurrent.textContent = btn.textContent; if (navCurrent && btn) navCurrent.textContent = btn.textContent;
-97
View File
@@ -1,97 +0,0 @@
// bot status dashboard
(() => {
const FIREBASE_CONFIG = {
apiKey: "AIzaSyDuSjEGEKx5FnWYnQq8f_owbpYRBRrl5x0",
authDomain: "esef-514bf.firebaseapp.com",
projectId: "esef-514bf",
storageBucket: "esef-514bf.firebasestorage.app",
messagingSenderId: "353969651290",
appId: "1:353969651290:web:41e3aaf8e54c743702a263"
};
// bot updates every 10s, nothing for a minute means it's probably dead
const STALE_MS = 60 * 1000;
document.addEventListener("DOMContentLoaded", () => {
const dash = document.getElementById("yuukabot");
if (!dash) return;
if (!firebase.apps.length) firebase.initializeApp(FIREBASE_CONFIG);
const db = firebase.firestore();
const dot = document.getElementById("dash-status-dot");
let online = false;
let updatedAt = null;
let loaded = false; // dot stays grey until the first data
function refreshDot() {
if (!loaded) return;
const fresh = updatedAt == null || Date.now() - updatedAt < STALE_MS;
if (dot) dot.className = online && fresh ? "status-dot" : "status-dot offline";
}
// a crashed bot stops sending updates so keep checking
setInterval(refreshDot, 5000);
db.collection("sysinfo").doc("server").onSnapshot(doc => {
loaded = true;
const d = doc.exists ? doc.data() : {};
online = !!d.online;
updatedAt = d.updatedAt ? d.updatedAt.toMillis() : null;
refreshDot();
if (!doc.exists) return;
setText("dash-uptime", d.uptime);
setText("dash-bot-uptime", d.botUptime ? "bot up " + d.botUptime : "");
setBar("dash-cpu-val", "dash-cpu-bar", d.cpu);
setBar("dash-ram-val", "dash-ram-bar", d.ram);
setBar("dash-disk-val", "dash-disk-bar", d.disk);
setBar("dash-swap-val", "dash-swap-bar", d.swap);
setText("dash-ram-detail", usedOfTotal(d.ramUsed, d.ramTotal));
setText("dash-disk-detail", usedOfTotal(d.diskUsed, d.diskTotal));
setText("dash-swap-detail", usedOfTotal(d.swapUsed, d.swapTotal));
if (d.load1 != null) {
setText("dash-load", d.load1 + " / " + d.load5 + " / " + d.load15);
}
if (d.netSent) {
setText("dash-net", "sent " + d.netSent);
setText("dash-net-detail", "recv " + (d.netRecv || "—"));
}
if (d.processes != null) {
setText("dash-procs", d.processes.toLocaleString());
}
setText("dash-fetch", d.fetch);
}, () => {
loaded = true;
online = false;
refreshDot();
});
});
function usedOfTotal(used, total) {
return used ? used + " / " + total : "";
}
function setText(id, value) {
const el = document.getElementById(id);
if (el && value != null) el.textContent = value;
}
function setBar(valId, barId, value) {
const valEl = document.getElementById(valId);
const barEl = document.getElementById(barId);
if (valEl && value != null) {
valEl.textContent = value;
const unit = document.createElement("span");
unit.textContent = "%";
valEl.appendChild(unit);
}
if (barEl) {
barEl.style.width = Math.min(Math.max(value || 0, 0), 100) + "%";
}
}
})();
+35 -1
View File
@@ -91,6 +91,19 @@ html, body {
transition: border-color 0.4s ease, color 0.4s ease; transition: border-color 0.4s ease, color 0.4s ease;
} }
/* status theme (VEGA colours) */
#top-line.status-theme {
background-color: #03070b;
border-bottom: 1px solid rgba(75, 187, 232, .28);
}
#top-line.status-theme #nav-tabs button {
border-bottom-color: #4bbbe8;
border-left-color: #4bbbe8;
border-right-color: #4bbbe8;
color: #a6e4ff;
transition: border-color 0.4s ease, color 0.4s ease;
}
h1 { h1 {
font-size: 3rem; font-size: 3rem;
color: #000000; color: #000000;
@@ -186,7 +199,8 @@ img {
#nav-tabs button, #nav-tabs button,
#top-line.cal-theme #nav-tabs button, #top-line.cal-theme #nav-tabs button,
#top-line.bucketlist-theme #nav-tabs button { #top-line.bucketlist-theme #nav-tabs button,
#top-line.status-theme #nav-tabs button {
width: 100%; width: 100%;
margin: 0; margin: 0;
padding: 12px 24px; padding: 12px 24px;
@@ -205,6 +219,7 @@ img {
} }
#top-line.cal-theme #nav-tabs button:hover { border-left-color: #FBC4CC; } #top-line.cal-theme #nav-tabs button:hover { border-left-color: #FBC4CC; }
#top-line.bucketlist-theme #nav-tabs button:hover { border-left-color: #B84457; } #top-line.bucketlist-theme #nav-tabs button:hover { border-left-color: #B84457; }
#top-line.status-theme #nav-tabs button:hover { border-left-color: #4bbbe8; }
/* keep the video centered on tall screens */ /* keep the video centered on tall screens */
#background-video, #background-video,
@@ -221,3 +236,22 @@ img {
h1 { font-size: 2.2rem; } h1 { font-size: 2.2rem; }
p { font-size: 1.2rem; } p { font-size: 1.2rem; }
} }
/* status tab: VEGA page fills everything under the top line */
#status { padding: 0; }
#status-frame {
position: fixed;
top: 115px;
left: 0;
width: 100%;
height: calc(100% - 115px);
border: 0;
background: #05080c;
}
@media (max-width: 900px) {
#status-frame {
top: 56px;
height: calc(100% - 56px);
}
}
-155
View File
@@ -1,155 +0,0 @@
/* grid settings */
:root {
--dash-columns: 6;
--dash-gap: 20px;
--dash-min-card-height: 200px;
--dash-max-width: none;
}
/* tab header */
.dash-header {
padding: 120px 20px 30px;
text-align: center;
}
.dash-header h1 {
font-size: 2.8rem;
color: #fff;
margin: 0 0 6px;
text-shadow: 0 0 30px rgba(91, 111, 222, 0.5);
}
.dash-header .status-dot {
display: inline-block;
width: 14px; height: 14px;
border-radius: 50%;
background: #22c55e;
margin-right: 8px;
box-shadow: 0 0 12px #22c55e;
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { box-shadow: 0 0 8px #22c55e; }
50% { box-shadow: 0 0 20px #22c55e, 0 0 40px rgba(34,197,94,0.4); }
}
.dash-header .offline { background: #ef4444; box-shadow: 0 0 12px #ef4444; animation: none; }
.dash-header .pending { background: #64748b; box-shadow: none; animation: none; }
/* card grid */
.dash-grid {
display: grid;
grid-template-columns: repeat(var(--dash-columns), 1fr);
gap: var(--dash-gap);
max-width: var(--dash-max-width);
margin: 0 auto;
padding: 0 48px 60px;
}
/* glass card */
.dash-card {
background: rgba(15, 15, 35, 0.55);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
border: 1px solid rgba(91, 111, 222, 0.2);
border-radius: 16px;
padding: 28px 30px;
min-height: var(--dash-min-card-height);
display: flex;
flex-direction: column;
justify-content: space-between;
transition: border-color 0.3s, box-shadow 0.3s;
}
.dash-card:hover {
border-color: rgba(91, 111, 222, 0.5);
box-shadow: 0 6px 28px rgba(91, 111, 222, 0.12);
}
/* card header */
.card-top {
display: flex;
align-items: center;
gap: 12px;
}
.card-label {
font-size: 0.8rem;
text-transform: uppercase;
letter-spacing: 1.5px;
color: rgba(255, 255, 255, 0.45);
font-family: Arial, Helvetica, sans-serif;
}
/* card value */
.card-value {
font-size: 3rem;
font-weight: bold;
color: #fff;
margin: 0;
line-height: 1;
}
.card-value span {
font-size: 1.2rem;
color: rgba(255, 255, 255, 0.4);
font-weight: 400;
}
/* progress bar */
.card-bar-wrap {
width: 100%;
height: 8px;
background: rgba(255, 255, 255, 0.08);
border-radius: 4px;
overflow: hidden;
margin-top: 12px;
}
.card-bar-fill {
height: 100%;
border-radius: 4px;
transition: width 0.8s ease;
}
.card-bar-fill.cpu { background: linear-gradient(90deg, #5b6fde, #818cf8); }
.card-bar-fill.ram { background: linear-gradient(90deg, #a78bfa, #c4b5fd); }
.card-bar-fill.disk { background: linear-gradient(90deg, #34d399, #6ee7b7); }
.card-bar-fill.swap { background: linear-gradient(90deg, #f59e0b, #fbbf24); }
/* detail text */
.card-detail {
font-size: 0.78rem;
color: rgba(255, 255, 255, 0.3);
font-family: Arial, Helvetica, sans-serif;
margin-top: 6px;
}
/* fastfetch text block */
.card-fetch {
margin: 12px 0 0;
font-family: "Cascadia Code", "Fira Code", "JetBrains Mono", Consolas, monospace;
font-size: 0.78rem;
color: rgba(255, 255, 255, 0.7);
white-space: pre-wrap;
line-height: 1.6;
overflow: hidden;
}
/* card widths */
.dash-card.span2 { grid-column: span 2; } /* 3 per row */
.dash-card.span3 { grid-column: span 3; } /* 2 per row */
.dash-card.span6 { grid-column: span 6; } /* full width */
/* mobile */
/* 2 columns on tablets, 1 on phones */
@media (max-width: 900px) {
:root {
--dash-columns: 2;
--dash-gap: 12px;
--dash-min-card-height: 130px;
}
.dash-header { padding: 72px 12px 20px; }
.dash-header h1 { font-size: 2rem; }
.dash-grid { padding: 0 4px 30px; }
.dash-card { padding: 20px; }
.dash-card.span2,
.dash-card.span3 { grid-column: span 1; }
.dash-card.span6 { grid-column: 1 / -1; }
.card-value { font-size: 2.2rem; }
}
@media (max-width: 575px) {
:root { --dash-columns: 1; }
}
+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" shape-rendering="geometricPrecision"><circle cx="100" cy="100" r="94" fill="#0b161f"/><circle cx="100" cy="100" r="93" fill="none" stroke="#24384a" stroke-width="2"/><circle cx="100" cy="100" r="80" fill="#040a10"/><path d="M51.36 37.75 L41.51 25.14" stroke="#020509" stroke-width="3"/><path d="M178.23 89.01 L194.08 86.78" stroke="#020509" stroke-width="3"/><path d="M70.41 173.25 L64.41 188.08" stroke="#020509" stroke-width="3"/><g class="spin"><g transform="rotate(0 100 100)"><path d="M137.09 38.99 A71.4 71.4 0 0 0 80.20 31.40 A3.5 3.5 0 0 0 82.14 38.13 A64.4 64.4 0 0 1 133.46 44.97 Z" fill="#4bbbe8" stroke="#4bbbe8" stroke-width="8" stroke-linejoin="round"/><path d="M92.41 29.00 A71.4 71.4 0 0 0 80.20 31.40 A3.5 3.5 0 0 0 82.14 38.13 A64.4 64.4 0 0 1 93.16 35.96 Z" fill="#2a78d8" stroke="#2a78d8" stroke-width="8" stroke-linejoin="round"/><path d="M138.40 39.80 A71.4 71.4 0 0 1 170.92 91.75 L147.48 94.48 A47.8 47.8 0 0 0 125.71 59.70 Z" fill="#4bbbe8" stroke="#4bbbe8" stroke-width="8" stroke-linejoin="round"/><rect x="93.59" y="49.47" width="22" height="7.5" rx="3.75" fill="#4bbbe8" transform="rotate(365.6 104.59 53.22)"/></g><g transform="rotate(120 100 100)"><path d="M137.09 38.99 A71.4 71.4 0 0 0 80.20 31.40 A3.5 3.5 0 0 0 82.14 38.13 A64.4 64.4 0 0 1 133.46 44.97 Z" fill="#4bbbe8" stroke="#4bbbe8" stroke-width="8" stroke-linejoin="round"/><path d="M92.41 29.00 A71.4 71.4 0 0 0 80.20 31.40 A3.5 3.5 0 0 0 82.14 38.13 A64.4 64.4 0 0 1 93.16 35.96 Z" fill="#2a78d8" stroke="#2a78d8" stroke-width="8" stroke-linejoin="round"/><path d="M138.40 39.80 A71.4 71.4 0 0 1 170.92 91.75 L147.48 94.48 A47.8 47.8 0 0 0 125.71 59.70 Z" fill="#4bbbe8" stroke="#4bbbe8" stroke-width="8" stroke-linejoin="round"/><rect x="93.59" y="49.47" width="22" height="7.5" rx="3.75" fill="#4bbbe8" transform="rotate(365.6 104.59 53.22)"/></g><g transform="rotate(240 100 100)"><path d="M137.09 38.99 A71.4 71.4 0 0 0 80.20 31.40 A3.5 3.5 0 0 0 82.14 38.13 A64.4 64.4 0 0 1 133.46 44.97 Z" fill="#4bbbe8" stroke="#4bbbe8" stroke-width="8" stroke-linejoin="round"/><path d="M92.41 29.00 A71.4 71.4 0 0 0 80.20 31.40 A3.5 3.5 0 0 0 82.14 38.13 A64.4 64.4 0 0 1 93.16 35.96 Z" fill="#2a78d8" stroke="#2a78d8" stroke-width="8" stroke-linejoin="round"/><path d="M138.40 39.80 A71.4 71.4 0 0 1 170.92 91.75 L147.48 94.48 A47.8 47.8 0 0 0 125.71 59.70 Z" fill="#4bbbe8" stroke="#4bbbe8" stroke-width="8" stroke-linejoin="round"/><rect x="93.59" y="49.47" width="22" height="7.5" rx="3.75" fill="#4bbbe8" transform="rotate(365.6 104.59 53.22)"/></g><circle cx="100" cy="100" r="42" fill="#040a10"/></g><circle cx="100" cy="100" r="29" fill="none" stroke="#3a4f92" stroke-width="2.6"/><circle class="core" cx="100" cy="100" r="20" fill="#5fcfd8"/></svg>

After

Width:  |  Height:  |  Size: 2.7 KiB