first commit
175
.gitignore
vendored
Normal file
@ -0,0 +1,175 @@
|
||||
# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
|
||||
|
||||
# Logs
|
||||
|
||||
logs
|
||||
_.log
|
||||
npm-debug.log_
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Caches
|
||||
|
||||
.cache
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
|
||||
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||
|
||||
# Runtime data
|
||||
|
||||
pids
|
||||
_.pid
|
||||
_.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
|
||||
.temp
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
# IntelliJ based IDEs
|
||||
.idea
|
||||
|
||||
# Finder (MacOS) folder config
|
||||
.DS_Store
|
BIN
.unused/bg.png
Normal file
After Width: | Height: | Size: 296 B |
11
.unused/dither copy.svg
Normal file
@ -0,0 +1,11 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="2vh"
|
||||
height="2vh"
|
||||
>
|
||||
<rect x="0" y="0" width="1vh" height="1vh" fill="#262626"/>
|
||||
<rect x="1vh" y="0" width="1vh" height="1vh" fill="#242424"/>
|
||||
<rect x="0" y="1vh" width="1vh" height="1vh" fill="#242424"/>
|
||||
<rect x="1vh" y="1vh" width="1vh" height="1vh" fill="#262626"/>
|
||||
|
||||
</svg>
|
After Width: | Height: | Size: 345 B |
11
.unused/dither.svg
Normal file
@ -0,0 +1,11 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="10px"
|
||||
height="10px"
|
||||
>
|
||||
<rect x="5" y="0" width="5" height="5" fill="#212121"/>
|
||||
<rect x="0" y="0" width="5" height="5" fill="#262626"/>
|
||||
<rect x="0" y="5" width="5" height="5" fill="#212121"/>
|
||||
<rect x="5" y="5" width="5" height="5" fill="#262626"/>
|
||||
|
||||
</svg>
|
After Width: | Height: | Size: 339 B |
11
.unused/dithertest1.svg
Normal file
@ -0,0 +1,11 @@
|
||||
<svg class="dithering-pattern" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<pattern id="dither" patternUnits="userSpaceOnUse" width="8" height="8">
|
||||
<rect width="4" height="4" fill="#232323"></rect>
|
||||
<rect x="4" y="4" width="4" height="4" fill="#505758"></rect>
|
||||
<rect x="4" width="4" height="4" fill="#232323"></rect>
|
||||
<rect y="4" width="4" height="4" fill="#232323"></rect>
|
||||
</pattern>
|
||||
</defs>
|
||||
<rect width="100%" height="100%" fill="url(#dither)"></rect>
|
||||
</svg>
|
After Width: | Height: | Size: 517 B |
23
.unused/index2.html
Normal file
@ -0,0 +1,23 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>SVG Background</title>
|
||||
<style>
|
||||
/* CSS to apply background image */
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-image: url('noise.svg');
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>hi :3</h1>>
|
||||
</body>
|
||||
</html>
|
67
.unused/noise copy.svg
Normal file
@ -0,0 +1,67 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:svgjs="http://svgjs.dev/svgjs"
|
||||
|
||||
viewBox="0 0 700 700"
|
||||
width="700"
|
||||
height="700"
|
||||
|
||||
opacity="1">
|
||||
<defs>
|
||||
<filter
|
||||
id="noise-filter"
|
||||
x="-20%"
|
||||
y="-20%"
|
||||
width="140%"
|
||||
height="140%"
|
||||
filterUnits="objectBoundingBox"
|
||||
primitiveUnits="userSpaceOnUse"
|
||||
color-interpolation-filters="linearRGB">
|
||||
|
||||
<feTurbulence
|
||||
type="fractalNoise"
|
||||
baseFrequency="0.1"
|
||||
numOctaves="10" seed="2"
|
||||
stitchTiles="stitch"
|
||||
x="0%"
|
||||
y="0%"
|
||||
width="100%"
|
||||
height="100%"
|
||||
result="turbulence">
|
||||
</feTurbulence>
|
||||
|
||||
<feSpecularLighting
|
||||
surfaceScale="14"
|
||||
specularConstant="1.3"
|
||||
specularExponent="20"
|
||||
lighting-color="#232323"
|
||||
x="0%"
|
||||
y="0%"
|
||||
width="100%"
|
||||
height="100%"
|
||||
in="turbulence"
|
||||
result="specularLighting">
|
||||
<feDistantLight
|
||||
azimuth="3"
|
||||
elevation="96">
|
||||
</feDistantLight>
|
||||
</feSpecularLighting>
|
||||
</filter>
|
||||
</defs>
|
||||
|
||||
|
||||
<rect
|
||||
width="700"
|
||||
height="700"
|
||||
fill="#262626">
|
||||
</rect>
|
||||
|
||||
<rect
|
||||
width="700"
|
||||
height="700"
|
||||
fill="#232323"
|
||||
filter="url(#noise-filter)">
|
||||
</rect>
|
||||
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
51
.unused/noise.svg
Normal file
@ -0,0 +1,51 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:svgjs="http://svgjs.dev/svgjs"
|
||||
>
|
||||
|
||||
<defs>
|
||||
<!-- Define noise -->
|
||||
<filter id="noise-filter">
|
||||
<feTurbulence
|
||||
type="fractalNoise"
|
||||
baseFrequency="0.1"
|
||||
numOctaves="10"
|
||||
seed="2"
|
||||
stitchTiles="stitch"
|
||||
x="0%"
|
||||
y="0%"
|
||||
width="100%"
|
||||
height="100%"
|
||||
result="turbulence">
|
||||
</feTurbulence>
|
||||
<feSpecularLighting
|
||||
surfaceScale="14"
|
||||
specularConstant="1.3"
|
||||
specularExponent="20"
|
||||
lighting-color="#232323"
|
||||
x="0%"
|
||||
y="0%"
|
||||
width="100%"
|
||||
height="100%"
|
||||
in="turbulence"
|
||||
result="specularLighting">
|
||||
<feDistantLight
|
||||
azimuth="3"
|
||||
elevation="96"
|
||||
></feDistantLight>
|
||||
</feSpecularLighting>
|
||||
</filter>
|
||||
</defs>
|
||||
|
||||
<!-- Define the background -->
|
||||
<rect width="100%" height="100%" fill="#262626"></rect>
|
||||
|
||||
<!-- Apply noise -->
|
||||
<rect
|
||||
width="100%"
|
||||
height="100%"
|
||||
fill="#232323"
|
||||
filter="url(#noise-filter)"></rect>
|
||||
|
||||
</svg>
|
After Width: | Height: | Size: 1011 B |
37
404.html
Normal file
@ -0,0 +1,37 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&display=swap');
|
||||
</style>
|
||||
<title>quinten0508.com</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="container">
|
||||
|
||||
<div class="box" id="maintitlebox">
|
||||
<h1 id="maintitle">Quinten</h1>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div id="stripes">
|
||||
<img src="stripes.svg" id="stripes">
|
||||
</div>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- class -> .class and id -> #id in css
|
||||
use id for one-time and classes for re-useable stuff -->
|
BIN
assets/bg.gif
Normal file
After Width: | Height: | Size: 53 B |
BIN
assets/buttons/firefox.gif
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
assets/buttons/piracy.gif
Normal file
After Width: | Height: | Size: 910 B |
BIN
assets/buttons/yippeee.gif
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
assets/capy.jpg
Normal file
After Width: | Height: | Size: 299 KiB |
BIN
assets/cat-hammer-404.gif
Normal file
After Width: | Height: | Size: 7.2 MiB |
BIN
assets/fonts/Nintendo-DS-BIOS.ttf
Normal file
BIN
assets/fonts/ibm-plex-mono-v19-latin-500.woff2
Normal file
BIN
assets/fonts/ibm-plex-mono-v19-latin-500italic.woff2
Normal file
BIN
assets/fonts/ibm-plex-mono-v19-latin-italic.woff2
Normal file
BIN
assets/fonts/ibm-plex-mono-v19-latin-regular.woff2
Normal file
BIN
assets/icons/lastfm.png
Normal file
After Width: | Height: | Size: 6.3 KiB |
BIN
assets/icons/lastfm_small.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
assets/icons/moon_small.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
assets/icons/skull_small.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
assets/icons/sun_small.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
1
assets/icons/twitter.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24"><path fill="#E9E9E9" d="M19.913 5.322a1.034 1.034 0 0 1 .837 1.629l-1.042 1.481c-.064 5.086-1.765 8.539-5.056 10.264A10.9 10.9 0 0 1 9.6 19.835a12.23 12.23 0 0 1-6.2-1.524a.76.76 0 0 1-.317-.8a.77.77 0 0 1 .63-.6a20.6 20.6 0 0 0 3.745-.886C2 13.5 3.19 7.824 3.71 6.081a1.028 1.028 0 0 1 1.729-.422a9.93 9.93 0 0 0 5.995 2.95A4.19 4.19 0 0 1 12.725 5.3a4.125 4.125 0 0 1 5.7.02ZM4.521 17.794c1.862.872 6.226 1.819 9.667.016c2.955-1.549 4.476-4.732 4.521-9.461a.77.77 0 0 1 .142-.436l1.081-1.538l-.041-.053c-.518-.007-1.029-.014-1.55 0a.84.84 0 0 1-.547-.221a3.13 3.13 0 0 0-4.383-.072a3.17 3.17 0 0 0-.935 2.87a.65.65 0 0 1-.154.545a.59.59 0 0 1-.516.205a10.92 10.92 0 0 1-7.084-3.295c-.67 2.078-1.52 7.094 3.869 9.065a.63.63 0 0 1 .416.538a.63.63 0 0 1-.3.6a13.2 13.2 0 0 1-4.186 1.237m15.147-9.305"/></svg>
|
After Width: | Height: | Size: 892 B |
BIN
assets/image.png
Normal file
After Width: | Height: | Size: 23 MiB |
BIN
assets/oneko-tux-old.gif
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
assets/oneko-tux.gif
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
assets/oneko.gif
Normal file
After Width: | Height: | Size: 3.2 KiB |
27
assets/scripts/clock.js
Normal file
@ -0,0 +1,27 @@
|
||||
function updateClock() {
|
||||
const now = new Date().toLocaleString("en-US", {timeZone: "Europe/Amsterdam"});
|
||||
const cestTime = new Date(now);
|
||||
|
||||
let hours = cestTime.getHours();
|
||||
let minutes = cestTime.getMinutes();
|
||||
let seconds = cestTime.getSeconds();
|
||||
|
||||
hours = hours < 10 ? '0' + hours : hours;
|
||||
minutes = minutes < 10 ? '0' + minutes : minutes;
|
||||
seconds = seconds < 10 ? '0' + seconds : seconds;
|
||||
|
||||
|
||||
const timeString = hours + ':' + minutes + ':' + seconds;
|
||||
|
||||
|
||||
//12pm //am
|
||||
const isDaytime = hours >= 0 && hours > 7;
|
||||
const imageElement = document.getElementById('clock-icon');
|
||||
imageElement.src = isDaytime ? '/assets/icons/sun_small.png' : 'assets/icons/moon_small.png';
|
||||
document.getElementById('clock').textContent = timeString;
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
updateClock();
|
||||
setInterval(updateClock, 1000);
|
||||
});
|
42
assets/scripts/heartbeat.js
Normal file
@ -0,0 +1,42 @@
|
||||
document.addEventListener('DOMContentLoaded', async function() {
|
||||
async function fetchLastBeat() {
|
||||
|
||||
const heartbeatElement = document.getElementById('heartbeat-time');
|
||||
|
||||
try {
|
||||
const response = await fetch('https://quinten0508.com/api/heartbeat');
|
||||
const data = await response.json();
|
||||
const phoneDevice = data.find(device => device.device_name === 'Phone');
|
||||
if (phoneDevice) {
|
||||
const phoneTimestamp = phoneDevice.last_beat.timestamp;
|
||||
const timestampMilliseconds = phoneTimestamp * 1000;
|
||||
|
||||
const currentTime = Date.now();
|
||||
const difference = currentTime - timestampMilliseconds;
|
||||
|
||||
const isDead = difference > (1000 * 60 * 60 * 48);
|
||||
const online = difference < (1000 * 60 * 5);
|
||||
if (online) {
|
||||
heartbeatElement.textContent = 'Online!';
|
||||
heartbeatElement.style = 'color: #00b400';
|
||||
return;
|
||||
} else if (isDead) {
|
||||
heartbeatElement.textContent = 'Dead';
|
||||
heartbeatElement.style = 'color: #b30000';
|
||||
} else {
|
||||
heartbeatElement.textContent = 'Alive';
|
||||
heartbeatElement.style = 'color: #00b400';
|
||||
}
|
||||
|
||||
} else {
|
||||
console.error('Device "Phone" not found.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching last beat:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch the last beat immediately and then every 10 seconds
|
||||
fetchLastBeat();
|
||||
setInterval(fetchLastBeat, 10000);
|
||||
});
|
81
assets/scripts/lastfm.js
Normal file
@ -0,0 +1,81 @@
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const nowPlayingElement = document.getElementById('lastfm-contents');
|
||||
const lastfmArtElement = document.getElementById('lastfm-artbox');
|
||||
|
||||
function fetchNowPlaying() {
|
||||
fetch('https://quinten0508.com/api/nowplaying')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.recenttracks.track && data.recenttracks.track.length > 0) {
|
||||
const tracks = data.recenttracks.track;
|
||||
const nowPlaying = tracks[0];
|
||||
const lastPlayedSong = tracks[1];
|
||||
const lastlastPlayedSong = tracks[2];
|
||||
|
||||
if (nowPlaying['@attr'] && nowPlaying['@attr'].nowplaying) {
|
||||
const nowPlayingHtml = `
|
||||
<strong>Now Playing:</strong><br>
|
||||
<span id="lastfm-artist">1. ${nowPlaying.artist['#text']}</span> - ${nowPlaying.name}<br>
|
||||
<div id="lastfm-lastplayedsong">
|
||||
<span id="lastfm-artist">2. ${lastPlayedSong.artist['#text']}</span> - ${lastPlayedSong.name}
|
||||
</div>
|
||||
<div id="lastfm-lastlastplayedsong">
|
||||
<span id="lastfm-artist">3. ${lastlastPlayedSong.artist['#text']}</span> - ${lastlastPlayedSong.name}
|
||||
</div>
|
||||
`;
|
||||
nowPlayingElement.innerHTML = nowPlayingHtml;
|
||||
const albumArt = nowPlaying.image.find(img => img.size === 'large')['#text'];
|
||||
lastfmArtElement.innerHTML = `<img src="${albumArt}" id="lastfm-art">`;
|
||||
} else {
|
||||
const lastPlayed = tracks[0];
|
||||
const lastPlayedTime = new Date(lastPlayed.date.uts * 1000);
|
||||
const currentTime = new Date();
|
||||
const timeDiff = Math.floor((currentTime - lastPlayedTime) / 1000);
|
||||
const timeSince = formatTimeSince(timeDiff);
|
||||
|
||||
const lastPlayedHtml = `
|
||||
<strong>Last Played:</strong> <br>
|
||||
<span id="lastfm-artist">${lastPlayed.artist['#text']}</span> - ${lastPlayed.name} <br>
|
||||
<span id="lastfm-timesinceplay">${timeSince} ago</span>
|
||||
`;
|
||||
nowPlayingElement.innerHTML = lastPlayedHtml;
|
||||
const albumArt = lastPlayed.image.find(img => img.size === 'large')['#text'];
|
||||
lastfmArtElement.innerHTML = `<img src="${albumArt}" id="lastfm-art"> `;
|
||||
}
|
||||
} else {
|
||||
nowPlayingElement.innerHTML = `<strong>Now Playing:</strong> <br> Nothing`;
|
||||
lastfmArtElement.innerHTML = '<div id="lastfm-art"></div>';
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
nowPlayingElement.textContent = 'Error fetching last.fm status.';
|
||||
lastfmArtElement.innerHTML = '<div id="lastfm-art"></div>';
|
||||
console.error('Error fetching now playing status:', error);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
function formatTimeSince(seconds) {
|
||||
const intervals = [
|
||||
{ label: 'year', seconds: 31536000 },
|
||||
{ label: 'month', seconds: 2592000 },
|
||||
{ label: 'day', seconds: 86400 },
|
||||
{ label: 'hour', seconds: 3600 },
|
||||
{ label: 'minute', seconds: 60 },
|
||||
{ label: 'second', seconds: 1 }
|
||||
];
|
||||
|
||||
for (const interval of intervals) {
|
||||
const count = Math.floor(seconds / interval.seconds);
|
||||
if (count > 0) {
|
||||
return `${count} ${interval.label}${count !== 1 ? 's' : ''}`;
|
||||
}
|
||||
}
|
||||
return 'just now';
|
||||
}
|
||||
|
||||
fetchNowPlaying();
|
||||
|
||||
setInterval(fetchNowPlaying, 10000);
|
||||
});
|
93
assets/scripts/lastfm.js.bak
Normal file
@ -0,0 +1,93 @@
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const apiKey = 'APIKEY CHANGE ME'; //these are free, why would you...
|
||||
const username = 'Quinten0508';
|
||||
|
||||
const nowPlayingElement = document.getElementById('lastfm-contents');
|
||||
const lastfmArtElement = document.getElementById('lastfm-artbox');
|
||||
const topTrackElement = document.getElementById('lastfm-toptrack');
|
||||
|
||||
function fetchNowPlaying() {
|
||||
fetch(`https://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=${username}&api_key=${apiKey}&format=json`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.recenttracks.track && data.recenttracks.track.length > 0) {
|
||||
const tracks = data.recenttracks.track;
|
||||
const nowPlaying = tracks[0];
|
||||
const lastPlayedSong = tracks[1];
|
||||
const lastlastPlayedSong = tracks[2];
|
||||
|
||||
if (nowPlaying['@attr'] && nowPlaying['@attr'].nowplaying) { //absolute clusterfuck incoming SORRY - rewrite and send this mess to the css file instead!
|
||||
nowPlayingElement.innerHTML = `<strong>Now Playing:</strong> <br> <span id=lastfm-artist>1. ${nowPlaying.artist['#text']}</span> - ${nowPlaying.name} <div id=lastfm-lastplayedsong>2. ${lastPlayedSong.artist['#text']}</span> - ${lastPlayedSong.name} </div><div id=lastfm-lastplayedsong>3. ${lastlastPlayedSong.artist['#text']}</span> - ${lastlastPlayedSong.name}</div>`;
|
||||
const albumArt = nowPlaying.image.find(img => img.size === 'large')['#text'];
|
||||
lastfmArtElement.innerHTML = `<img src="${albumArt}" id="lastfm-art">`;
|
||||
} else {
|
||||
const lastPlayed = tracks[0];
|
||||
const lastPlayedTime = new Date(lastPlayed.date.uts * 1000);
|
||||
const currentTime = new Date();
|
||||
const timeDiff = Math.floor((currentTime - lastPlayedTime) / 1000);
|
||||
const timeSince = formatTimeSince(timeDiff);
|
||||
|
||||
nowPlayingElement.innerHTML = `<strong>Last Played:</strong> <br> <span id=lastfm-artist>${lastPlayed.artist['#text']}</span> - ${lastPlayed.name} <br> <span id="lastfm-timesinceplay">${timeSince} ago</span>`;
|
||||
const albumArt = lastPlayed.image.find(img => img.size === 'large')['#text'];
|
||||
lastfmArtElement.innerHTML = `<img src="${albumArt}" id="lastfm-art"> `;
|
||||
}
|
||||
} else {
|
||||
nowPlayingElement.innerHTML = `<strong>Now Playing:</strong> <br> Nothing`;
|
||||
lastfmArtElement.innerHTML = '<div id=lastfm-art></div>';
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
nowPlayingElement.textContent = 'Error fetching last.fm status.';
|
||||
lastfmArtElement.innerHTML = '<div id=lastfm-art></div>';
|
||||
console.error('Error fetching now playing status:', error);
|
||||
});
|
||||
}
|
||||
|
||||
function formatTimeSince(seconds) {
|
||||
const intervals = [
|
||||
{ label: 'year', seconds: 31536000 },
|
||||
{ label: 'month', seconds: 2592000 },
|
||||
{ label: 'day', seconds: 86400 },
|
||||
{ label: 'hour', seconds: 3600 },
|
||||
{ label: 'minute', seconds: 60 },
|
||||
{ label: 'second', seconds: 1 }
|
||||
];
|
||||
|
||||
for (const interval of intervals) {
|
||||
const count = Math.floor(seconds / interval.seconds);
|
||||
if (count > 0) {
|
||||
return `${count} ${interval.label}${count !== 1 ? 's' : ''}`;
|
||||
}
|
||||
}
|
||||
return 'just now';
|
||||
}
|
||||
|
||||
fetchNowPlaying();
|
||||
|
||||
setInterval(fetchNowPlaying, 10000);
|
||||
});
|
||||
|
||||
/*
|
||||
|
||||
// fetchTopTrack();
|
||||
function fetchTopTrack() {
|
||||
fetch(`https://ws.audioscrobbler.com/2.0/?method=user.gettoptracks&user=${username}&api_key=${apiKey}&format=json&period=1month&limit=1`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.toptracks.track && data.toptracks.track.length > 0) {
|
||||
const topTrack = data.toptracks.track[0];
|
||||
const topTrackName = topTrack.name;
|
||||
const topTrackArtist = topTrack.artist.name;
|
||||
const topTrackPlayCount = topTrack.playcount;
|
||||
topTrackElement.innerHTML = `<strong>Top Track This Month:</strong> <br> ${topTrackArtist} - ${topTrackName} <br> Play Count: ${topTrackPlayCount}`;
|
||||
nowPlayingElement.innerHTML(topTrackElement);
|
||||
} else {
|
||||
console.error('No top track found.');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching top track:', error);
|
||||
});
|
||||
}
|
||||
|
||||
*/
|
239
assets/scripts/oneko.js
Normal file
@ -0,0 +1,239 @@
|
||||
// oneko.js: https://github.com/adryd325/oneko.js
|
||||
|
||||
(function oneko() {
|
||||
const isReducedMotion =
|
||||
window.matchMedia(`(prefers-reduced-motion: reduce)`) === true ||
|
||||
window.matchMedia(`(prefers-reduced-motion: reduce)`).matches === true;
|
||||
|
||||
if (isReducedMotion) return;
|
||||
|
||||
const nekoEl = document.createElement("div");
|
||||
|
||||
let nekoPosX = 32;
|
||||
let nekoPosY = 32;
|
||||
|
||||
let mousePosX = 0;
|
||||
let mousePosY = 0;
|
||||
|
||||
let frameCount = 0;
|
||||
let idleTime = 0;
|
||||
let idleAnimation = null;
|
||||
let idleAnimationFrame = 0;
|
||||
|
||||
const nekoSpeed = 10;
|
||||
const spriteSets = {
|
||||
idle: [[-3, -3]],
|
||||
alert: [[-7, -3]],
|
||||
scratchSelf: [
|
||||
[-5, 0],
|
||||
[-6, 0],
|
||||
[-7, 0],
|
||||
],
|
||||
scratchWallN: [
|
||||
[0, 0],
|
||||
[0, -1],
|
||||
],
|
||||
scratchWallS: [
|
||||
[-7, -1],
|
||||
[-6, -2],
|
||||
],
|
||||
scratchWallE: [
|
||||
[-2, -2],
|
||||
[-2, -3],
|
||||
],
|
||||
scratchWallW: [
|
||||
[-4, 0],
|
||||
[-4, -1],
|
||||
],
|
||||
tired: [[-3, -2]],
|
||||
sleeping: [
|
||||
[-2, 0],
|
||||
[-2, -1],
|
||||
],
|
||||
N: [
|
||||
[-1, -2],
|
||||
[-1, -3],
|
||||
],
|
||||
NE: [
|
||||
[0, -2],
|
||||
[0, -3],
|
||||
],
|
||||
E: [
|
||||
[-3, 0],
|
||||
[-3, -1],
|
||||
],
|
||||
SE: [
|
||||
[-5, -1],
|
||||
[-5, -2],
|
||||
],
|
||||
S: [
|
||||
[-6, -3],
|
||||
[-7, -2],
|
||||
],
|
||||
SW: [
|
||||
[-5, -3],
|
||||
[-6, -1],
|
||||
],
|
||||
W: [
|
||||
[-4, -2],
|
||||
[-4, -3],
|
||||
],
|
||||
NW: [
|
||||
[-1, 0],
|
||||
[-1, -1],
|
||||
],
|
||||
};
|
||||
|
||||
function init() {
|
||||
nekoEl.id = "oneko";
|
||||
nekoEl.ariaHidden = true;
|
||||
nekoEl.style.width = "32px";
|
||||
nekoEl.style.height = "32px";
|
||||
nekoEl.style.position = "fixed";
|
||||
nekoEl.style.pointerEvents = "none";
|
||||
nekoEl.style.imageRendering = "pixelated";
|
||||
nekoEl.style.left = `${nekoPosX - 16}px`;
|
||||
nekoEl.style.top = `${nekoPosY - 16}px`;
|
||||
nekoEl.style.zIndex = Number.MAX_VALUE;
|
||||
|
||||
let nekoFile = "./oneko.gif"
|
||||
const curScript = document.currentScript
|
||||
if (curScript && curScript.dataset.cat) {
|
||||
nekoFile = curScript.dataset.cat
|
||||
}
|
||||
nekoEl.style.backgroundImage = `url(${nekoFile})`;
|
||||
|
||||
document.body.appendChild(nekoEl);
|
||||
|
||||
document.addEventListener("mousemove", function (event) {
|
||||
mousePosX = event.clientX;
|
||||
mousePosY = event.clientY;
|
||||
});
|
||||
|
||||
window.requestAnimationFrame(onAnimationFrame);
|
||||
}
|
||||
|
||||
let lastFrameTimestamp;
|
||||
|
||||
function onAnimationFrame(timestamp) {
|
||||
// Stops execution if the neko element is removed from DOM
|
||||
if (!nekoEl.isConnected) {
|
||||
return;
|
||||
}
|
||||
if (!lastFrameTimestamp) {
|
||||
lastFrameTimestamp = timestamp;
|
||||
}
|
||||
if (timestamp - lastFrameTimestamp > 100) {
|
||||
lastFrameTimestamp = timestamp
|
||||
frame()
|
||||
}
|
||||
window.requestAnimationFrame(onAnimationFrame);
|
||||
}
|
||||
|
||||
function setSprite(name, frame) {
|
||||
const sprite = spriteSets[name][frame % spriteSets[name].length];
|
||||
nekoEl.style.backgroundPosition = `${sprite[0] * 32}px ${sprite[1] * 32}px`;
|
||||
}
|
||||
|
||||
function resetIdleAnimation() {
|
||||
idleAnimation = null;
|
||||
idleAnimationFrame = 0;
|
||||
}
|
||||
|
||||
function idle() {
|
||||
idleTime += 1;
|
||||
|
||||
// every ~ 20 seconds
|
||||
if (
|
||||
idleTime > 10 &&
|
||||
Math.floor(Math.random() * 200) == 0 &&
|
||||
idleAnimation == null
|
||||
) {
|
||||
let avalibleIdleAnimations = ["sleeping", "scratchSelf"];
|
||||
if (nekoPosX < 32) {
|
||||
avalibleIdleAnimations.push("scratchWallW");
|
||||
}
|
||||
if (nekoPosY < 32) {
|
||||
avalibleIdleAnimations.push("scratchWallN");
|
||||
}
|
||||
if (nekoPosX > window.innerWidth - 32) {
|
||||
avalibleIdleAnimations.push("scratchWallE");
|
||||
}
|
||||
if (nekoPosY > window.innerHeight - 32) {
|
||||
avalibleIdleAnimations.push("scratchWallS");
|
||||
}
|
||||
idleAnimation =
|
||||
avalibleIdleAnimations[
|
||||
Math.floor(Math.random() * avalibleIdleAnimations.length)
|
||||
];
|
||||
}
|
||||
|
||||
switch (idleAnimation) {
|
||||
case "sleeping":
|
||||
if (idleAnimationFrame < 8) {
|
||||
setSprite("tired", 0);
|
||||
break;
|
||||
}
|
||||
setSprite("sleeping", Math.floor(idleAnimationFrame / 4));
|
||||
if (idleAnimationFrame > 192) {
|
||||
resetIdleAnimation();
|
||||
}
|
||||
break;
|
||||
case "scratchWallN":
|
||||
case "scratchWallS":
|
||||
case "scratchWallE":
|
||||
case "scratchWallW":
|
||||
case "scratchSelf":
|
||||
setSprite(idleAnimation, idleAnimationFrame);
|
||||
if (idleAnimationFrame > 9) {
|
||||
resetIdleAnimation();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
setSprite("idle", 0);
|
||||
return;
|
||||
}
|
||||
idleAnimationFrame += 1;
|
||||
}
|
||||
|
||||
function frame() {
|
||||
frameCount += 1;
|
||||
const diffX = nekoPosX - mousePosX;
|
||||
const diffY = nekoPosY - mousePosY;
|
||||
const distance = Math.sqrt(diffX ** 2 + diffY ** 2);
|
||||
|
||||
if (distance < nekoSpeed || distance < 48) {
|
||||
idle();
|
||||
return;
|
||||
}
|
||||
|
||||
idleAnimation = null;
|
||||
idleAnimationFrame = 0;
|
||||
|
||||
if (idleTime > 1) {
|
||||
setSprite("alert", 0);
|
||||
// count down after being alerted before moving
|
||||
idleTime = Math.min(idleTime, 7);
|
||||
idleTime -= 1;
|
||||
return;
|
||||
}
|
||||
|
||||
let direction;
|
||||
direction = diffY / distance > 0.5 ? "N" : "";
|
||||
direction += diffY / distance < -0.5 ? "S" : "";
|
||||
direction += diffX / distance > 0.5 ? "W" : "";
|
||||
direction += diffX / distance < -0.5 ? "E" : "";
|
||||
setSprite(direction, frameCount);
|
||||
|
||||
nekoPosX -= (diffX / distance) * nekoSpeed;
|
||||
nekoPosY -= (diffY / distance) * nekoSpeed;
|
||||
|
||||
nekoPosX = Math.min(Math.max(16, nekoPosX), window.innerWidth - 16);
|
||||
nekoPosY = Math.min(Math.max(16, nekoPosY), window.innerHeight - 16);
|
||||
|
||||
nekoEl.style.left = `${nekoPosX - 16}px`;
|
||||
nekoEl.style.top = `${nekoPosY - 16}px`;
|
||||
}
|
||||
|
||||
init();
|
||||
})();
|
15
assets/scripts/onekoswap.js
Normal file
@ -0,0 +1,15 @@
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
var onekos = [
|
||||
'/assets/oneko.gif',
|
||||
'/assets/oneko-tux.gif',
|
||||
// Add more file paths here if needed
|
||||
];
|
||||
var currentIndex = 0;
|
||||
document.getElementById('oneko-button').addEventListener('click', function() {
|
||||
var oneko = document.getElementById('oneko');
|
||||
currentIndex = (currentIndex + 1) % onekos.length;
|
||||
var newOneko = onekos[currentIndex];
|
||||
oneko.style.backgroundImage = 'url("' + newOneko + '")';
|
||||
});
|
||||
|
||||
});
|
53
assets/scripts/uptime.js
Normal file
@ -0,0 +1,53 @@
|
||||
document.addEventListener('DOMContentLoaded', async function() {
|
||||
async function fetchUptime() {
|
||||
const uptimeElement = document.getElementById('uptime');
|
||||
const names = {
|
||||
"Zipline": "https://zip.quinten0508.com"
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch('https://quinten0508.com/api/uptime');
|
||||
const data = await response.json();
|
||||
|
||||
// Clear previous content
|
||||
uptimeElement.innerHTML = '';
|
||||
|
||||
data.forEach(element => {
|
||||
// Create parent div for each pair
|
||||
const pairDiv = document.createElement('div');
|
||||
pairDiv.className = 'uptime-pair';
|
||||
|
||||
// Create div for name
|
||||
const nameDiv = document.createElement('div');
|
||||
nameDiv.className = 'uptime-name-element';
|
||||
|
||||
// Check if there is a specific URL for this monitor name
|
||||
if (names.hasOwnProperty(element.monitor_name)) {
|
||||
const url = names[element.monitor_name];
|
||||
nameDiv.innerHTML = `<a href="${url}" class="link" target="_blank">${element.monitor_name}</a>`;
|
||||
} else {
|
||||
nameDiv.textContent = element.monitor_name;
|
||||
}
|
||||
|
||||
// Create div for status
|
||||
const statusDiv = document.createElement('div');
|
||||
statusDiv.className = 'uptime-status-element';
|
||||
statusDiv.textContent = element.status;
|
||||
|
||||
// Append name and status divs to pair div
|
||||
pairDiv.appendChild(nameDiv);
|
||||
pairDiv.appendChild(statusDiv);
|
||||
|
||||
// Append pair div to uptime container
|
||||
uptimeElement.appendChild(pairDiv);
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error fetching uptime data:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch the uptime immediately and then every 10 seconds
|
||||
fetchUptime();
|
||||
setInterval(fetchUptime, 10000);
|
||||
});
|
18
colorscheme.css
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
/*
|
||||
COLOR SCHEME
|
||||
|
||||
Colors
|
||||
#B1C6CB
|
||||
#74C1B1
|
||||
#8FC8B9
|
||||
#799ACD
|
||||
|
||||
Dark-gray
|
||||
#262626
|
||||
|
||||
Off-white
|
||||
#E9E9E9
|
||||
#e9e9e9a2
|
||||
|
||||
*/
|
BIN
favicon.ico
Normal file
After Width: | Height: | Size: 4.2 KiB |
104
index.html
Normal file
@ -0,0 +1,104 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<title>Quintens Outpost</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<script src="/assets/scripts/lastfm.js"></script>
|
||||
<script src="/assets/scripts/clock.js"></script>
|
||||
<script src="/assets/scripts/heartbeat.js"></script>
|
||||
<script src="/assets/scripts/onekoswap.js"></script>
|
||||
<script src="/assets/scripts/uptime.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="container">
|
||||
|
||||
<div id="maintitlebox">
|
||||
<h1 id="maintitle" class="box">Quinten's Outpost</h1>
|
||||
</div>
|
||||
|
||||
<div id="subtitlebox">
|
||||
<div id="links" class="box">
|
||||
<a class="linkbox link" href="https://x.com/quinten0508" rel="me" target="_blank">
|
||||
<p>twitter</p></a>
|
||||
<a class="linkbox link" href="https://www.last.fm/user/Quinten0508" rel="me" target="_blank">
|
||||
<p>last.fm</p></a>
|
||||
<a class="linkbox link" href="https://github.com/Quinten0508" rel="me" target="_blank">
|
||||
<p>github</p></a>
|
||||
<a class="linkbox link" href="https://t.me/quinten0508" rel="me" target="_blank">
|
||||
<p>telegram</p></a>
|
||||
<!-- :3 13 year old firefox bug https://bugzilla.mozilla.org/show_bug.cgi?id=646552 -->
|
||||
<a class="linkbox link" onClick="javascript:window.open('mailto:quinten0508@protonmail.com', 'mail');event.preventDefault()" href="mailto:quinten0508@protonmail.com" rel="me" target="_blank">
|
||||
<p>email</p></a>
|
||||
<!-- new button template
|
||||
<a class="linkbox link" href="" target="_blank">
|
||||
<p></p></a>
|
||||
-->
|
||||
|
||||
</div>
|
||||
<div id="heartbeatbox" class="box">
|
||||
<a href="https://heartbeat.quinten0508.com" target="_blank" class="link"><p>Status</p></a><p>: </p>
|
||||
<p id="heartbeat-time"> </p> <!-- prevents text shift after load, doenst work with online T-T -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="header">
|
||||
|
||||
<div id="lastfm-box">
|
||||
<div id="lastfm-contents"><p>Loading...</p></div>
|
||||
<div id="lastfm-artbox"><div style="background-color: #000000;"></div></div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="clock-box">
|
||||
<p id="clocktitle"> My time (UTC+2)</p>
|
||||
<div id="clock-contents">
|
||||
<p id="clock">Loading...</p>
|
||||
<img id="clock-icon"></img>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="box">
|
||||
<h3 style="padding-bottom: 1rem;">Status</h3>
|
||||
<h5 style="color: red;">TEMPORARY DOWNTIME</h5>
|
||||
<p>Accidentally nuked all 700 server configuration files, expect wonky behaviour across services while i figure this out...</p>
|
||||
<div id="uptime"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="box">
|
||||
<button id="oneko-button" class="button">Click me :3</button>
|
||||
<h3>titleee</h3>
|
||||
<h5>caption</h5>
|
||||
<p> this text will automatically fill up the box and has decent spacing?? </p>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="box">
|
||||
<p> heres some more text and shit</p>
|
||||
</div>
|
||||
<div class="box">
|
||||
<p> heres some more text and shit</p>
|
||||
</div>
|
||||
<div class="box">
|
||||
<p> heres some more text and shit</p>
|
||||
<!--<img src="/assets/capy.jpg" class="image">-->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div id="stripes">
|
||||
<img src="stripes.svg" id="stripes">
|
||||
</div>
|
||||
|
||||
|
||||
</body>
|
||||
<script src="/assets/scripts/oneko.js" data-cat="/assets/oneko.gif"></script>
|
||||
</html>
|
33
robots.txt
Normal file
@ -0,0 +1,33 @@
|
||||
User-agent: AdsBot-Google
|
||||
User-agent: Amazonbot
|
||||
User-agent: anthropic-ai
|
||||
User-agent: Applebot
|
||||
User-agent: AwarioRssBot
|
||||
User-agent: AwarioSmartBot
|
||||
User-agent: Bytespider
|
||||
User-agent: CCBot
|
||||
User-agent: ChatGPT-User
|
||||
User-agent: ClaudeBot
|
||||
User-agent: Claude-Web
|
||||
User-agent: cohere-ai
|
||||
User-agent: DataForSeoBot
|
||||
User-agent: Diffbot
|
||||
User-agent: FacebookBot
|
||||
User-agent: FriendlyCrawler
|
||||
User-agent: Google-Extended
|
||||
User-agent: GoogleOther
|
||||
User-agent: GPTBot
|
||||
User-agent: img2dataset
|
||||
User-agent: ImagesiftBot
|
||||
User-agent: magpie-crawler
|
||||
User-agent: Meltwater
|
||||
User-agent: omgili
|
||||
User-agent: omgilibot
|
||||
User-agent: peer39_crawler
|
||||
User-agent: peer39_crawler/1.0
|
||||
User-agent: PerplexityBot
|
||||
User-agent: PiplBot
|
||||
User-agent: scoop.it
|
||||
User-agent: Seekr
|
||||
User-agent: YouBot
|
||||
Disallow: /
|
23
stripes.svg
Normal file
@ -0,0 +1,23 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:svgjs="http://svgjs.dev/svgjs"
|
||||
|
||||
>
|
||||
<rect x="0" y="0" width="100%" height="25%"
|
||||
fill="#B1C6CB"
|
||||
></rect>
|
||||
|
||||
<rect x="0" y="25%" width="100%" height="25%"
|
||||
fill="#8FC8B9"
|
||||
></rect>
|
||||
|
||||
<rect x="0" y="50%" width="100%" height="25%"
|
||||
fill="#74C1B1"
|
||||
></rect>
|
||||
|
||||
<rect x="0" y="75%" width="100%" height="25%"
|
||||
fill="#799ACD"
|
||||
></rect>
|
||||
|
||||
</svg>
|
After Width: | Height: | Size: 473 B |
457
style.css
Normal file
@ -0,0 +1,457 @@
|
||||
/* ibm-plex-mono-regular - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: 'IBM Plex Mono';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url('/assets/fonts/ibm-plex-mono-v19-latin-regular.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
}
|
||||
|
||||
/* ibm-plex-mono-italic - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: 'IBM Plex Mono';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
src: url('/assets/fonts/ibm-plex-mono-v19-latin-italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
}
|
||||
|
||||
/* ibm-plex-mono-500 - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: 'IBM Plex Mono';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
src: url('/assets/fonts/ibm-plex-mono-v19-latin-500.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
}
|
||||
|
||||
/* ibm-plex-mono-500italic - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: 'IBM Plex Mono';
|
||||
font-style: italic;
|
||||
font-weight: 500;
|
||||
src: url('/assets/fonts/ibm-plex-mono-v19-latin-500italic.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 1400px) {
|
||||
html {
|
||||
font-size: 25px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 768px) {
|
||||
html {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@media (max-width: 450px) {
|
||||
html {
|
||||
font-size: 10px;
|
||||
}
|
||||
#subtitlebox{
|
||||
height: 6rem !important;
|
||||
}
|
||||
#lastfm-box, #links {
|
||||
flex: 25 !important;
|
||||
}
|
||||
#heartbeatbox, #clock-box {
|
||||
flex: 13 !important;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Rules for thy Sanity
|
||||
h1 = title
|
||||
h3 = paragraph
|
||||
h5 = caption
|
||||
paragraph = text
|
||||
3rem vertical space between standard boxes (split into 1.5rem top and bottom)
|
||||
*/
|
||||
|
||||
/*
|
||||
ideas
|
||||
* navbar as vertical element on left side
|
||||
* status bar under title for lastfm, mood?, misc
|
||||
* services uptime - uptime kuma integration ---- sad, no api or anything for kuma...
|
||||
* socials/links/platforms in first right-aligned box
|
||||
** wont work well on mobile, instead just attach it under title within same box?
|
||||
* left side of that box as bio
|
||||
* current weather widget to right of lastfm status -- naur, too much effort and weird?
|
||||
* comets and blinking stars in background
|
||||
* more animation in general - make this mf ALIVE!!!!
|
||||
* fancy borders see bookmark
|
||||
* make a little place for the kitty in top left (or right?)
|
||||
*/
|
||||
|
||||
/*
|
||||
The container query length units are:
|
||||
|
||||
cqw: 1% of a query container's width
|
||||
cqh: 1% of a query container's height
|
||||
cqi: 1% of a query container's inline size
|
||||
cqb: 1% of a query container's block size
|
||||
cqmin: The smaller value of either cqi or cqb
|
||||
cqmax: The larger value of either cqi or cqb
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
html {
|
||||
background-color: #000000;
|
||||
background-image: url('/assets/bg.gif');
|
||||
background-repeat: repeat;
|
||||
background-color: transparent;
|
||||
margin: 0px;
|
||||
border: 0px;
|
||||
padding: 0px;
|
||||
min-height: 100vh;
|
||||
font-family: "IBM Plex Mono", monospace;
|
||||
font-style: normal;
|
||||
color: #E9E9E9;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0px;
|
||||
border: 0px;
|
||||
padding: 0px;
|
||||
min-height: 100vh;
|
||||
|
||||
}
|
||||
|
||||
|
||||
.container {
|
||||
width: min(900px,92vw);
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
#maintitlebox {
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#maintitle {
|
||||
font-size: 3.5rem;
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
|
||||
#subtitlebox {
|
||||
display: flex;
|
||||
justify-content: stretch;
|
||||
align-items: stretch;
|
||||
height: 4rem;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
#links {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
flex: 3;
|
||||
}
|
||||
|
||||
.linkbox {
|
||||
margin-right: 1rem;
|
||||
background: #000;
|
||||
padding: 0.5rem;
|
||||
|
||||
}
|
||||
#heartbeatbox {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex: 1
|
||||
|
||||
}
|
||||
#heartbeat-time {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.link {
|
||||
color: #E9E9E9;
|
||||
text-decoration: none;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.link::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 0.1rem;
|
||||
display: block;
|
||||
left: 0;
|
||||
background: #E9E9E9;
|
||||
transition: width 0.3s ease, left 0.3s ease;
|
||||
}
|
||||
|
||||
.link:hover::after {
|
||||
width: 100%;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
|
||||
.box {
|
||||
background: #000;
|
||||
border: 1px solid #E9E9E9;
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
padding: 1rem;
|
||||
align-self: center;
|
||||
justify-self: center;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
|
||||
.button {
|
||||
background: #000;
|
||||
border: 1px solid #E9E9E9;
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
padding: 1rem;
|
||||
align-self: center;
|
||||
justify-self: center;
|
||||
max-height: 100%;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
.button:active {
|
||||
background: #333333; /* Lighter grey color */
|
||||
}
|
||||
|
||||
|
||||
|
||||
.box:last-child {
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
|
||||
#header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin-top: 0.75rem;
|
||||
height: 8rem;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#lastfm-box {
|
||||
background: #000;
|
||||
border: 1px solid #E9E9E9;
|
||||
justify-content: space-between;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1 1 auto;
|
||||
height: 8rem;
|
||||
flex: 3;
|
||||
}
|
||||
|
||||
#lastfm-contents {
|
||||
font-family: "IBM Plex Mono", monospace;
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
color: #E9E9E9;
|
||||
line-height: 1.8;
|
||||
font-size: min(1rem, 2.2cm);
|
||||
overflow: hidden;
|
||||
max-height: 100%; /* Adjusted to 100% */
|
||||
padding: 1rem;
|
||||
padding-top: 0.5rem;
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#lastfm-artist {
|
||||
font-style: normal;
|
||||
}
|
||||
#lastfm-timesinceplay {
|
||||
font-style:italic;
|
||||
color:#e9e9e9a2;
|
||||
font-size: min(1rem, 2.2cqmin);
|
||||
}
|
||||
|
||||
#lastfm-lastplayedsong, #lastfm-lastlastplayedsong{
|
||||
font-style:italic;
|
||||
color: #e9e9e9a2;
|
||||
font-size: min(1rem, 2.2cqmin);
|
||||
}
|
||||
#lastfm-artbox {
|
||||
padding: 1rem;
|
||||
}
|
||||
#lastfm-art {
|
||||
border: 1px solid #E9E9E9;
|
||||
padding: 0.2rem;
|
||||
width: 5rem;
|
||||
height: 5rem;
|
||||
}
|
||||
|
||||
|
||||
#clock-box {
|
||||
background: #000;
|
||||
border: 1px solid #E9E9E9;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 8rem;
|
||||
gap: 0.3rem;
|
||||
flex: 1;
|
||||
}
|
||||
#clocktitle {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
#clock-contents {
|
||||
display: flex;
|
||||
gap: 0.3rem;
|
||||
align-items: top;
|
||||
justify-content: center;
|
||||
}
|
||||
#clock {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 1.8rem;
|
||||
flex: 9;
|
||||
padding-left: 0.5rem;
|
||||
}
|
||||
#clock-icon {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
padding-top: 0.4rem;
|
||||
flex: 1;
|
||||
width: 1.2rem;
|
||||
height: 1.2rem;
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.image {
|
||||
width: 100%;
|
||||
border: 1rem;
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
|
||||
#uptime {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
justify-content: left;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.uptime-pair {
|
||||
display: flex;
|
||||
border: 1px solid #E9E9E9;
|
||||
padding: 1rem;
|
||||
flex-direction: row;
|
||||
}
|
||||
.uptime-name-element, .uptime-status-element {
|
||||
border: 1px solid red;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
/* #uptime-name, #uptime-status {
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
|
||||
}
|
||||
.uptime-name-element, .uptime-status-element {
|
||||
height: 2rem;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
.uptime-name-element {
|
||||
font-style: bold;
|
||||
border-bottom: 1px solid #E9E9E9;
|
||||
}
|
||||
.uptime-name-element:last-of-type {
|
||||
border-bottom: 0;
|
||||
}
|
||||
.uptime-box {
|
||||
background: #000;
|
||||
border: 1px solid #E9E9E9;
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
padding: 1rem;
|
||||
max-height: 100%;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
h1 {
|
||||
font-weight: 500;
|
||||
font-size: 4rem;
|
||||
letter-spacing: 0.2rem;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-weight: 500;
|
||||
font-size: 2.4rem;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
padding-bottom: 0.2rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1.2rem;
|
||||
font-style: italic;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
padding-bottom: 1.2rem;
|
||||
}
|
||||
|
||||
p, pre {
|
||||
font-size: 1.2rem;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
button {
|
||||
color: #E9E9E9;
|
||||
}
|
||||
|
||||
|
||||
#stripes {
|
||||
width: 100vw;
|
||||
height: max(16vh, 176px);
|
||||
}
|