mirror of
https://github.com/asimonson1125/asimonson1125.github.io.git
synced 2026-09-22 11:35:33 -05:00
clean up clean up everybody do your share
This commit is contained in:
@@ -271,6 +271,10 @@ tr {
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.navElement + .navElement {
|
||||
border-left: 1px solid rgba(var(--accent-rgb), 0.4);
|
||||
}
|
||||
|
||||
.navElement {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
@@ -786,6 +790,7 @@ tr {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
color: inherit;
|
||||
background: currentColor;
|
||||
box-shadow: 0 0 6px currentColor;
|
||||
flex-shrink: 0;
|
||||
@@ -1402,7 +1407,8 @@ tr {
|
||||
}
|
||||
|
||||
.navElement + .navElement {
|
||||
border-top: 1px solid rgba(var(--accent-rgb), 0.1);
|
||||
border-top: 1px solid rgba(var(--accent-rgb), 0.25);
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.navElement * {
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.hiddenup {
|
||||
max-height: 0px !important;
|
||||
}
|
||||
|
||||
.checkbox-wrapper > div {
|
||||
display: inline-block;
|
||||
margin-right: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.checkbox-wrapper > div:last-child {
|
||||
margin-bottom: 0;;
|
||||
}
|
||||
|
||||
.checkbox-wrapper .switch {
|
||||
display: flex;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.checkbox-wrapper .switch > * {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.checkbox-wrapper .switch input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
.checkbox-wrapper .slider {
|
||||
background-color: #ccc;
|
||||
transition: 0.4s;
|
||||
height: 34px;
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
.checkbox-wrapper .slider:before {
|
||||
background-color: #fff;
|
||||
bottom: 4px;
|
||||
content: "";
|
||||
height: 26px;
|
||||
left: 4px;
|
||||
position: absolute;
|
||||
transition: 0.4s;
|
||||
width: 26px;
|
||||
}
|
||||
|
||||
.checkbox-wrapper input:checked+.slider {
|
||||
background-color: #66bb6a;
|
||||
}
|
||||
|
||||
.checkbox-wrapper input:checked+.slider:before {
|
||||
transform: translateX(26px);
|
||||
}
|
||||
|
||||
.checkbox-wrapper .slider.round {
|
||||
border-radius: 34px;
|
||||
}
|
||||
|
||||
.checkbox-wrapper .slider.round:before {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.checkbox-wrapper strong {
|
||||
margin-left: .5em;
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
function toggleCheckbox(dir) {
|
||||
let toggles = document.querySelectorAll(
|
||||
".checkbox-wrapper input[type=checkbox]"
|
||||
);
|
||||
let allow = [];
|
||||
toggles.forEach(function (x) {
|
||||
if (x.checked) {
|
||||
allow.push(x.id);
|
||||
}
|
||||
});
|
||||
let list = document.querySelectorAll(".checkbox-client > div");
|
||||
if (allow.length === 0) {
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
list[i].classList.remove("hidden" + dir);
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
list[i].classList.remove("hidden" + dir);
|
||||
for (let x = 0; x < allow.length; x++) {
|
||||
if (!list[i].classList.contains(allow[x])) {
|
||||
list[i].classList.add("hidden" + dir);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function activeSkill(obj) {
|
||||
let skill = obj.closest(".skill");
|
||||
if (skill.classList.contains("activeSkill")) {
|
||||
skill.classList.remove("activeSkill");
|
||||
return;
|
||||
}
|
||||
while (skill) {
|
||||
skill.classList.add("activeSkill");
|
||||
skill = skill.parentElement.closest(".skill");
|
||||
}
|
||||
}
|
||||
@@ -7,17 +7,21 @@ async function addChessEmbed(username) {
|
||||
setChess({ cName: "Chess.com request failed" });
|
||||
return;
|
||||
}
|
||||
|
||||
if (user.status === 200) {
|
||||
user = await user.json();
|
||||
stats = await stats.json();
|
||||
const ratings = {
|
||||
rapid: stats.chess_rapid.last.rating,
|
||||
blitz: stats.chess_blitz.last.rating,
|
||||
bullet: stats.chess_bullet.last.rating,
|
||||
tactics: stats.tactics.highest.rating,
|
||||
};
|
||||
setChess({ cName: user["username"], pic: user.avatar, ratings: ratings });
|
||||
} else if (user === null || user.status === 403 || user.status === null) {
|
||||
setChess({
|
||||
cName: user["username"],
|
||||
pic: user.avatar,
|
||||
ratings: {
|
||||
rapid: stats.chess_rapid.last.rating,
|
||||
blitz: stats.chess_blitz.last.rating,
|
||||
bullet: stats.chess_bullet.last.rating,
|
||||
tactics: stats.tactics.highest.rating,
|
||||
},
|
||||
});
|
||||
} else if (user.status === 403) {
|
||||
setChess({ cName: "Chess.com request failed" });
|
||||
} else {
|
||||
setChess({ cName: "User Not Found" });
|
||||
@@ -33,16 +37,12 @@ function setChess({ cName = null, pic = null, ratings = null }) {
|
||||
document.querySelector(".chessImage").src = pic;
|
||||
}
|
||||
if (ratings) {
|
||||
document.querySelector(".chessRapid .chessStat").textContent =
|
||||
ratings.rapid;
|
||||
document.querySelector(".chessBlitz .chessStat").textContent =
|
||||
ratings.blitz;
|
||||
document.querySelector(".chessBullet .chessStat").textContent =
|
||||
ratings.bullet;
|
||||
document.querySelector(".chessPuzzles .chessStat").textContent =
|
||||
ratings.tactics;
|
||||
document.querySelector(".chessRapid .chessStat").textContent = ratings.rapid;
|
||||
document.querySelector(".chessBlitz .chessStat").textContent = ratings.blitz;
|
||||
document.querySelector(".chessBullet .chessStat").textContent = ratings.bullet;
|
||||
document.querySelector(".chessPuzzles .chessStat").textContent = ratings.tactics;
|
||||
}
|
||||
} catch {
|
||||
console.log("fucker clicking so fast the internet can't even keep up");
|
||||
console.warn("Chess DOM elements not available (navigated away during fetch)");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,9 @@ const density = 0.00005;
|
||||
let screenWidth = window.innerWidth + 10;
|
||||
let screenHeight = window.innerHeight + 10;
|
||||
|
||||
const MAX_DIST = 150;
|
||||
const MAX_DIST_SQUARED = MAX_DIST * MAX_DIST;
|
||||
|
||||
class Ball {
|
||||
constructor(x, y, size, speed, angle) {
|
||||
this.x = x;
|
||||
@@ -14,8 +17,9 @@ class Ball {
|
||||
}
|
||||
|
||||
calcChange() {
|
||||
this.xSpeed = this.speed * Math.sin((this.angle * Math.PI) / 180);
|
||||
this.ySpeed = this.speed * Math.cos((this.angle * Math.PI) / 180);
|
||||
const radians = (this.angle * Math.PI) / 180
|
||||
this.xSpeed = this.speed * Math.sin(radians);
|
||||
this.ySpeed = this.speed * Math.cos(radians);
|
||||
}
|
||||
|
||||
update() {
|
||||
@@ -44,19 +48,17 @@ class Ball {
|
||||
|
||||
function setup() {
|
||||
frameRate(15);
|
||||
const pix = screenHeight * screenWidth;
|
||||
const pixels = screenHeight * screenWidth;
|
||||
createCanvas(screenWidth, screenHeight);
|
||||
for (let i = 0; i < pix * density; i++) {
|
||||
let thisBall = new Ball(
|
||||
for (let i = 0; i < pixels * density; i++) {
|
||||
balls.push(new Ball(
|
||||
random(screenWidth),
|
||||
random(screenHeight),
|
||||
random(6) + 3,
|
||||
Math.exp(random(4) + 3) / 1000 + 1,
|
||||
random(360)
|
||||
);
|
||||
balls.push(thisBall);
|
||||
));
|
||||
}
|
||||
|
||||
stroke(255);
|
||||
}
|
||||
|
||||
@@ -69,42 +71,31 @@ function windowResized() {
|
||||
function draw() {
|
||||
background(24);
|
||||
|
||||
// Update all balls
|
||||
for (let i = 0; i < balls.length; i++) {
|
||||
balls[i].update();
|
||||
}
|
||||
|
||||
// Draw lines with additive blending so overlaps increase brightness
|
||||
// Draw connection lines with additive blending so overlaps brighten
|
||||
blendMode(ADD);
|
||||
strokeWeight(2);
|
||||
|
||||
const maxDist = 150;
|
||||
const maxDistSquared = maxDist * maxDist;
|
||||
|
||||
for (let i = 0; i < balls.length - 1; i++) {
|
||||
const ball1 = balls[i];
|
||||
const a = balls[i];
|
||||
for (let j = i + 1; j < balls.length; j++) {
|
||||
const ball2 = balls[j];
|
||||
|
||||
const dx = ball2.x - ball1.x;
|
||||
const dy = ball2.y - ball1.y;
|
||||
const b = balls[j];
|
||||
const dx = b.x - a.x;
|
||||
const dy = b.y - a.y;
|
||||
const distSquared = dx * dx + dy * dy;
|
||||
|
||||
if (distSquared < maxDistSquared) {
|
||||
if (distSquared < MAX_DIST_SQUARED) {
|
||||
const distance = Math.sqrt(distSquared);
|
||||
|
||||
if (distance < 75) {
|
||||
stroke(255, 85);
|
||||
line(ball1.x, ball1.y, ball2.x, ball2.y);
|
||||
} else {
|
||||
const chance = 0.3 ** (((random(0.2) + 0.8) * distance) / 150);
|
||||
if (chance < 0.5) {
|
||||
stroke(255, 40);
|
||||
} else {
|
||||
stroke(255, 75);
|
||||
}
|
||||
line(ball1.x, ball1.y, ball2.x, ball2.y);
|
||||
const chance = 0.3 ** (((random(0.2) + 0.8) * distance) / MAX_DIST);
|
||||
stroke(255, chance < 0.5 ? 40 : 75);
|
||||
}
|
||||
line(a.x, a.y, b.x, b.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
function toggleMenu(collapse=false) {
|
||||
function toggleMenu(collapse) {
|
||||
if (window.innerWidth < 1400) {
|
||||
const e = document.querySelector(".navControl");
|
||||
const menu = document.querySelector(".navControl");
|
||||
const bar = document.querySelector(".header");
|
||||
const isCollapsed = !e.style.maxHeight || e.style.maxHeight === "0px";
|
||||
const isCollapsed = !menu.style.maxHeight || menu.style.maxHeight === "0px";
|
||||
if (isCollapsed && !collapse) {
|
||||
e.style.maxHeight = `${e.scrollHeight + 10}px`;
|
||||
menu.style.maxHeight = `${menu.scrollHeight + 10}px`;
|
||||
bar.style.borderBottomWidth = "0px";
|
||||
} else {
|
||||
e.style.maxHeight = "0px";
|
||||
menu.style.maxHeight = "0px";
|
||||
bar.style.borderBottomWidth = "3px";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function goto(location, { push = true } = {}) {
|
||||
let a;
|
||||
let response;
|
||||
try {
|
||||
a = await fetch("/api/goto/" + location, {
|
||||
response = await fetch("/api/goto/" + location, {
|
||||
credentials: "include",
|
||||
method: "GET",
|
||||
mode: "cors",
|
||||
});
|
||||
if (!a.ok) {
|
||||
console.error(`Navigation failed: HTTP ${a.status}`);
|
||||
if (!response.ok) {
|
||||
console.error(`Navigation failed: HTTP ${response.status}`);
|
||||
return;
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -32,29 +32,29 @@ async function goto(location, { push = true } = {}) {
|
||||
|
||||
document.dispatchEvent(new Event('beforenavigate'));
|
||||
|
||||
const response = await a.json();
|
||||
const metadata = response[0];
|
||||
const content = response[1];
|
||||
const [metadata, content] = await response.json();
|
||||
const root = document.getElementById("root");
|
||||
root.innerHTML = content;
|
||||
root.querySelectorAll("script").forEach((oldScript) => {
|
||||
|
||||
// Re-execute scripts injected via innerHTML (browser ignores them otherwise)
|
||||
root.querySelectorAll("script").forEach(function(oldScript) {
|
||||
const newScript = document.createElement("script");
|
||||
Array.from(oldScript.attributes).forEach(attr => {
|
||||
Array.from(oldScript.attributes).forEach(function(attr) {
|
||||
newScript.setAttribute(attr.name, attr.value);
|
||||
});
|
||||
newScript.textContent = oldScript.textContent;
|
||||
oldScript.parentNode.replaceChild(newScript, oldScript);
|
||||
});
|
||||
|
||||
if (!window.location.href.includes("#")) {
|
||||
window.scrollTo({top: 0, left: 0, behavior:"instant"});
|
||||
} else {
|
||||
const eid = decodeURIComponent(window.location.hash.substring(1));
|
||||
const el = document.getElementById(eid);
|
||||
if (window.location.href.includes("#")) {
|
||||
const id = decodeURIComponent(window.location.hash.substring(1));
|
||||
const el = document.getElementById(id);
|
||||
if (el) el.scrollIntoView();
|
||||
} else {
|
||||
window.scrollTo({ top: 0, left: 0, behavior: "instant" });
|
||||
}
|
||||
|
||||
toggleMenu(collapse=true);
|
||||
toggleMenu(true);
|
||||
document.querySelector("title").textContent = metadata["title"];
|
||||
if (push) {
|
||||
history.pushState(null, null, metadata["canonical"]);
|
||||
@@ -62,6 +62,18 @@ async function goto(location, { push = true } = {}) {
|
||||
}
|
||||
|
||||
function backButton() {
|
||||
const location = window.location.pathname;
|
||||
goto(location.substring(1), { push: false }); // remove slash, goto already does that
|
||||
const path = window.location.pathname;
|
||||
goto(path.substring(1), { push: false });
|
||||
}
|
||||
|
||||
function activeSkill(obj) {
|
||||
let skill = obj.closest(".skill");
|
||||
if (skill.classList.contains("activeSkill")) {
|
||||
skill.classList.remove("activeSkill");
|
||||
return;
|
||||
}
|
||||
while (skill) {
|
||||
skill.classList.add("activeSkill");
|
||||
skill = skill.parentElement.closest(".skill");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
// Fetch and display service status from API
|
||||
let statusIntervalId = null;
|
||||
|
||||
/**
|
||||
* Fetch status data from server
|
||||
*/
|
||||
async function fetchStatus() {
|
||||
try {
|
||||
const response = await fetch('/api/status');
|
||||
@@ -17,36 +14,26 @@ async function fetchStatus() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the status display with fetched data
|
||||
*/
|
||||
function updateStatusDisplay(data) {
|
||||
// Update last check time
|
||||
if (data.last_check) {
|
||||
const lastCheck = new Date(data.last_check);
|
||||
const timeString = lastCheck.toLocaleString();
|
||||
document.getElementById('lastUpdate').textContent = `Last checked: ${timeString}`;
|
||||
document.getElementById('lastUpdate').textContent = `Last checked: ${lastCheck.toLocaleString()}`;
|
||||
}
|
||||
|
||||
// Update next check time
|
||||
if (data.next_check) {
|
||||
const nextCheck = new Date(data.next_check);
|
||||
const timeString = nextCheck.toLocaleString();
|
||||
const nextCheckEl = document.getElementById('nextUpdate');
|
||||
if (nextCheckEl) {
|
||||
nextCheckEl.textContent = `Next check: ${timeString}`;
|
||||
const nextCheck = new Date(data.next_check);
|
||||
nextCheckEl.textContent = `Next check: ${nextCheck.toLocaleString()}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Update each service
|
||||
data.services.forEach(service => {
|
||||
data.services.forEach(function(service) {
|
||||
updateServiceCard(service);
|
||||
});
|
||||
|
||||
// Update overall status
|
||||
updateOverallStatus(data.services);
|
||||
|
||||
// Re-enable refresh button
|
||||
const refreshBtn = document.getElementById('refreshBtn');
|
||||
if (refreshBtn) {
|
||||
refreshBtn.disabled = false;
|
||||
@@ -54,9 +41,19 @@ function updateStatusDisplay(data) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a single service card
|
||||
*/
|
||||
function getUptimeClass(value) {
|
||||
if (value === null) return 'text-muted';
|
||||
if (value >= 99) return 'text-excellent';
|
||||
if (value >= 95) return 'text-good';
|
||||
if (value >= 90) return 'text-fair';
|
||||
return 'text-poor';
|
||||
}
|
||||
|
||||
function formatUptime(value, label) {
|
||||
const display = value !== null ? `${value}%` : '--';
|
||||
return `${label}: <strong class="${getUptimeClass(value)}">${display}</strong>`;
|
||||
}
|
||||
|
||||
function updateServiceCard(service) {
|
||||
const card = document.getElementById(`status-${service.id}`);
|
||||
if (!card) return;
|
||||
@@ -68,21 +65,14 @@ function updateServiceCard(service) {
|
||||
const uptimeDisplay = document.getElementById(`uptime-${service.id}`);
|
||||
const checksDisplay = document.getElementById(`checks-${service.id}`);
|
||||
|
||||
// Update response time
|
||||
if (service.response_time !== null) {
|
||||
timeDisplay.textContent = `${service.response_time}ms`;
|
||||
} else {
|
||||
timeDisplay.textContent = '--';
|
||||
}
|
||||
timeDisplay.textContent = service.response_time !== null ? `${service.response_time}ms` : '--';
|
||||
|
||||
// Update status code
|
||||
if (service.status_code !== null) {
|
||||
codeDisplay.textContent = service.status_code;
|
||||
} else {
|
||||
codeDisplay.textContent = service.status === 'unknown' ? 'Unknown' : 'Error';
|
||||
}
|
||||
|
||||
// Update status indicator
|
||||
card.classList.remove('online', 'degraded', 'offline', 'unknown');
|
||||
|
||||
switch (service.status) {
|
||||
@@ -108,44 +98,20 @@ function updateServiceCard(service) {
|
||||
card.classList.add('unknown');
|
||||
}
|
||||
|
||||
// Update uptime statistics
|
||||
if (uptimeDisplay && service.uptime) {
|
||||
const uptimeHTML = [];
|
||||
|
||||
// Helper function to get color class based on uptime percentage
|
||||
const getUptimeClass = (value) => {
|
||||
if (value === null) return 'text-muted';
|
||||
if (value >= 99) return 'text-excellent';
|
||||
if (value >= 95) return 'text-good';
|
||||
if (value >= 90) return 'text-fair';
|
||||
return 'text-poor';
|
||||
};
|
||||
|
||||
// Helper function to format uptime value
|
||||
const formatUptime = (value, label) => {
|
||||
const display = value !== null ? `${value}%` : '--';
|
||||
const colorClass = getUptimeClass(value);
|
||||
return `${label}: <strong class="${colorClass}">${display}</strong>`;
|
||||
};
|
||||
|
||||
// Add all uptime metrics
|
||||
uptimeHTML.push(formatUptime(service.uptime['24h'], '24h'));
|
||||
uptimeHTML.push(formatUptime(service.uptime['7d'], '7d'));
|
||||
uptimeHTML.push(formatUptime(service.uptime['30d'], '30d'));
|
||||
uptimeHTML.push(formatUptime(service.uptime.all_time, 'All'));
|
||||
|
||||
uptimeDisplay.innerHTML = uptimeHTML.join(' | ');
|
||||
uptimeDisplay.innerHTML = [
|
||||
formatUptime(service.uptime['24h'], '24h'),
|
||||
formatUptime(service.uptime['7d'], '7d'),
|
||||
formatUptime(service.uptime['30d'], '30d'),
|
||||
formatUptime(service.uptime.all_time, 'All'),
|
||||
].join(' | ');
|
||||
}
|
||||
|
||||
// Update total checks
|
||||
if (checksDisplay && service.total_checks !== undefined) {
|
||||
checksDisplay.textContent = service.total_checks;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update overall status bar
|
||||
*/
|
||||
function updateOverallStatus(services) {
|
||||
const overallBar = document.getElementById('overallStatus');
|
||||
const icon = overallBar.querySelector('.summary-icon');
|
||||
@@ -154,17 +120,14 @@ function updateOverallStatus(services) {
|
||||
const onlineCount = document.getElementById('onlineCount');
|
||||
const totalCount = document.getElementById('totalCount');
|
||||
|
||||
// Count service statuses
|
||||
const total = services.length;
|
||||
const online = services.filter(s => s.status === 'online').length;
|
||||
const degraded = services.filter(s => s.status === 'degraded' || s.status === 'timeout').length;
|
||||
const offline = services.filter(s => s.status === 'offline').length;
|
||||
const online = services.filter(function(s) { return s.status === 'online'; }).length;
|
||||
const degraded = services.filter(function(s) { return s.status === 'degraded' || s.status === 'timeout'; }).length;
|
||||
const offline = services.filter(function(s) { return s.status === 'offline'; }).length;
|
||||
|
||||
// Update counts
|
||||
onlineCount.textContent = online;
|
||||
totalCount.textContent = total;
|
||||
|
||||
// Remove all status classes
|
||||
overallBar.classList.remove('online', 'degraded', 'offline');
|
||||
icon.classList.remove('operational', 'partial', 'major', 'loading');
|
||||
|
||||
@@ -205,9 +168,6 @@ function updateOverallStatus(services) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show error message
|
||||
*/
|
||||
function showError(message) {
|
||||
const errorDiv = document.createElement('div');
|
||||
errorDiv.className = 'status-error';
|
||||
@@ -217,13 +177,10 @@ function showError(message) {
|
||||
const container = document.querySelector('.foregroundContent');
|
||||
if (container) {
|
||||
container.insertBefore(errorDiv, container.firstChild);
|
||||
setTimeout(() => errorDiv.remove(), 5000);
|
||||
setTimeout(function() { errorDiv.remove(); }, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manual refresh
|
||||
*/
|
||||
function refreshStatus() {
|
||||
const refreshBtn = document.getElementById('refreshBtn');
|
||||
if (refreshBtn) {
|
||||
@@ -233,30 +190,22 @@ function refreshStatus() {
|
||||
fetchStatus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize on page load
|
||||
*/
|
||||
var statusIntervalId = null;
|
||||
|
||||
function initStatusPage() {
|
||||
// Clear any existing interval from a previous SPA navigation
|
||||
if (statusIntervalId !== null) {
|
||||
clearInterval(statusIntervalId);
|
||||
}
|
||||
fetchStatus();
|
||||
// Auto-refresh every 1 minute to get latest data
|
||||
statusIntervalId = setInterval(fetchStatus, 60000);
|
||||
}
|
||||
|
||||
// Clean up interval when navigating away via SPA
|
||||
document.addEventListener('beforenavigate', () => {
|
||||
// Clean up polling interval when navigating away via SPA
|
||||
document.addEventListener('beforenavigate', function() {
|
||||
if (statusIntervalId !== null) {
|
||||
clearInterval(statusIntervalId);
|
||||
statusIntervalId = null;
|
||||
}
|
||||
});
|
||||
|
||||
// Start when page loads
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initStatusPage);
|
||||
} else {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"status": "complete",
|
||||
"classes": "geospacial",
|
||||
"bgi": "watershedTemps.png",
|
||||
"content": "Geospacial analysis of Maryland's Antietam and Conococheague sub-watersheds, monitoring water quality and temperatures through the summer months for reporting to governmental review boards for environmental protection"
|
||||
"content": "Live geospacial analysis of Maryland's Antietam and Conococheague sub-watersheds, monitoring water quality and temperatures through the summer months for governmental environment health review boards."
|
||||
},
|
||||
"Automotive Brand Valuation Analysis": {
|
||||
"status": "complete",
|
||||
|
||||
Reference in New Issue
Block a user