johnandersen777.bsky.social/knotless
git that lives in your Atmosphere account
Forked from chadtmiller.com/knotless
0
0
<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 />