From 0e46dc943ee320adfeb5875d65db60552c7b1ecb Mon Sep 17 00:00:00 2001
From: dusk <y.bera003.06@protonmail.com>
Date: Wed, 2 Apr 2025 05:13:38 +0300
Subject: [PATCH] feat: update texT

---
 src/lib/bluesky.ts           |  84 ++++++++-------
 src/lib/lastfm.ts            |  70 ++++++------
 src/lib/steam.ts             |  89 ++++++++-------
 src/lib/visits.ts            | 202 +++++++++++++++++++----------------
 src/lib/window.ts            |  23 ++--
 src/routes/+layout.server.ts |  34 +++---
 src/routes/+layout.svelte    |  57 ++++++----
 src/routes/+page.svelte      | 196 +++++++++++++++++----------------
 8 files changed, 417 insertions(+), 338 deletions(-)

diff --git a/src/lib/bluesky.ts b/src/lib/bluesky.ts
index 2451ad9..d37f783 100644
--- a/src/lib/bluesky.ts
+++ b/src/lib/bluesky.ts
@@ -1,48 +1,56 @@
-import { env } from '$env/dynamic/private'
-import { Bot, type Post } from "@skyware/bot";
-import { get, writable } from 'svelte/store'
+import { env } from '$env/dynamic/private';
+import { Bot, type Post } from '@skyware/bot';
+import { get, writable } from 'svelte/store';
 
-const bskyClient = writable<null | Bot>(null)
+const bskyClient = writable<null | Bot>(null);
 
 export const getBskyClient = async () => {
-    let client = get(bskyClient)
-    if (client === null) {
-        client = await loginToBsky()
-        bskyClient.set(client)
-    }
-    return client
-}
+	let client = get(bskyClient);
+	if (client === null) {
+		client = await loginToBsky();
+		bskyClient.set(client);
+	}
+	return client;
+};
 
 const loginToBsky = async () => {
-    const bot = new Bot({ service: "https://gaze.systems" })
-    await bot.login({ identifier: 'guestbook.gaze.systems', password: env.BSKY_PASSWORD ?? "" })
-    return bot
-}
+	const bot = new Bot({ service: 'https://gaze.systems' });
+	await bot.login({ identifier: 'guestbook.gaze.systems', password: env.BSKY_PASSWORD ?? '' });
+	return bot;
+};
 
-export const getUserPosts = async (did: string, count: number = 10, cursor: string | null = null) => {
-    const client = await getBskyClient()
-    let feedCursor: string | null | undefined = cursor;
-    let posts: Post[] = []
-    // fetch requested amount of posts
-    while (posts.length < count - 1 && (typeof feedCursor === "string" || feedCursor === null)) {
-        let feedData = await client.getUserPosts(
-            did, { limit: count, filter: 'posts_no_replies', cursor: feedCursor === null ? undefined : feedCursor }
-        )
-        posts.push(...feedData.posts.filter((post) => post.author.did === did))
-        feedCursor = feedData.cursor
-    }
-    return { posts, cursor: feedCursor === null ? undefined : feedCursor }
-}
+export const getUserPosts = async (
+	did: string,
+	count: number = 10,
+	cursor: string | null = null
+) => {
+	const client = await getBskyClient();
+	let feedCursor: string | null | undefined = cursor;
+	const posts: Post[] = [];
+	// fetch requested amount of posts
+	while (posts.length < count - 1 && (typeof feedCursor === 'string' || feedCursor === null)) {
+		const feedData = await client.getUserPosts(did, {
+			limit: count,
+			filter: 'posts_no_replies',
+			cursor: feedCursor === null ? undefined : feedCursor
+		});
+		posts.push(...feedData.posts.filter((post) => post.author.did === did));
+		feedCursor = feedData.cursor;
+	}
+	return { posts, cursor: feedCursor === null ? undefined : feedCursor };
+};
 
-const lastPosts = writable<Post[]>([])
+const lastPosts = writable<Post[]>([]);
 
 export const updateLastPosts = async () => {
-    try {
-        const { posts } = await getUserPosts("did:plc:dfl62fgb7wtjj3fcbb72naae", 13)
-        lastPosts.set(posts)
-    } catch (err) {
-        console.log(`can't update last posts ${err}`)
-    }
-}
+	try {
+		const { posts } = await getUserPosts('did:plc:dfl62fgb7wtjj3fcbb72naae', 13);
+		lastPosts.set(posts);
+	} catch (err) {
+		console.log(`can't update last posts ${err}`);
+	}
+};
 
-export const getLastPosts = () => { return get(lastPosts) }
\ No newline at end of file
+export const getLastPosts = () => {
+	return get(lastPosts);
+};
diff --git a/src/lib/lastfm.ts b/src/lib/lastfm.ts
index 8bdff5a..18fcc7f 100644
--- a/src/lib/lastfm.ts
+++ b/src/lib/lastfm.ts
@@ -1,37 +1,45 @@
-import { get, writable } from "svelte/store"
+import { get, writable } from 'svelte/store';
 
