commit 9a8690ea68082eb0de15083f93e4f56e6b25229d Author: Quinten0508 <55107945+Quinten0508@users.noreply.github.com> Date: Sat Jun 22 20:58:35 2024 +0200 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9b1ee42 --- /dev/null +++ b/.gitignore @@ -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 diff --git a/.unused/bg.png b/.unused/bg.png new file mode 100644 index 0000000..972bc32 Binary files /dev/null and b/.unused/bg.png differ diff --git a/.unused/dither copy.svg b/.unused/dither copy.svg new file mode 100644 index 0000000..28f87cd --- /dev/null +++ b/.unused/dither copy.svg @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/.unused/dither.svg b/.unused/dither.svg new file mode 100644 index 0000000..a25e5a4 --- /dev/null +++ b/.unused/dither.svg @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/.unused/dithertest1.svg b/.unused/dithertest1.svg new file mode 100644 index 0000000..5198327 --- /dev/null +++ b/.unused/dithertest1.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.unused/index2.html b/.unused/index2.html new file mode 100644 index 0000000..7ec8d3d --- /dev/null +++ b/.unused/index2.html @@ -0,0 +1,23 @@ + + + + + +SVG Background + + + +

hi :3

> + + diff --git a/.unused/noise copy.svg b/.unused/noise copy.svg new file mode 100644 index 0000000..39aece2 --- /dev/null +++ b/.unused/noise copy.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.unused/noise.svg b/.unused/noise.svg new file mode 100644 index 0000000..4b5e1ff --- /dev/null +++ b/.unused/noise.svg @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/404.html b/404.html new file mode 100644 index 0000000..d6f2f6d --- /dev/null +++ b/404.html @@ -0,0 +1,37 @@ + + + + + + quinten0508.com + + + + + + + +
+ +
+

Quinten

