Files
MyBlog-Next/src/layouts/Layout.astro
T
Sat Naing e0506cb41e feat: add callout support (#655)
* feat: toggle .dark class on theme change

* feat: add callouts with rehype-callouts plugin

* docs: update blog posts with callouts
2026-06-06 09:09:08 +07:00

128 lines
3.9 KiB
Plaintext

---
import { Font } from "astro:assets";
import { ClientRouter } from "astro:transitions";
import { getRelativeLocaleUrl } from "astro:i18n";
import { resolveDefaultOgImagePath } from "@/utils/resolveDefaultOgImagePath";
import { getAssetPath } from "@/utils/withBase";
import config from "@/config";
import "@/styles/global.css";
type Props = {
title?: string;
description?: string;
ogImage?: string;
canonicalURL?: string;
};
const { site } = config;
const {
title = site.title,
description = site.description,
ogImage = resolveDefaultOgImagePath(config),
canonicalURL = new URL(Astro.url.pathname, Astro.site).href,
} = Astro.props;
const socialImageURL = new URL(ogImage, Astro.site ?? Astro.url);
const rssHref = getRelativeLocaleUrl(
Astro.currentLocale ?? config.site.lang,
"rss.xml"
);
---
<!doctype html>
<html
dir={site.dir ?? "ltr"}
lang={Astro.currentLocale ?? site.lang}
class="overflow-y-scroll scroll-smooth"
>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/svg+xml" href={getAssetPath("favicon.svg")} />
<link rel="icon" href={getAssetPath("favicon.ico")} />
<link rel="canonical" href={canonicalURL} />
<meta name="generator" content={Astro.generator} />
<!-- Font -->
<Font
cssVariable="--font-google-sans-code"
preload={[{ subset: "latin", weight: 400, style: "normal" }]}
/>
<!-- Primary meta -->
<title>{title}</title>
<meta name="title" content={title} />
<meta name="description" content={description} />
<meta name="author" content={site.author} />
<link rel="sitemap" href={getAssetPath("sitemap-index.xml")} />
<!-- Open Graph -->
<meta property="og:type" content="website" />
<meta property="og:site_name" content={site.title} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:url" content={canonicalURL} />
<meta property="og:image" content={socialImageURL} />
<!-- Twitter / X -->
<meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:url" content={canonicalURL} />
<meta property="twitter:title" content={title} />
<meta property="twitter:description" content={description} />
<meta property="twitter:image" content={socialImageURL} />
<!-- RSS autodiscovery -->
<link
rel="alternate"
type="application/rss+xml"
title={site.title}
href={new URL(rssHref, Astro.site)}
/>
<!-- Filled at runtime by theme.ts to match the current background colour -->
<meta name="theme-color" content="" />
<!-- Extra head content injected by child layouts (e.g. JSON-LD, article meta) -->
<slot name="head" />
{
site.googleVerification && (
<meta
name="google-site-verification"
content={site.googleVerification}
/>
)
}
<!--
Inline FOUC-prevention script: sets data-theme on <html> before
the browser paints. Runs synchronously, no defer/async.
-->
<script is:inline>
(function () {
const stored = localStorage.getItem("theme");
const prefersDark = window.matchMedia(
"(prefers-color-scheme: dark)"
).matches;
const theme = stored ?? (prefersDark ? "dark" : "light");
const root = document.firstElementChild;
root?.setAttribute("data-theme", theme);
root?.classList.toggle("dark", theme === "dark");
// Expose value so theme.ts can skip re-detection.
window.__theme = { value: theme };
})();
</script>
<ClientRouter />
</head>
<body
class="bg-background font-app text-foreground selection:bg-accent/75 selection:text-accent-foreground flex min-h-svh flex-col"
>
<slot />
<script>
import "@/scripts/theme";
</script>
</body>
</html>