-const GET_RECENT_TRACKS_ENDPOINT = "https://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=yusdacra&api_key=da1911d405b5b37383e200b8f36ee9ec&format=json&limit=1"
+const GET_RECENT_TRACKS_ENDPOINT =
+	'https://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=yusdacra&api_key=da1911d405b5b37383e200b8f36ee9ec&format=json&limit=1';
 
 type LastTrack = {
-    name: string,
-    artist: string,
-    image: string | null,
-    link: string,
-    when: number,
-    playing: boolean,
-}
-const lastTrack = writable<LastTrack | null>(null)
+	name: string;
+	artist: string;
+	image: string | null;
+	link: string;
+	when: number;
+	playing: boolean;
+};
+const lastTrack = writable<LastTrack | null>(null);
 
 export const lastFmUpdateNowPlaying = async () => {
-    try {
-        var resp = await (await fetch(GET_RECENT_TRACKS_ENDPOINT)).json()
-        var track = resp.recenttracks.track[0] ?? null
-        if (!((track['@attr'] ?? {}).nowplaying ?? null)) {
-            throw "no nowplaying track found"
-        }
-        var data = {
-            name: track.name,
-            artist: track.artist['#text'],
-            image: track.image[2]['#text'] ?? null,
-            link: track.url,
-            when: Date.now(),
-            playing: true,
-        }
-        lastTrack.set(data)
-    } catch(why) {
-        console.log("could not fetch last fm: ", why)
-        lastTrack.update((t) => { if (t !== null) { t.playing = false; } return t })
-    }
-}
+	try {
+		const resp = await (await fetch(GET_RECENT_TRACKS_ENDPOINT)).json();
+		const track = resp.recenttracks.track[0] ?? null;
+		if (!((track['@attr'] ?? {}).nowplaying ?? null)) {
+			throw 'no nowplaying track found';
+		}
+		const data = {
+			name: track.name,
+			artist: track.artist['#text'],
+			image: track.image[2]['#text'] ?? null,
+			link: track.url,
+			when: Date.now(),
+			playing: true
+		};
+		lastTrack.set(data);
+	} catch (why) {
+		console.log('could not fetch last fm: ', why);
+		lastTrack.update((t) => {
+			if (t !== null) {
+				t.playing = false;
+			}
+			return t;
+		});
+	}
+};
 
-export const getNowPlaying = () => { return get(lastTrack) }
\ No newline at end of file
+export const getNowPlaying = () => {
+	return get(lastTrack);
+};
diff --git a/src/lib/steam.ts b/src/lib/steam.ts
index eaf5779..b9743f8 100644
--- a/src/lib/steam.ts
+++ b/src/lib/steam.ts
@@ -1,48 +1,55 @@
-import { env } from "$env/dynamic/private";
-import SGDB from "steamgriddb";
-import { get, writable } from "svelte/store";
+import { env } from '$env/dynamic/private';
+import SGDB from 'steamgriddb';
+import { get, writable } from 'svelte/store';
 
-const STEAM_ID = "76561198106829949"
-const GET_PLAYER_SUMMARY_ENDPOINT = `http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=${env.STEAM_API_KEY}&steamids=${STEAM_ID}&format=json`
+const STEAM_ID = '76561198106829949';
+const GET_PLAYER_SUMMARY_ENDPOINT = `http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=${env.STEAM_API_KEY}&steamids=${STEAM_ID}&format=json`;
 
 type LastGame = {
-    name: string,
-    link: string,
-    icon: string,
-    pfp: string,
-    when: number,
-    playing: boolean,
-}
+	name: string;
+	link: string;
+	icon: string;
+	pfp: string;
+	when: number;
+	playing: boolean;
+};
 
-const steamgriddbClient = writable<SGDB | null>(null)
-const lastGame = writable<LastGame | null>(null)
+const steamgriddbClient = writable<SGDB | null>(null);
+const lastGame = writable<LastGame | null>(null);
 
 export const steamUpdateNowPlaying = async () => {
-    var griddbClient = get(steamgriddbClient)
-    if (griddbClient === null) {
-        griddbClient = new SGDB(env.STEAMGRIDDB_API_KEY)
-        steamgriddbClient.set(griddbClient)
-    }
-    try {
-        var profile = (await (await fetch(GET_PLAYER_SUMMARY_ENDPOINT)).json()).response.players[0]
-        if (!profile.gameid) {
-            throw "no game is being played"
-        }
-        var icons = await griddbClient.getIconsBySteamAppId(profile.gameid, ['official', 'custom'])
-        //console.log(icons)
-        var game: LastGame = {
-            name: profile.gameextrainfo,
-            link: `https://store.steampowered.com/app/${profile.gameid}`,
-            icon: icons[0].thumb.toString(),
-            pfp: profile.avatarmedium,
-            when: Date.now(),
-            playing: true,
-        }
-        lastGame.set(game)
-    } catch(why) {
-        console.log("could not fetch steam: ", why)
-        lastGame.update((t) => { if (t !== null) { t.playing = false; } return t })
-    }
-}
+	let griddbClient = get(steamgriddbClient);
+	if (griddbClient === null) {
+		griddbClient = new SGDB(env.STEAMGRIDDB_API_KEY);
+		steamgriddbClient.set(griddbClient);
+	}
+	try {
+		const profile = (await (await fetch(GET_PLAYER_SUMMARY_ENDPOINT)).json()).response.players[0];
+		if (!profile.gameid) {
+			throw 'no game is being played';
+		}
+		const icons = await griddbClient.getIconsBySteamAppId(profile.gameid, ['official', 'custom']);
+		//console.log(icons)
+		const game: LastGame = {
+			name: profile.gameextrainfo,
+			link: `https://store.steampowered.com/app/${profile.gameid}`,
+			icon: icons[0].thumb.toString(),
+			pfp: profile.avatarmedium,
+			when: Date.now(),
+			playing: true
+		};
+		lastGame.set(game);
+	} catch (why) {
+		console.log('could not fetch steam: ', why);
+		lastGame.update((t) => {
+			if (t !== null) {
+				t.playing = false;
+			}
+			return t;
+		});
+	}
+};
 
