2023-09-26 14:27:38 +08:00
---
2024-01-21 13:54:41 +09:00
import GlobalStyles from "@components/GlobalStyles.astro";
2023-09-26 14:27:38 +08:00
import '@fontsource/roboto/400.css';
import '@fontsource/roboto/500.css';
import '@fontsource/roboto/700.css';
2024-02-18 18:13:43 +08:00
import ImageWrapper from "@components/misc/ImageWrapper.astro";
2023-09-26 14:27:38 +08:00
2024-01-21 13:54:41 +09:00
import {pathsEqual} from "@utils/url-utils";
import ConfigCarrier from "@components/ConfigCarrier.astro";
2024-04-22 23:42:47 +08:00
import {profileConfig, siteConfig} from "@/config";
2024-04-23 02:57:38 +08:00
import {Favicon} from "../types/config";
import {defaultFavicons} from "../constants/icon";
2024-04-29 12:52:50 +08:00
import {LIGHT_MODE, DARK_MODE, AUTO_MODE, DEFAULT_THEME} from "../constants/constants";
2024-04-29 15:56:28 +08:00
import {url} from "../utils/url-utils";
2023-09-26 14:27:38 +08:00
interface Props {
title: string;
banner: string;
2024-04-23 00:04:43 +08:00
description?: string;
2023-09-26 14:27:38 +08:00
}
2024-04-23 00:04:43 +08:00
let { title, banner, description } = Astro.props;
2023-09-26 14:27:38 +08:00
2024-02-18 18:24:00 +08:00
const isHomePage = pathsEqual(Astro.url.pathname, '/');
2023-09-26 14:27:38 +08:00
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
2023-10-23 17:45:07 +08:00
const configHue = siteConfig.themeHue;
2023-09-26 14:27:38 +08:00
if (!banner || typeof banner !== 'string' || banner.trim() === '') {
2023-10-23 17:45:07 +08:00
banner = siteConfig.banner.src;
2023-09-26 14:27:38 +08:00
}
2023-10-02 01:52:08 +08:00
// TODO don't use post cover as banner for now
2023-10-23 17:45:07 +08:00
banner = siteConfig.banner.src;
2023-10-02 01:52:08 +08:00
2024-03-12 14:04:58 +08:00
const enableBanner = siteConfig.banner.enable;
2023-10-23 17:45:07 +08:00
let pageTitle;
2023-10-06 02:53:47 +08:00
if (title) {
2023-10-23 17:45:07 +08:00
pageTitle = `${title} - ${siteConfig.title}`;
} else {
pageTitle = `${siteConfig.title} - ${siteConfig.subtitle}`;
2023-10-06 02:53:47 +08:00
}
2024-04-23 02:57:38 +08:00
const favicons: Favicon[] = siteConfig.favicon.length > 0 ? siteConfig.favicon : defaultFavicons
2024-05-01 01:08:21 +08:00
const siteLang = siteConfig.lang.replace('_', '-')
2023-09-26 14:27:38 +08:00
---
<!DOCTYPE html>
2024-05-01 01:08:21 +08:00
<html lang={siteLang} isHome={isHomePage} pathname={testPathName} class="bg-[var(--page-bg)] transition text-[14px] md:text-[16px]">
2023-09-26 14:27:38 +08:00
<head>
2023-10-06 02:53:47 +08:00
<title>{pageTitle}</title>
2023-09-26 14:27:38 +08:00
<meta charset="UTF-8" />
2024-04-23 00:04:43 +08:00
<meta name="description" content={description || pageTitle}>
2023-09-26 14:27:38 +08:00
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
2024-04-23 02:57:38 +08:00
{favicons.map(favicon => (
<link rel="icon"
2024-04-29 15:56:28 +08:00
href={favicon.src.startsWith('/') ? url(favicon.src) : favicon.src}
2024-04-23 02:57:38 +08:00
sizes={favicon.sizes}
media={favicon.theme && `(prefers-color-scheme: ${favicon.theme})`}
/>
))}
2024-04-29 12:52:50 +08:00
<!-- Set the theme before the page is rendered to avoid a flash -->
<script define:vars={{DEFAULT_THEME: DEFAULT_THEME, LIGHT_MODE: LIGHT_MODE, DARK_MODE: DARK_MODE, AUTO_MODE: AUTO_MODE}}>
const theme = localStorage.getItem('theme') || DEFAULT_THEME;
switch (theme) {
case LIGHT_MODE:
document.documentElement.classList.remove('dark');
break
case DARK_MODE:
document.documentElement.classList.add('dark');
break
case AUTO_MODE:
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
}
</script>
2023-09-26 14:27:38 +08:00
2024-04-29 17:04:15 +08:00
<slot name="head"></slot>
2023-10-11 22:30:20 +08:00
<link rel="stylesheet" href="https://cdn.staticfile.org/KaTeX/0.16.9/katex.min.css" integrity="sha384-n8MVd4RsNIU0tAv4ct0nTaAbDJwPJzDEaqSD1odI+WdtXRGWt2kTvGFasHpSy3SV" crossorigin="anonymous">
2024-04-22 23:42:47 +08:00
<link rel="alternate" type="application/rss+xml" title={profileConfig.name} href={`${Astro.site}rss.xml`}/>
2023-10-02 01:52:08 +08:00
<style define:vars={{ configHue }}></style> <!-- defines global css variables. This will be applied to <html> <body> and some other elements idk why -->
2023-09-26 14:27:38 +08:00
</head>
2024-03-12 14:04:58 +08:00
<body class=" min-h-screen transition " class:list={[{"is-home": isHomePage, "enable-banner": enableBanner}]}>
2023-10-19 21:48:26 +08:00
<ConfigCarrier></ConfigCarrier>
2023-09-26 14:27:38 +08:00
<GlobalStyles>
2024-03-12 14:04:58 +08:00
<div id="banner-wrapper" class="absolute w-full">
2024-02-18 18:13:43 +08:00
<ImageWrapper id="boxtest" alt="Banner image of the blog" class:list={["object-center object-cover h-full", {"hidden": !siteConfig.banner.enable}]}
2024-03-12 14:04:58 +08:00
src={siteConfig.banner.src}
2023-09-26 14:27:38 +08:00
>
2024-02-18 18:13:43 +08:00
</ImageWrapper>
2023-09-26 14:27:38 +08:00
</div>
<slot />
</GlobalStyles>
</body>
</html>
<style is:global>
:root {
2023-10-02 01:52:08 +08:00
--hue: var(--configHue);
2024-02-18 18:13:43 +08:00
--page-width: 75rem;
2023-09-26 14:27:38 +08:00
}
</style>
2024-03-12 14:04:58 +08:00
<style is:global>
2023-09-26 14:27:38 +08:00
@tailwind components;
@tailwind utilities;
@layer components {
2024-03-12 14:04:58 +08:00
/* TODO: temporarily make banner height same for all pages since I cannot make the transition feel good
I want to make the height transition parallel with the content transition instead of blocking it
*/
/*
.enable-banner.is-home #banner-wrapper {
2023-11-06 21:56:53 +08:00
@apply h-[var(--banner-height)] md:h-[var(--banner-height-home)]
2023-09-26 14:27:38 +08:00
}
2024-03-12 14:04:58 +08:00
*/
.enable-banner #banner-wrapper {
2023-09-26 14:27:38 +08:00
@apply h-[var(--banner-height)]
}
2024-03-12 14:04:58 +08:00
/*
.enable-banner.is-home #top-row {
@apply h-[calc(var(--banner-height)_-_4.5rem)] md:h-[calc(var(--banner-height-home)_-_4.5rem)]
}
*/
.enable-banner #top-row {
@apply h-[calc(var(--banner-height)_-_4.5rem)]
}
2023-09-26 14:27:38 +08:00
}
</style>
2023-10-19 21:48:26 +08:00
<script>
2023-11-08 13:01:06 +08:00
import 'overlayscrollbars/overlayscrollbars.css';
import {
OverlayScrollbars,
ScrollbarsHidingPlugin,
SizeObserverPlugin,
ClickScrollPlugin
} from 'overlayscrollbars';
2024-04-28 12:43:10 +08:00
import {getHue, getStoredTheme, setHue, setTheme} from "../utils/setting-utils";
2023-11-08 13:01:06 +08:00
/* Preload fonts */
2023-09-26 14:27:38 +08:00
// (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);
// }
// })();
2023-10-06 02:59:56 +08:00
/* 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 */
2023-10-11 22:30:20 +08:00
/* update: fixed in Astro 3.2.4 */
2023-10-06 02:59:56 +08:00
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)
}
}
2024-02-18 18:13:43 +08:00
function setClickOutsideToClose(panel: string, ignores: string[]) {
document.addEventListener("click", event => {
let panelDom = document.getElementById(panel);
let tDom = event.target;
for (let ig of ignores) {
let ie = document.getElementById(ig)
if (ie == tDom || (ie?.contains(tDom))) {
return;
2023-11-06 21:55:52 +08:00
}
2024-02-18 18:13:43 +08:00
}
2024-04-28 12:43:10 +08:00
panelDom.classList.add("float-panel-closed");
2024-02-18 18:13:43 +08:00
});
2023-10-06 02:59:56 +08:00
}
2024-02-18 18:13:43 +08:00
setClickOutsideToClose("display-setting", ["display-setting", "display-settings-switch"])
setClickOutsideToClose("nav-menu-panel", ["nav-menu-panel", "nav-menu-switch"])
setClickOutsideToClose("search-panel", ["search-panel", "search-bar", "search-switch"])
2023-10-06 02:59:56 +08:00
2023-09-26 14:27:38 +08:00
function loadTheme() {
2024-04-28 12:43:10 +08:00
const theme = getStoredTheme()
setTheme(theme)
2023-09-26 14:27:38 +08:00
}
2023-10-02 01:52:08 +08:00
function loadHue() {
2024-02-18 18:13:43 +08:00
setHue(getHue())
2023-10-02 01:52:08 +08:00
}
2023-09-26 14:27:38 +08:00
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');
}
}
2023-11-08 13:01:06 +08:00
function initCustomScrollbar() {
2024-01-22 12:01:06 +08:00
OverlayScrollbars(
// docs say that a initialization to the body element would affect native functionality like window.scrollTo
// but just leave it here for now
{
target: document.querySelector('body'),
cancel: {
nativeScrollbarsOverlaid: true, // don't initialize the overlay scrollbar if there is a native one
}
}, {
2023-11-08 13:01:06 +08:00
scrollbars: {
theme: 'scrollbar-base scrollbar-auto py-1',
autoHide: 'move',
2023-11-08 15:26:18 +08:00
autoHideDelay: 500,
2024-01-22 12:01:06 +08:00
autoHideSuspend: false,
},
2023-11-08 13:01:06 +08:00
});
document.querySelectorAll('pre').forEach((ele) => {
OverlayScrollbars(ele, {
scrollbars: {
theme: 'scrollbar-base scrollbar-dark px-2',
autoHide: 'leave',
2023-11-08 15:26:18 +08:00
autoHideDelay: 500,
2023-11-08 13:01:06 +08:00
autoHideSuspend: false
}
});
});
}
2023-10-02 01:52:08 +08:00
2023-11-08 13:01:06 +08:00
function init() {
// disableAnimation()() // TODO
2023-09-26 14:27:38 +08:00
setBannerHeight();
loadTheme();
2023-10-02 01:52:08 +08:00
loadHue();
2023-11-08 13:01:06 +08:00
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);
2024-03-12 14:04:58 +08:00
const setup = () => {
// TODO: temp solution to change the height of the banner
/*
window.swup.hooks.on('animation:out:start', () => {
const path = window.location.pathname
const body = document.querySelector('body')
if (path[path.length - 1] === '/' && !body.classList.contains('is-home')) {
body.classList.add('is-home')
} else if (path[path.length - 1] !== '/' && body.classList.contains('is-home')) {
body.classList.remove('is-home')
}
})
*/
2024-03-13 01:32:54 +08:00
// Remove the delay for the first time page load
window.swup.hooks.on('link:click', () => {
document.documentElement.style.setProperty('--content-delay', '0ms')
})
2024-03-12 14:04:58 +08:00
}
if (window.swup.hooks) {
setup()
} else {
document.addEventListener('swup:enable', setup)
}
2023-10-06 03:02:46 +08:00
</script>
<style is:global lang="stylus">
#banner-wrapper
top: 0
opacity: 1
.banner-closed
#banner-wrapper
top: -120px
opacity: 0
</style>