~ knotless Search/
↑↓ move↵ open⇧↵ all results

johnandersen777.bsky.social/knotless

git that lives in your Atmosphere account

Forked from chadtmiller.com/knotless

0
0
71 lines · 3.0 KB Raw History
<script lang="ts">
	import '../app.css';
	import { onMount, tick, untrack } from 'svelte';
	import { afterNavigate } from '$app/navigation';
	import { hit } from '#lib/hit.ts';
	import { followReturns } from '#lib/live.ts';
	import { clicked, closeMenus, pressed } from '#lib/menus.ts';
	import { recount, unread, watch } from '#lib/notifications.svelte.ts';
	import { COOKIE, zone } from '#lib/zone.svelte.ts';
	import SiteHeader from '#lib/organisms/SiteHeader.svelte';
	import SiteFooter from '#lib/organisms/SiteFooter.svelte';
	import GrantNote from '#lib/organisms/GrantNote.svelte';
	let { data, children } = $props();
	// Times are put in words in the zone and at the now the server read, so
	// the browser's first pass says what its HTML did. A page is drawn on the
	// server in one go, so what is set here holds for this page alone.
	untrack(() => {
		zone.tz = data.tz;
		zone.now = data.now;
		unread.count = data.unread;
	});
	// And again each time the layout's answers are asked again.
	$effect.pre(() => {
		unread.count = data.unread;
	});
	// Once the page is running, it keeps the browser's zone, in the cookie
	// for the next page the server draws and here if it was not known, and
	// its now, to the minute; then it is marked, with its highlighting
	// painted: what the screenshots wait for.
	onMount(() => {
		const tz = Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC';
		const secure = location.protocol === 'https:' ? '; secure' : '';
		document.cookie = `${COOKIE}=${encodeURIComponent(tz)}; path=/; max-age=31536000; samesite=lax${secure}`;
		zone.tz = tz;
		zone.now = Date.now();
		const minutes = setInterval(() => (zone.now = Date.now()), 60_000);
		tick().then(() => document.documentElement.setAttribute('data-ready', ''));
		// A browser that shows notifications asks for them as the tab stays open.
		const unwatch = data.viewer?.actor ? watch() : () => {};
		// A page left a while, or offline, is drawn again from fresh answers.
		const unfollow = followReturns();
		return () => {
			clearInterval(minutes);
			unwatch();
			unfollow();
		};
	});
	// Each page drawn, counted for the operator: see hit.ts.
	afterNavigate(hit);
	// A menu's link drawing the next page leaves it open: see menus.ts.
	afterNavigate(() => closeMenus());
	// Kit keeps the scroll to itself, so a reload would paint at the top and
	// jump back only once it runs: the browser keeps the place while the page
	// is away instead, and Kit has it back for its own navigations.
	function away() {
		history.scrollRestoration = 'auto';
	}
	function back() {
		history.scrollRestoration = 'manual';
	}
	// A tab left in the background counts again once it is looked at.
	function shown() {
		if (data.viewer?.actor && document.visibilityState === 'visible') void recount();
	}
</script>

<svelte:window onpagehide={away} onpageshow={back} />
<svelte:document onclick={clicked} onkeydown={pressed} onvisibilitychange={shown} />
<SiteHeader viewer={data.viewer} />
<main class="wrap"><GrantNote viewer={data.viewer} />{@render children()}</main>
<SiteFooter />