-export const getLastGame = () => { return get(lastGame) }
\ No newline at end of file
+export const getLastGame = () => {
+	return get(lastGame);
+};
diff --git a/src/lib/visits.ts b/src/lib/visits.ts
index 8b15999..b0b85df 100644
--- a/src/lib/visits.ts
+++ b/src/lib/visits.ts
@@ -1,110 +1,122 @@
-import { env } from "$env/dynamic/private";
-import { scopeCookies } from "$lib";
-import type { Cookies } from "@sveltejs/kit";
-import { existsSync, readFileSync, writeFileSync } from "fs";
-import { nanoid } from "nanoid";
-import { get, writable } from "svelte/store";
+import { env } from '$env/dynamic/private';
+import { scopeCookies } from '$lib';
+import type { Cookies } from '@sveltejs/kit';
+import { existsSync, readFileSync, writeFileSync } from 'fs';
+import { nanoid } from 'nanoid';
+import { get, writable } from 'svelte/store';
 
-const visitCountFile = `${env.WEBSITE_DATA_DIR}/visitcount`
-const visitCount = writable(parseInt(existsSync(visitCountFile) ? readFileSync(visitCountFile).toString() : '0'))
+const visitCountFile = `${env.WEBSITE_DATA_DIR}/visitcount`;
+const visitCount = writable(
+	parseInt(existsSync(visitCountFile) ? readFileSync(visitCountFile).toString() : '0')
+);
 
