--- import GlobalStyles from "../components/GlobalStyles.astro"; import '@fontsource/roboto/400.css'; import '@fontsource/roboto/500.css'; import '@fontsource/roboto/700.css'; import { ViewTransitions } from 'astro:transitions'; import ImageBox from "../components/misc/ImageBox.astro"; import { fade } from 'astro:transitions'; import {pathsEqual} from "../utils/url-utils"; import ConfigCarrier from "../components/ConfigCarrier.astro"; import {siteConfig} from "../config"; interface Props { title: string; banner: string; } let { title, banner } = Astro.props; const isHomePage = pathsEqual(Astro.url.pathname, '/') || pathsEqual(Astro.url.pathname, '/page/1'); const testPathName = Astro.url.pathname; const anim = { old: { name: 'fadeIn', duration: '4s', easing: 'linear', fillMode: 'forwards', mixBlendMode: 'normal', }, new: { name: 'fadeOut', duration: '4s', easing: 'linear', fillMode: 'backwards', mixBlendMode: 'normal', } }; const myFade = { forwards: anim, backwards: anim, }; // defines global css variables // why doing this in Layout instead of GlobalStyles: https://github.com/withastro/astro/issues/6728#issuecomment-1502203757 const configHue = siteConfig.themeHue; if (!banner || typeof banner !== 'string' || banner.trim() === '') { banner = siteConfig.banner.src; } // TODO don't use post cover as banner for now banner = siteConfig.banner.src; let pageTitle; if (title) { pageTitle = `${title} - ${siteConfig.title}`; } else { pageTitle = `${siteConfig.title} - ${siteConfig.subtitle}`; } --- <!DOCTYPE html> <html lang="en" isHome={isHomePage} pathname={testPathName} class="bg-[var(--page-bg)] transition"> <head> <ViewTransitions /> <title>{pageTitle}</title> <meta charset="UTF-8" /> <meta name="description" content="Astro description"> <meta name="viewport" content="width=device-width" /> <meta name="generator" content={Astro.generator} /> <link rel="icon" media="(prefers-color-scheme: light)" href="/favicon/favicon-light-32.png" sizes="32x32"> <link rel="icon" media="(prefers-color-scheme: light)" href="/favicon/favicon-light-128.png" sizes="128x128"> <link rel="icon" media="(prefers-color-scheme: light)" href="/favicon/favicon-light-180.png" sizes="180x180"> <link rel="icon" media="(prefers-color-scheme: light)" href="/favicon/favicon-light-192.png" sizes="192x192"> <link rel="icon" media="(prefers-color-scheme: dark)" href="/favicon/favicon-dark-32.png" sizes="32x32"> <link rel="icon" media="(prefers-color-scheme: dark)" href="/favicon/favicon-dark-128.png" sizes="128x128"> <link rel="icon" media="(prefers-color-scheme: dark)" href="/favicon/favicon-dark-180.png" sizes="180x180"> <link rel="icon" media="(prefers-color-scheme: dark)" href="/favicon/favicon-dark-192.png" sizes="192x192"> <link rel="stylesheet" href="https://cdn.staticfile.org/KaTeX/0.16.9/katex.min.css" integrity="sha384-n8MVd4RsNIU0tAv4ct0nTaAbDJwPJzDEaqSD1odI+WdtXRGWt2kTvGFasHpSy3SV" crossorigin="anonymous"> <style define:vars={{ configHue }}></style> <!-- defines global css variables. This will be applied to <html> <body> and some other elements idk why --> </head> <body class=" min-h-screen transition "> <ConfigCarrier></ConfigCarrier> <GlobalStyles> <div id="banner-wrapper" class="absolute w-full transition-all" class:list={{'banner-home': isHomePage, 'banner-else': !isHomePage}} > <ImageBox id="boxtest" alt="Banner image of the blog" class:list={["object-center object-cover h-full", {"hidden": !siteConfig.banner.enable}]} src={siteConfig.banner.src} transition:animate="fade" > </ImageBox> </div> <slot /> </GlobalStyles> </body> </html> <style is:global> :root { --hue: var(--configHue); --accent: 136, 58, 234; --accent-light: 224, 204, 250; --accent-dark: 49, 10, 101; --accent-gradient: linear-gradient(45deg, rgb(var(--accent)), rgb(var(--accent-light)) 30%, white 60%); --page-width: 1200px; } html { background: #13151A; background-size: 224px; } code { font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace; } </style> <style> @tailwind components; @tailwind utilities; @layer components { .banner-home { @apply h-[var(--banner-height)] md:h-[var(--banner-height-home)] } .banner-else { @apply h-[var(--banner-height)] } } #banner-wrapper { view-transition-name: banner-ani; } /* i don't know how this work*/ html::view-transition-old(banner-ani) { mix-blend-mode: normal; animation: none; height: 100%; overflow: clip; object-fit: none; } html::view-transition-new(banner-ani) { mix-blend-mode: normal; animation: none; height: 100%; overflow: clip; object-fit: none; } </style> <script> import 'overlayscrollbars/overlayscrollbars.css'; import { OverlayScrollbars, ScrollbarsHidingPlugin, SizeObserverPlugin, ClickScrollPlugin } from 'overlayscrollbars'; /* Preload fonts */ // (async function() { // try { // await Promise.all([ // document.fonts.load("400 1em Roboto"), // document.fonts.load("700 1em Roboto"), // ]); // document.body.classList.remove("hidden"); // } catch (error) { // console.log("Failed to load fonts:", error); // } // })(); /* TODO This is a temporary solution for style flicker issue when the transition is activated */ /* issue link: https://github.com/withastro/astro/issues/8711, the solution get from here too */ /* update: fixed in Astro 3.2.4 */ function disableAnimation() { const css = document.createElement('style') css.appendChild( document.createTextNode( `*{ -webkit-transition:none!important; -moz-transition:none!important; -o-transition:none!important; -ms-transition:none!important; transition:none!important }` ) ) document.head.appendChild(css) return () => { // Force restyle ;(() => window.getComputedStyle(document.body))() // Wait for next tick before removing setTimeout(() => { document.head.removeChild(css) }, 1) } } function activateDisplaySettings() { let output = document.getElementById("hueValue"); let slider = document.getElementById("colorSlider"); let configCarrier = document.getElementById("config-carrier"); output.innerHTML = slider.value; // Display the default slider value let r = document.querySelector(':root'); function setHue(hue) { localStorage.setItem('hue', hue); output.innerHTML = hue; slider.value = hue; r.style.setProperty(`--hue`, hue); } let storedHue = localStorage.getItem('hue'); if (storedHue) { setHue(storedHue); } else { setHue(configCarrier.dataset.hue); } slider.oninput = function() { let hue = this.value; output.innerHTML = this.value; setHue(hue); } function setClickOutsideToClose(panel, switchBtn) { document.addEventListener("click", event => { var cDom = document.getElementById(panel); let settingBtn = document.getElementById(switchBtn); var tDom = event.target; if (cDom == tDom || cDom.contains(tDom) || settingBtn == tDom || settingBtn.contains(tDom)) { return; } cDom.classList.add("closed"); }); } setClickOutsideToClose("display-setting", "display-settings-switch") setClickOutsideToClose("nav-menu-panel", "nav-menu-switch") } function loadTheme() { if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) { document.documentElement.classList.add('dark'); localStorage.theme = 'dark'; } else { document.documentElement.classList.remove('dark'); localStorage.theme = 'light'; } } function loadHue() { const hue = localStorage.hue; if (hue) { document.documentElement.style.setProperty('--hue', hue); } } function setBannerHeight() { const banner = document.getElementById('banner-wrapper'); if (document.documentElement.hasAttribute('isHome')) { banner.classList.remove('banner-else'); banner.classList.add('banner-home'); } else { banner.classList.remove('banner-home'); banner.classList.add('banner-else'); } } function initCustomScrollbar() { OverlayScrollbars(document.querySelector('body'), { scrollbars: { theme: 'scrollbar-base scrollbar-auto py-1', autoHide: 'move', autoHideDelay: 1300, autoHideSuspend: false } }); document.querySelectorAll('pre').forEach((ele) => { OverlayScrollbars(ele, { scrollbars: { theme: 'scrollbar-base scrollbar-dark px-2', autoHide: 'leave', autoHideDelay: 1300, autoHideSuspend: false } }); }); } function init() { // disableAnimation()() // TODO setBannerHeight(); loadTheme(); loadHue(); activateDisplaySettings(); initCustomScrollbar(); } /* Load settings when entering the site */ init(); /* Load settings before swapping */ /* astro:after-swap event happened before swap animation */ document.addEventListener('astro:after-swap', init); </script> <style is:global lang="stylus"> #banner-wrapper top: 0 opacity: 1 .banner-closed #banner-wrapper top: -120px opacity: 0 </style>