mirror of
https://github.com/Patiun/com.gregkilmer.www.git
synced 2026-11-08 04:08:24 +00:00
Initial Commit
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* reveal-init.ts
|
||||
* ---------------------------------------------------------------------------
|
||||
* The other half of Reveal.astro. Reveal.astro stamps each wrapper with the
|
||||
* `reveal` class (opacity:0, set in global.css) and a `data-reveal` hook, but
|
||||
* it ships NO script of its own. This module is what actually flips those
|
||||
* elements to `is-visible` when they scroll into view.
|
||||
*
|
||||
* Without it every page's content is stuck at opacity:0 (the original bug).
|
||||
*
|
||||
* It also removes the `no-js` class from <html> as its first act, so that the
|
||||
* `.no-js .reveal { opacity: 1 }` guard in global.css only applies when JS is
|
||||
* genuinely unavailable — i.e. content is NEVER invisible, even if this script
|
||||
* fails to load for some reason.
|
||||
*
|
||||
* Honors prefers-reduced-motion: elements are revealed instantly.
|
||||
*/
|
||||
export function initReveals(): void {
|
||||
const root = document.documentElement;
|
||||
|
||||
// 1. Flip <html class="no-js"> -> the JS guard no longer applies; CSS reveals
|
||||
// remain at opacity:0 until we toggle them (or instantly under reduced motion).
|
||||
root.classList.remove('no-js');
|
||||
|
||||
const targets = Array.from(
|
||||
document.querySelectorAll<HTMLElement>('[data-reveal]'),
|
||||
);
|
||||
if (targets.length === 0) return;
|
||||
|
||||
const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||
|
||||
// Reduced motion: show everything immediately, no observer needed.
|
||||
if (reduce) {
|
||||
for (const el of targets) el.classList.add('is-visible');
|
||||
return;
|
||||
}
|
||||
|
||||
// Anything already in view on load should appear at once (avoid a late pop).
|
||||
const reveal = (el: HTMLElement) => el.classList.add('is-visible');
|
||||
|
||||
const io = new IntersectionObserver(
|
||||
(entries, observer) => {
|
||||
for (const entry of entries) {
|
||||
if (entry.isIntersecting) {
|
||||
reveal(entry.target as HTMLElement);
|
||||
observer.unobserve(entry.target);
|
||||
}
|
||||
}
|
||||
},
|
||||
{ rootMargin: '0px 0px -8% 0px', threshold: 0.08 },
|
||||
);
|
||||
|
||||
for (const el of targets) io.observe(el);
|
||||
}
|
||||
|
||||
// Run on first load.
|
||||
initReveals();
|
||||
|
||||
// Re-run after Astro View Transitions swap in new DOM.
|
||||
document.addEventListener('astro:page-load', initReveals);
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* theme-init.ts
|
||||
* ---------------------------------------------------------------------------
|
||||
* Inlined (as a string) into the <head> of BaseLayout.astro so it runs BEFORE
|
||||
* first paint. Reads the saved theme from localStorage, falling back to the OS
|
||||
* preference via prefers-color-scheme, and sets `data-theme` on <html>.
|
||||
*
|
||||
* Doing this inline + blocking is what prevents the flash-of-wrong-theme (FOUC).
|
||||
* Keep this file dependency-free and tiny: it ships to every page.
|
||||
*/
|
||||
|
||||
export const themeInitScript = `
|
||||
(function () {
|
||||
try {
|
||||
var STORAGE_KEY = 'gk-theme';
|
||||
var stored = localStorage.getItem(STORAGE_KEY);
|
||||
var prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
var theme = stored || (prefersDark ? 'dark' : 'light');
|
||||
document.documentElement.setAttribute('data-theme', theme);
|
||||
|
||||
// React to OS theme changes only if the user hasn't chosen explicitly.
|
||||
if (!stored) {
|
||||
var mq = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
var onChange = function (e) {
|
||||
document.documentElement.setAttribute('data-theme', e.matches ? 'dark' : 'light');
|
||||
};
|
||||
if (mq.addEventListener) mq.addEventListener('change', onChange);
|
||||
else if (mq.addListener) mq.addListener(onChange);
|
||||
}
|
||||
} catch (e) {
|
||||
// If anything fails (private mode, etc.), default to light.
|
||||
document.documentElement.setAttribute('data-theme', 'light');
|
||||
}
|
||||
})();
|
||||
`;
|
||||
|
||||
export default themeInitScript;
|
||||
Reference in New Issue
Block a user