-type Visitor = { visits: number[] }
-const lastVisitors = writable<Map<string, Visitor>>(new Map())
-const VISITOR_EXPIRY_SECONDS = 60 * 60 // an hour seems reasonable
+type Visitor = { visits: number[] };
+const lastVisitors = writable<Map<string, Visitor>>(new Map());
+const VISITOR_EXPIRY_SECONDS = 60 * 60; // an hour seems reasonable
 
 export const incrementVisitCount = (request: Request, cookies: Cookies) => {
-    let currentVisitCount = get(visitCount)
-    // check whether the request is from a bot or not (this doesnt need to be accurate we just want to filter out honest bots)
-    if (isBot(request)) { return currentVisitCount }
-    const scopedCookies = scopeCookies(cookies, '/')
-    // parse the last visit timestamp from cookies if it exists
-    const visitedTimestamp = parseInt(scopedCookies.get('visitedTimestamp') || "0")
-    // get unix timestamp
-    const currentTime = Date.now()
-    const timeSinceVisit = currentTime - visitedTimestamp
-    // check if this is the first time a client is visiting or if an hour has passed since they last visited
-    if (visitedTimestamp === 0 || timeSinceVisit > 1000 * 60 * 60 * 24) {
-        // increment current and write to the store
-        currentVisitCount += 1; visitCount.set(currentVisitCount)
-        // update the cookie with the current timestamp
-        scopedCookies.set('visitedTimestamp', currentTime.toString())
-        // write the visit count to a file so we can load it later again
-        writeFileSync(visitCountFile, currentVisitCount.toString())
-    }
-    return currentVisitCount
-}
+	let currentVisitCount = get(visitCount);
+	// check whether the request is from a bot or not (this doesnt need to be accurate we just want to filter out honest bots)
+	if (isBot(request)) {
+		return currentVisitCount;
+	}
+	const scopedCookies = scopeCookies(cookies, '/');
+	// parse the last visit timestamp from cookies if it exists
+	const visitedTimestamp = parseInt(scopedCookies.get('visitedTimestamp') || '0');
+	// get unix timestamp
+	const currentTime = Date.now();
+	const timeSinceVisit = currentTime - visitedTimestamp;
+	// check if this is the first time a client is visiting or if an hour has passed since they last visited
+	if (visitedTimestamp === 0 || timeSinceVisit > 1000 * 60 * 60 * 24) {
+		// increment current and write to the store
+		currentVisitCount += 1;
+		visitCount.set(currentVisitCount);
+		// update the cookie with the current timestamp
+		scopedCookies.set('visitedTimestamp', currentTime.toString());
+		// write the visit count to a file so we can load it later again
+		writeFileSync(visitCountFile, currentVisitCount.toString());
+	}
+	return currentVisitCount;
+};
 
 export const addLastVisitor = (request: Request, cookies: Cookies) => {
-    let visitors = get(lastVisitors)
-    visitors = _addLastVisitor(visitors, request, cookies)
-    lastVisitors.set(visitors)
-    return visitors
-}
+	let visitors = get(lastVisitors);
+	visitors = _addLastVisitor(visitors, request, cookies);
+	lastVisitors.set(visitors);
+	return visitors;
+};
 
 export const getVisitorId = (cookies: Cookies) => {
-    const scopedCookies = scopeCookies(cookies, '/')
-    // parse the last visit timestamp from cookies if it exists
-    return scopedCookies.get('visitorId')
-}
+	const scopedCookies = scopeCookies(cookies, '/');
+	// parse the last visit timestamp from cookies if it exists
+	return scopedCookies.get('visitorId');
+};
 
 // why not use this for incrementVisitCount? cuz i wanna have separate visit counts (one per hour and one per day, per hour being recent visitors)
 const _addLastVisitor = (visitors: Map<string, Visitor>, request: Request, cookies: Cookies) => {
-    const currentTime = Date.now()
-    // filter out old entries
-    visitors.forEach((visitor, id, map) => {
-        if (currentTime - visitor.visits[0] > 1000 * VISITOR_EXPIRY_SECONDS)
-            map.delete(id)
-        else {
-            visitor.visits = visitor.visits.filter((since) => {
-                return currentTime - since < 1000 * VISITOR_EXPIRY_SECONDS
-            })
-            map.set(id, visitor)
-        }
-    })
-    // check whether the request is from a bot or not (this doesnt need to be accurate we just want to filter out honest bots)
-    if (isBot(request)) { return visitors }
-    const scopedCookies = scopeCookies(cookies, '/')
-    // parse the last visit timestamp from cookies if it exists
-    let visitorId = scopedCookies.get('visitorId') || ""
-    // if no such id exists, create one and assign it to the client
-    if (! visitors.has(visitorId)) {
-        visitorId = nanoid()
-        scopedCookies.set('visitorId', visitorId)
-        console.log(`new client visitor id ${visitorId}`)
-    }
-    // update the entry
-    let visitorEntry = visitors.get(visitorId) || {visits: []}
-    // put new visit in the front
-    visitorEntry.visits = [currentTime].concat(visitorEntry.visits)
-    visitors.set(visitorId, visitorEntry);
-    return visitors
-}
+	const currentTime = Date.now();
+	// filter out old entries
+	visitors.forEach((visitor, id, map) => {
+		if (currentTime - visitor.visits[0] > 1000 * VISITOR_EXPIRY_SECONDS) map.delete(id);
+		else {
+			visitor.visits = visitor.visits.filter((since) => {
+				return currentTime - since < 1000 * VISITOR_EXPIRY_SECONDS;
+			});
+			map.set(id, visitor);
+		}
+	});
+	// check whether the request is from a bot or not (this doesnt need to be accurate we just want to filter out honest bots)
+	if (isBot(request)) {
+		return visitors;
+	}
+	const scopedCookies = scopeCookies(cookies, '/');
+	// parse the last visit timestamp from cookies if it exists
+	let visitorId = scopedCookies.get('visitorId') || '';
+	// if no such id exists, create one and assign it to the client
+	if (!visitors.has(visitorId)) {
+		visitorId = nanoid();
+		scopedCookies.set('visitorId', visitorId);
+		console.log(`new client visitor id ${visitorId}`);
+	}
+	// update the entry
+	const visitorEntry = visitors.get(visitorId) || { visits: [] };
+	// put new visit in the front
+	visitorEntry.visits = [currentTime].concat(visitorEntry.visits);
+	visitors.set(visitorId, visitorEntry);
+	return visitors;
+};
 
 const isBot = (request: Request) => {
-    const ua = request.headers.get('user-agent')
-    return ua ? ua.toLowerCase().match(/(bot|crawl|spider|walk|fetch|scrap|proxy|image)/) !== null : true
-}
+	const ua = request.headers.get('user-agent');
+	return ua
+		? ua.toLowerCase().match(/(bot|crawl|spider|walk|fetch|scrap|proxy|image)/) !== null
+		: true;
+};
 
 export const notifyDarkVisitors = (url: URL, request: Request) => {
-    fetch('https://api.darkvisitors.com/visits', {
-        method: 'POST',
-        headers: {
-            authorization: `Bearer ${env.DARK_VISITORS_TOKEN}`,
-            'content-type': 'application/json',
-        },
-        body: JSON.stringify({
-            request_path: url.pathname,
-            request_method: request.method,
-            request_headers: request.headers,
-        })
-    }).catch((why) => {
-        console.log("failed sending dark visitors analytics:", why)
-        return null
-    }).then(async (resp) => {
-        if (resp !== null) {
-            const msg = await resp.json()
-            const host = `(${request.headers.get('host')} ${request.headers.get('x-real-ip')})`
-            console.log(`sent visitor analytic to dark visitors: ${resp.statusText}; ${msg.message ?? ''}${host}`)
-        }
-    })
-}
\ No newline at end of file
+	fetch('https://api.darkvisitors.com/visits', {
+		method: 'POST',
+		headers: {
+			authorization: `Bearer ${env.DARK_VISITORS_TOKEN}`,
+			'content-type': 'application/json'
+		},
+		body: JSON.stringify({
+			request_path: url.pathname,
+			request_method: request.method,
+			request_headers: request.headers
+		})
+	})
+		.catch((why) => {
+			console.log('failed sending dark visitors analytics:', why);
+			return null;
+		})
+		.then(async (resp) => {
+			if (resp !== null) {
+				const msg = await resp.json();
+				const host = `(${request.headers.get('host')} ${request.headers.get('x-real-ip')})`;
+				console.log(
+					`sent visitor analytic to dark visitors: ${resp.statusText}; ${msg.message ?? ''}${host}`
+				);
+			}
+		});
+};
diff --git a/src/lib/window.ts b/src/lib/window.ts
index 2783b14..a8700ff 100644
--- a/src/lib/window.ts
+++ b/src/lib/window.ts
@@ -1,9 +1,20 @@
-import { writable } from "svelte/store";
+/* eslint-disable no-useless-escape */
+import { writable } from 'svelte/store';
 