+
+ + +
+
+ +
+ + + + + + + + + + diff --git a/assets/bg.gif b/assets/bg.gif new file mode 100644 index 0000000..4b14c67 Binary files /dev/null and b/assets/bg.gif differ diff --git a/assets/buttons/firefox.gif b/assets/buttons/firefox.gif new file mode 100644 index 0000000..14a24df Binary files /dev/null and b/assets/buttons/firefox.gif differ diff --git a/assets/buttons/piracy.gif b/assets/buttons/piracy.gif new file mode 100644 index 0000000..37b73b8 Binary files /dev/null and b/assets/buttons/piracy.gif differ diff --git a/assets/buttons/yippeee.gif b/assets/buttons/yippeee.gif new file mode 100644 index 0000000..c6a4035 Binary files /dev/null and b/assets/buttons/yippeee.gif differ diff --git a/assets/capy.jpg b/assets/capy.jpg new file mode 100644 index 0000000..b3d9973 Binary files /dev/null and b/assets/capy.jpg differ diff --git a/assets/cat-hammer-404.gif b/assets/cat-hammer-404.gif new file mode 100644 index 0000000..b1376e5 Binary files /dev/null and b/assets/cat-hammer-404.gif differ diff --git a/assets/fonts/Nintendo-DS-BIOS.ttf b/assets/fonts/Nintendo-DS-BIOS.ttf new file mode 100644 index 0000000..18e9603 Binary files /dev/null and b/assets/fonts/Nintendo-DS-BIOS.ttf differ diff --git a/assets/fonts/ibm-plex-mono-v19-latin-500.woff2 b/assets/fonts/ibm-plex-mono-v19-latin-500.woff2 new file mode 100644 index 0000000..99c2610 Binary files /dev/null and b/assets/fonts/ibm-plex-mono-v19-latin-500.woff2 differ diff --git a/assets/fonts/ibm-plex-mono-v19-latin-500italic.woff2 b/assets/fonts/ibm-plex-mono-v19-latin-500italic.woff2 new file mode 100644 index 0000000..f534ad6 Binary files /dev/null and b/assets/fonts/ibm-plex-mono-v19-latin-500italic.woff2 differ diff --git a/assets/fonts/ibm-plex-mono-v19-latin-italic.woff2 b/assets/fonts/ibm-plex-mono-v19-latin-italic.woff2 new file mode 100644 index 0000000..0e72669 Binary files /dev/null and b/assets/fonts/ibm-plex-mono-v19-latin-italic.woff2 differ diff --git a/assets/fonts/ibm-plex-mono-v19-latin-regular.woff2 b/assets/fonts/ibm-plex-mono-v19-latin-regular.woff2 new file mode 100644 index 0000000..a6c77d6 Binary files /dev/null and b/assets/fonts/ibm-plex-mono-v19-latin-regular.woff2 differ diff --git a/assets/icons/lastfm.png b/assets/icons/lastfm.png new file mode 100644 index 0000000..049e5b0 Binary files /dev/null and b/assets/icons/lastfm.png differ diff --git a/assets/icons/lastfm_small.png b/assets/icons/lastfm_small.png new file mode 100644 index 0000000..7905116 Binary files /dev/null and b/assets/icons/lastfm_small.png differ diff --git a/assets/icons/moon_small.png b/assets/icons/moon_small.png new file mode 100644 index 0000000..36776d7 Binary files /dev/null and b/assets/icons/moon_small.png differ diff --git a/assets/icons/skull_small.png b/assets/icons/skull_small.png new file mode 100644 index 0000000..bebb7e2 Binary files /dev/null and b/assets/icons/skull_small.png differ diff --git a/assets/icons/sun_small.png b/assets/icons/sun_small.png new file mode 100644 index 0000000..3db4051 Binary files /dev/null and b/assets/icons/sun_small.png differ diff --git a/assets/icons/twitter.svg b/assets/icons/twitter.svg new file mode 100644 index 0000000..d5acd46 --- /dev/null +++ b/assets/icons/twitter.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/image.png b/assets/image.png new file mode 100644 index 0000000..8e85313 Binary files /dev/null and b/assets/image.png differ diff --git a/assets/oneko-tux-old.gif b/assets/oneko-tux-old.gif new file mode 100644 index 0000000..c4af325 Binary files /dev/null and b/assets/oneko-tux-old.gif differ diff --git a/assets/oneko-tux.gif b/assets/oneko-tux.gif new file mode 100644 index 0000000..b2dc823 Binary files /dev/null and b/assets/oneko-tux.gif differ diff --git a/assets/oneko.gif b/assets/oneko.gif new file mode 100644 index 0000000..a009c2c Binary files /dev/null and b/assets/oneko.gif differ diff --git a/assets/scripts/clock.js b/assets/scripts/clock.js new file mode 100644 index 0000000..bee6fc3 --- /dev/null +++ b/assets/scripts/clock.js @@ -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); + }); \ No newline at end of file diff --git a/assets/scripts/heartbeat.js b/assets/scripts/heartbeat.js new file mode 100644 index 0000000..3e3803f --- /dev/null +++ b/assets/scripts/heartbeat.js @@ -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); +}); diff --git a/assets/scripts/lastfm.js b/assets/scripts/lastfm.js new file mode 100644 index 0000000..8de4d19 --- /dev/null +++ b/assets/scripts/lastfm.js @@ -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 = ` + Now Playing:
+ 1. ${nowPlaying.artist['#text']} - ${nowPlaying.name}
+
+ 2. ${lastPlayedSong.artist['#text']} - ${lastPlayedSong.name} +
+
+ 3. ${lastlastPlayedSong.artist['#text']} - ${lastlastPlayedSong.name} +
+ `; + nowPlayingElement.innerHTML = nowPlayingHtml; + const albumArt = nowPlaying.image.find(img => img.size === 'large')['#text']; + lastfmArtElement.innerHTML = ``; + } 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 = ` + Last Played:
+ ${lastPlayed.artist['#text']} - ${lastPlayed.name}
+ ${timeSince} ago + `; + nowPlayingElement.innerHTML = lastPlayedHtml; + const albumArt = lastPlayed.image.find(img => img.size === 'large')['#text']; + lastfmArtElement.innerHTML = ` `; + } + } else { + nowPlayingElement.innerHTML = `Now Playing:
Nothing`; + lastfmArtElement.innerHTML = '
'; + } + }) + .catch(error => { + nowPlayingElement.textContent = 'Error fetching last.fm status.'; + lastfmArtElement.innerHTML = '
'; + 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); +}); diff --git a/assets/scripts/lastfm.js.bak b/assets/scripts/lastfm.js.bak new file mode 100644 index 0000000..1b437af --- /dev/null +++ b/assets/scripts/lastfm.js.bak @@ -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 = `Now Playing:
1. ${nowPlaying.artist['#text']} - ${nowPlaying.name}
2. ${lastPlayedSong.artist['#text']} - ${lastPlayedSong.name}
3. ${lastlastPlayedSong.artist['#text']} - ${lastlastPlayedSong.name}
`; + const albumArt = nowPlaying.image.find(img => img.size === 'large')['#text']; + lastfmArtElement.innerHTML = ``; + } 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 = `Last Played:
${lastPlayed.artist['#text']} - ${lastPlayed.name}
${timeSince} ago`; + const albumArt = lastPlayed.image.find(img => img.size === 'large')['#text']; + lastfmArtElement.innerHTML = ` `; + } + } else { + nowPlayingElement.innerHTML = `Now Playing:
Nothing`; + lastfmArtElement.innerHTML = '
'; + } + }) + .catch(error => { + nowPlayingElement.textContent = 'Error fetching last.fm status.'; + lastfmArtElement.innerHTML = '
'; + 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 = `Top Track This Month:
${topTrackArtist} - ${topTrackName}
Play Count: ${topTrackPlayCount}`; + nowPlayingElement.innerHTML(topTrackElement); + } else { + console.error('No top track found.'); + } + }) + .catch(error => { + console.error('Error fetching top track:', error); + }); + } + + */ \ No newline at end of file diff --git a/assets/scripts/oneko.js b/assets/scripts/oneko.js new file mode 100644 index 0000000..bd8b882 --- /dev/null +++ b/assets/scripts/oneko.js @@ -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(); +})(); diff --git a/assets/scripts/onekoswap.js b/assets/scripts/onekoswap.js new file mode 100644 index 0000000..5c51d05 --- /dev/null +++ b/assets/scripts/onekoswap.js @@ -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 + '")'; + }); + +}); diff --git a/assets/scripts/uptime.js b/assets/scripts/uptime.js new file mode 100644 index 0000000..e1c36f3 --- /dev/null +++ b/assets/scripts/uptime.js @@ -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 = `${element.monitor_name}`; + } 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); +}); diff --git a/colorscheme.css b/colorscheme.css new file mode 100644 index 0000000..2694f08 --- /dev/null +++ b/colorscheme.css @@ -0,0 +1,18 @@ + +/* +COLOR SCHEME + +Colors +#B1C6CB +#74C1B1 +#8FC8B9 +#799ACD + +Dark-gray +#262626 + +Off-white +#E9E9E9 + #e9e9e9a2 + +*/ diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000..0c2a00c Binary files /dev/null and b/favicon.ico differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..6e51b48 --- /dev/null +++ b/index.html @@ -0,0 +1,104 @@ + + + + + Quintens Outpost + + + + + + + + + + + + +
+ +
+

Quinten's Outpost

+
+ +
+ +
+

Status

+

     

+
+
+ + + + + +
+

Status

+
TEMPORARY DOWNTIME
+

Accidentally nuked all 700 server configuration files, expect wonky behaviour across services while i figure this out...

+
+
+ + +
+ +

titleee

+
caption
+

this text will automatically fill up the box and has decent spacing??

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

+
+ + +
+

heres some more text and shit

+
+
+

heres some more text and shit

+
+
+

heres some more text and shit

+ +
+ +
+
+ +
+ + + + + \ No newline at end of file diff --git a/robots.txt b/robots.txt new file mode 100644 index 0000000..77c4a55 --- /dev/null +++ b/robots.txt @@ -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: / \ No newline at end of file diff --git a/stripes.svg b/stripes.svg new file mode 100644 index 0000000..557c434 --- /dev/null +++ b/stripes.svg @@ -0,0 +1,23 @@ + + + + + + + + + + \ No newline at end of file diff --git a/style.css b/style.css new file mode 100644 index 0000000..3a355fa --- /dev/null +++ b/style.css @@ -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); +} \ No newline at end of file