-export const highestZIndex = writable(0)
+export const highestZIndex = writable(0);
 
 export const isMobile = () => {
-    let check = false;
-    (function (a) { if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4))) check = true; })(navigator.userAgent || navigator.vendor);
-    return check;
-}
\ No newline at end of file
+	let check = false;
+	(function (a) {
+		if (
+			/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(
+				a
+			) ||
+			/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(
+				a.slice(0, 4)
+			)
+		)
+			check = true;
+	})(navigator.userAgent || navigator.vendor);
+	return check;
+};
diff --git a/src/routes/+layout.server.ts b/src/routes/+layout.server.ts
index b6e943c..2c77762 100644
--- a/src/routes/+layout.server.ts
+++ b/src/routes/+layout.server.ts
@@ -5,26 +5,26 @@ import { error } from '@sveltejs/kit';
 export const csr = true;
 export const ssr = true;
 export const prerender = false;
-export const trailingSlash = 'always'; 
+export const trailingSlash = 'always';
 
 export async function load({ request, cookies, url }) {
-    notifyDarkVisitors(url, request) // no await so it doesnt block load
+	notifyDarkVisitors(url, request); // no await so it doesnt block load
 
-    // block any requests if the user agent is disallowed by our robots txt
-    if (await testUa(url.toString(), request.headers.get('user-agent') ?? "") === false) {
-        throw error(403, "get a better user agent silly")
-    }
+	// block any requests if the user agent is disallowed by our robots txt
+	if ((await testUa(url.toString(), request.headers.get('user-agent') ?? '')) === false) {
+		throw error(403, 'get a better user agent silly');
+	}
 
-    const lastVisitors = addLastVisitor(request, cookies)
-    let recentVisitCount = 0
-    for (const [_, visitor] of lastVisitors) {
-        recentVisitCount += visitor.visits.length
-    }
+	const lastVisitors = addLastVisitor(request, cookies);
+	let recentVisitCount = 0;
+	for (const [, visitor] of lastVisitors) {
+		recentVisitCount += visitor.visits.length;
+	}
 
-    return {
-        route: url.pathname,
-        visitCount: incrementVisitCount(request, cookies),
-        lastVisitors,
-        recentVisitCount,
-    }
+	return {
+		route: url.pathname,
+		visitCount: incrementVisitCount(request, cookies),
+		lastVisitors,
+		recentVisitCount
+	};
 }
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte
index f9ef313..acc193c 100644
--- a/src/routes/+layout.svelte
+++ b/src/routes/+layout.svelte
@@ -5,6 +5,7 @@
 	import '../styles/app.css';
 
 	interface Props {
+		// eslint-disable-next-line @typescript-eslint/no-explicit-any
 		data: any;
 		children?: import('svelte').Snippet;
 	}
@@ -73,7 +74,7 @@
 			<filter id="squiggly-{index}">
 				<feTurbulence
 					id="turbulence"
-					baseFrequency=0.03
+					baseFrequency="0.03"
 					numOctaves="3"
 					result="noise"
 					seed={index}
@@ -134,7 +135,9 @@
 	</defs>
 </svg>
 
-<div class="md:h-[96vh] pb-[8vh] lg:px-[1vw] 2xl:px-[2vw] lg:pb-[3vh] lg:pt-[1vh] overflow-x-hidden [scrollbar-gutter:stable]">
+<div
+	class="md:h-[96vh] pb-[8vh] lg:px-[1vw] 2xl:px-[2vw] lg:pb-[3vh] lg:pt-[1vh] overflow-x-hidden [scrollbar-gutter:stable]"
+>
 	{@render children?.()}
 </div>
 
@@ -152,7 +155,12 @@
 				{@const highlight = isRoute(item.href)}
 				<NavButton {highlight} {...item} />
 				{#if doAddPostItem && menuIdx == 1}
-					<NavButton highlight name={routeComponents[2]} href={data.route.slice(1)} iconUri='/icons/entry.webp'/>
+					<NavButton
+						highlight
+						name={routeComponents[2]}
+						href={data.route.slice(1)}
+						iconUri="/icons/entry.webp"
+					/>
 				{/if}
 			{/each}
 			<div class="hidden md:block grow"></div>
@@ -163,22 +171,33 @@
 			</div>
 			<Tooltip>
 				{#snippet tooltipContent()}
-							
-						<p class="font-monospace">
-							<nobr>total visits = <span class="text-ralsei-green-light text-shadow-green">{data.visitCount.toString().padStart(9, ".")}</span></nobr>
-							<nobr>uniq recent visits = <span class="text-ralsei-green-light text-shadow-green">{data.lastVisitors.size.toString().padStart(3, ".")}</span></nobr>
-						</p>
-					
-							{/snippet}
-				<div class="navbox"><p><span class="text-ralsei-green-light text-shadow-green">{data.recentVisitCount}</span> recent clicks</p></div>
+					<p class="font-monospace">
+						<nobr
+							>total visits = <span class="text-ralsei-green-light text-shadow-green"
+								>{data.visitCount.toString().padStart(9, '.')}</span
+							></nobr
+						>
+						<nobr
+							>uniq recent visits = <span class="text-ralsei-green-light text-shadow-green"
+								>{data.lastVisitors.size.toString().padStart(3, '.')}</span
+							></nobr
+						>
+					</p>
+				{/snippet}
+				<div class="navbox">
+					<p>
+						<span class="text-ralsei-green-light text-shadow-green">{data.recentVisitCount}</span> recent
+						clicks
+					</p>
+				</div>
 			</Tooltip>
-			{#if isRoute("entries") || isRoute("log")}
-			<div class="navbox !gap-1">
-				rss:
-				<a class="align-middle hover:underline" href="/entries/_rss">posts</a>
-				/
-				<a class="align-middle hover:underline" href="/log/_rss">log</a>
-			</div>
+			{#if isRoute('entries') || isRoute('log')}
+				<div class="navbox !gap-1">
+					rss:
+					<a class="align-middle hover:underline" href="/entries/_rss">posts</a>
+					/
+					<a class="align-middle hover:underline" href="/log/_rss">log</a>
+				</div>
 			{/if}
 		</div>
 	</div>
@@ -189,4 +208,4 @@
 		@apply flex gap-3 px-1.5 text-nowrap align-middle items-center text-center place-content-center border-ralsei-white border-4;
 		border-style: groove;
 	}
-</style>
\ No newline at end of file
+</style>
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte
index 67a4a51..e9c06d7 100644
--- a/src/routes/+page.svelte
+++ b/src/routes/+page.svelte
@@ -3,9 +3,10 @@
 	import Note from '../components/note.svelte';
 	import Window from '../components/window.svelte';
 	import LatestStuff from './lateststuff.md';
-	import {renderDate, renderRelativeDate} from '$lib/dateFmt';
+	import { renderDate, renderRelativeDate } from '$lib/dateFmt';
 
 	interface Props {
+		// eslint-disable-next-line @typescript-eslint/no-explicit-any
 		data: any;
 	}
 
@@ -16,9 +17,7 @@
 	<div class="flex flex-col gap-y-2 lg:gap-y-0 mx-auto">
 		<Window title="readme?" iconUri="/icons/question.webp" removePadding>
 			<div class="flex flex-col p-1.5 gap-1.5 prose prose-ralsei prose-img:m-0 leading-none">
-				<div
-					class="flex flex-row gap-3 mx-auto bg-ralsei-black/20 overflow-hidden"
-				>
+				<div class="flex flex-row gap-3 mx-auto bg-ralsei-black/20 overflow-hidden">
 					{#each data.banners as bannerNo, index}
 						{@const hideIfMobile = index === data.banners.length - 1}
 						<img
@@ -35,10 +34,13 @@
 					{/each}
 				</div>
 				<div class="flex flex-grow">
-					<div
-						class="w-36 [padding:8px] place-content-center place-self-center bg-ralsei-black/20"
-					>
-					<img class="w-36 u-photo hover:invert transition-all [transition-duration:300ms]" src="/pfp-iojkqpwerojnasduijf.webp" alt="my character" title="hi ;)"/>
+					<div class="w-36 [padding:8px] place-content-center place-self-center bg-ralsei-black/20">
+						<img
+							class="w-36 u-photo hover:invert transition-all [transition-duration:300ms]"
+							src="/pfp-iojkqpwerojnasduijf.webp"
+							alt="my angelsona"
+							title="that's me! my angelsona :3c"
+						/>
 					</div>
 					<div
 						class="flex flex-row flex-grow place-content-center ml-1.5 [padding:8px] bg-ralsei-black/20"
@@ -47,7 +49,9 @@
 							class="place-self-center m-0 mr-4 [padding-left:1em] sm:[padding-left:0.5em] leading-none marker:[content:'->'] [list-style-type:'->']"
 						>
 							<li class="[list-style-type:'->'] p-note">trying to do stuff</li>
-							<li class="[list-style-type:'->'] p-note">is a thing that exists</li>
+							<li class="[list-style-type:'->'] p-note" title="angelrobotdollpuppything">
+								is a thing (it/they)
+							</li>
 							<li class="[list-style-type:'->']">
 								<span class="p-category">software engineer</span>,
 								<span class="p-category">indie game dev</span>
@@ -95,7 +99,9 @@
 	</div>
 	<div class="flex flex-col gap-y-2 lg:gap-y-0 mx-auto w-full md:w-fit place-items-end">
 		<Window title="links!" iconUri="/icons/contact.webp">
-			<div class="prose prose-ralsei prose-ul:px-[0.9rem] prose-ul:leading-[1.1rem] prose-headings:leading-none">
+			<div
+				class="prose prose-ralsei prose-ul:px-[0.9rem] prose-ul:leading-[1.1rem] prose-headings:leading-none"
+			>
 				<ul>
 					<li>discord: yusdacra</li>
 					<li>
@@ -135,102 +141,110 @@
 				</ul>
 				<h4>88x31</h4>
 				<div class="flex flex-row flex-wrap gap-1 prose-img:m-0">
-					<img src="/88x31.gif" alt="88x31 banner" title="midnight AND sunrise! woaw"/>
-					<img src="/88x31_midnight.gif" alt="88x31 banner (midnight only)" title="it's midnight!"/>
-					<img src="/88x31_sunrise.gif" alt="88x31 banner (sunrise only)" title="it's sunrise!"/>
+					<img src="/88x31.gif" alt="88x31 banner" title="midnight AND sunrise! woaw" />
+					<img
+						src="/88x31_midnight.gif"
+						alt="88x31 banner (midnight only)"
+						title="it's midnight!"
+					/>
+					<img src="/88x31_sunrise.gif" alt="88x31 banner (sunrise only)" title="it's sunrise!" />
 				</div>
 			</div>
 		</Window>
 		<Window title="status" style="mt-auto" removePadding>
 			{#if data.lastNote}
-			<div class="m-1.5 flex flex-col font-monospace text-sm">
-				<p
-					class="prose prose-ralsei p-1 border-4 text-sm bg-ralsei-black"
-					style="border-style: double double none double;"
-					title={renderDate(data.lastNote.published)}
-				>
-					<a href="/entries">last log was…</a>
-					published {renderRelativeDate(data.lastNote.published)}!
-				</p>
-				<div class="mt-0 p-1.5 border-4 border-double bg-ralsei-black min-w-full max-w-[40ch]">
-					<Note note={data.lastNote} onlyContent/>
+				<div class="m-1.5 flex flex-col font-monospace text-sm">
+					<p
+						class="prose prose-ralsei p-1 border-4 text-sm bg-ralsei-black"
+						style="border-style: double double none double;"
+						title={renderDate(data.lastNote.published)}
+					>
+						<a href="/entries">last log was…</a>
+						published {renderRelativeDate(data.lastNote.published)}!
+					</p>
+					<div class="mt-0 p-1.5 border-4 border-double bg-ralsei-black min-w-full max-w-[40ch]">
+						<Note note={data.lastNote} onlyContent />
+					</div>
 				</div>
-			</div>
 			{/if}
 			{#if data.lastTrack}
-			<div class="flex flex-row gap-0.5 m-1.5 border-4 border-double bg-ralsei-black">
-				<!-- svelte-ignore a11y_missing_attribute -->
-				{#if data.lastTrack.image}
+				<div class="flex flex-row gap-0.5 m-1.5 border-4 border-double bg-ralsei-black">
+					<!-- svelte-ignore a11y_missing_attribute -->
+					{#if data.lastTrack.image}
+						<img
+							class="border-4 w-[4.5rem] h-[4.5rem]"
+							style="border-style: none double none none;"
+							src={data.lastTrack.image}
+						/>
+					{:else}
+						<img
+							class="border-4 w-[4.5rem] h-[4.5rem] p-2"
+							style="border-style: none double none none; image-rendering: pixelated;"
+							src="/icons/cd_audio.webp"
+						/>
+					{/if}
+					<div class="flex flex-col max-w-[40ch] p-2">
+						<p
+							class="text-shadow-green text-ralsei-green-light text-sm text-ellipsis text-nowrap overflow-hidden max-w-[30ch]"
+						>
+							<span class="text-sm text-shadow-white text-ralsei-white"
+								>{data.lastTrack.playing ? 'listening to' : 'listened to'}</span
+							>
+							<a
+								title={data.lastTrack.name}
+								href="https://www.last.fm/user/yusdacra"
+								class="hover:underline motion-safe:hover:animate-squiggle">{data.lastTrack.name}</a
+							>
+						</p>
+						<p
+							class="text-shadow-pink text-ralsei-pink-regular text-sm text-ellipsis text-nowrap overflow-hidden max-w-[30ch]"
+						>
+							<span class="text-shadow-white text-ralsei-white">by</span>
+							<span title={data.lastTrack.artist}>{data.lastTrack.artist}</span>
+						</p>
+						<p
+							class="text-shadow-white text-ralsei-white text-xs text-ellipsis text-nowrap overflow-hidden max-w-[30ch]"
+						>
+							…{renderRelativeDate(data.lastTrack.when)}
+						</p>
+					</div>
+				</div>
+			{/if}
+			{#if data.lastGame}
+				<div class="flex flex-row m-1.5 border-4 border-double bg-ralsei-black">
+					<!-- svelte-ignore a11y_missing_attribute -->
 					<img
 						class="border-4 w-[4.5rem] h-[4.5rem]"
 						style="border-style: none double none none;"
-						src={data.lastTrack.image}
+						width="64"
+						height="64"
+						src={data.lastGame.icon}
 					/>
-				{:else}
-					<img
-						class="border-4 w-[4.5rem] h-[4.5rem] p-2"
-						style="border-style: none double none none; image-rendering: pixelated;"
-						src="/icons/cd_audio.webp"
-					/>
-				{/if}
-				<div class="flex flex-col max-w-[40ch] p-2">
-					<p
-						class="text-shadow-green text-ralsei-green-light text-sm text-ellipsis text-nowrap overflow-hidden max-w-[30ch]"
-					>
-						<span class="text-sm text-shadow-white text-ralsei-white">{data.lastTrack.playing ? "listening to" : "listened to"}</span>
+					<div class="flex flex-col max-w-[40ch] p-2 gap-0.5 overflow-hidden">
+						<p
+							class="text-shadow-green text-ralsei-green-light text-sm text-ellipsis text-nowrap overflow-hidden max-w-[30ch]"
+						>
+							<span class="text-sm text-shadow-white text-ralsei-white"
+								>{data.lastGame.playing ? 'playing' : 'played'}</span
+							>
+							<a title={data.lastGame.name} class="hover:underline" href={data.lastGame.link}
+								>{data.lastGame.name}</a
+							>
+						</p>
+						<p
+							class="text-shadow-white text-ralsei-white text-xs text-ellipsis text-nowrap overflow-hidden max-w-[30ch]"
+						>
+							…{renderRelativeDate(data.lastGame.when)}
+						</p>
+						<!-- svelte-ignore a11y_missing_attribute -->
 						<a
-							title={data.lastTrack.name}
-							href="https://www.last.fm/user/yusdacra"
-							class="hover:underline motion-safe:hover:animate-squiggle">{data.lastTrack.name}</a
+							href="https://steamcommunity.com/id/yusdacra"
+							class="text-xs hover:underline text-shadow-green text-ralsei-green-light"
+							><img class="inline w-4" src={data.lastGame.pfp} />
+							<span class="align-middle">steam profile</span></a
 						>
-					</p>
-					<p
-						class="text-shadow-pink text-ralsei-pink-regular text-sm text-ellipsis text-nowrap overflow-hidden max-w-[30ch]"
-					>
-						<span class="text-shadow-white text-ralsei-white">by</span>
-						<span title={data.lastTrack.artist}>{data.lastTrack.artist}</span>
-					</p>
-					<p
-						class="text-shadow-white text-ralsei-white text-xs text-ellipsis text-nowrap overflow-hidden max-w-[30ch]"
-					>
-						…{renderRelativeDate(data.lastTrack.when)}
-					</p>
+					</div>
 				</div>
-			</div>
-			{/if}
-			{#if data.lastGame}
-			<div class="flex flex-row m-1.5 border-4 border-double bg-ralsei-black">
-				<!-- svelte-ignore a11y_missing_attribute -->
-				<img
-					class="border-4 w-[4.5rem] h-[4.5rem]"
-					style="border-style: none double none none;"
-					width="64"
-					height="64"
-					src={data.lastGame.icon}
-				/>
-				<div class="flex flex-col max-w-[40ch] p-2 gap-0.5 overflow-hidden">
-					<p
-						class="text-shadow-green text-ralsei-green-light text-sm text-ellipsis text-nowrap overflow-hidden max-w-[30ch]"
-					>
-						<span class="text-sm text-shadow-white text-ralsei-white">{data.lastGame.playing ? "playing" : "played"}</span>
-						<a title={data.lastGame.name} class="hover:underline" href={data.lastGame.link}
-							>{data.lastGame.name}</a
-						>
-					</p>
-					<p
-						class="text-shadow-white text-ralsei-white text-xs text-ellipsis text-nowrap overflow-hidden max-w-[30ch]"
-					>
-						…{renderRelativeDate(data.lastGame.when)}
-					</p>
-					<!-- svelte-ignore a11y_missing_attribute -->
-					<a
-						href="https://steamcommunity.com/id/yusdacra"
-						class="text-xs hover:underline text-shadow-green text-ralsei-green-light"
-						><img class="inline w-4" src={data.lastGame.pfp} />
-						<span class="align-middle">steam profile</span></a
-					>
-				</div>
-			</div>
 			{/if}
 		</Window>
 	</div>