chore: layout
This commit is contained in:
parent
b9561ad2d0
commit
230dca64ca
27 changed files with 446 additions and 339 deletions
|
@ -2,4 +2,4 @@
|
|||
|
||||
---
|
||||
|
||||
<div class="mx-auto max-w-screen-md px-3"><slot /></div>
|
||||
<div class="mx-auto max-w-screen-md"><slot /></div>
|
||||
|
|
|
@ -5,7 +5,7 @@ import BackToTop from '@components/BackToTop.astro'
|
|||
import SocialIcons from './SocialIcons.astro'
|
||||
---
|
||||
|
||||
<footer class="animate">
|
||||
<footer>
|
||||
<Container>
|
||||
<div class="my-2 flex justify-between">
|
||||
<SocialIcons icon_size={'text-xl'} />
|
||||
|
@ -16,78 +16,6 @@ import SocialIcons from './SocialIcons.astro'
|
|||
© {new Date().getFullYear()} • {SITE.TITLE} 👀<br />
|
||||
Built with Astro
|
||||
</div>
|
||||
<div class="flex flex-wrap items-center gap-1.5">
|
||||
<button
|
||||
id="light-theme-button"
|
||||
aria-label="Light theme"
|
||||
class="group flex size-9 items-center justify-center rounded border border-black/15 hover:bg-black/5 focus-visible:bg-black/5 dark:border-white/20 dark:hover:bg-white/5 dark:focus-visible:bg-white/5"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="transition-colors duration-300 ease-in-out group-hover:animate-pulse group-hover:stroke-black group-focus-visible:animate-pulse group-focus-visible:stroke-black group-hover:dark:stroke-white dark:group-focus-visible:stroke-white"
|
||||
>
|
||||
<circle cx="12" cy="12" r="5"></circle>
|
||||
<line x1="12" y1="1" x2="12" y2="3"></line>
|
||||
<line x1="12" y1="21" x2="12" y2="23"></line>
|
||||
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
|
||||
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
|
||||
<line x1="1" y1="12" x2="3" y2="12"></line>
|
||||
<line x1="21" y1="12" x2="23" y2="12"></line>
|
||||
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
|
||||
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
id="dark-theme-button"
|
||||
aria-label="Dark theme"
|
||||
class="group flex size-9 items-center justify-center rounded border border-black/15 hover:bg-black/5 focus-visible:bg-black/5 dark:border-white/20 dark:hover:bg-white/5 dark:focus-visible:bg-white/5"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="transition-colors duration-300 ease-in-out group-hover:animate-pulse group-hover:stroke-black group-focus-visible:animate-pulse group-focus-visible:stroke-black group-hover:dark:stroke-white dark:group-focus-visible:stroke-white"
|
||||
>
|
||||
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
id="system-theme-button"
|
||||
aria-label="System theme"
|
||||
class="group flex size-9 items-center justify-center rounded border border-black/15 hover:bg-black/5 focus-visible:bg-black/5 dark:border-white/20 dark:hover:bg-white/5 dark:focus-visible:bg-white/5"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="transition-colors duration-300 ease-in-out group-hover:animate-pulse group-hover:stroke-black group-focus-visible:animate-pulse group-focus-visible:stroke-black group-hover:dark:stroke-white dark:group-focus-visible:stroke-white"
|
||||
>
|
||||
<rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect>
|
||||
<line x1="8" y1="21" x2="16" y2="21"></line>
|
||||
<line x1="12" y1="17" x2="12" y2="21"></line>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</footer>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
import '../styles/global.css'
|
||||
import { ViewTransitions } from 'astro:transitions'
|
||||
|
||||
import '@fontsource/geist-sans'
|
||||
import '@fontsource/geist-mono'
|
||||
|
@ -16,46 +15,31 @@ const canonicalURL = new URL(Astro.url.pathname, Astro.site)
|
|||
const { title, description, image = '/blog-placeholder-1.jpg' } = Astro.props
|
||||
---
|
||||
|
||||
<!-- Global Metadata -->
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<link
|
||||
rel="icon"
|
||||
href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🍄</text></svg>"
|
||||
/>
|
||||
<meta name="generator" content={Astro.generator} />
|
||||
|
||||
<!-- Canonical URL -->
|
||||
<link rel="canonical" href={canonicalURL} />
|
||||
|
||||
<!-- Primary Meta Tags -->
|
||||
<title>{title}</title>
|
||||
<meta name="title" content={title} />
|
||||
<meta name="description" content={description} />
|
||||
|
||||
<!-- Open Graph / Facebook -->
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content={Astro.url} />
|
||||
<meta property="og:title" content={title} />
|
||||
<meta property="og:description" content={description} />
|
||||
<meta property="og:image" content={new URL(image, Astro.url)} />
|
||||
|
||||
<!-- Twitter -->
|
||||
<meta property="twitter:card" content="summary_large_image" />
|
||||
<meta property="twitter:url" content={Astro.url} />
|
||||
<meta property="twitter:title" content={title} />
|
||||
<meta property="twitter:description" content={description} />
|
||||
<meta property="twitter:image" content={new URL(image, Astro.url)} />
|
||||
|
||||
<ViewTransitions />
|
||||
|
||||
<script is:inline>
|
||||
function init() {
|
||||
preloadTheme()
|
||||
onScroll()
|
||||
animate()
|
||||
updateThemeButtons()
|
||||
addCopyCodeButtons()
|
||||
|
||||
const backToTop = document.getElementById('back-to-top')
|
||||
|
@ -64,77 +48,9 @@ const { title, description, image = '/blog-placeholder-1.jpg' } = Astro.props
|
|||
const backToPrev = document.getElementById('back-to-prev')
|
||||
backToPrev?.addEventListener('click', () => window.history.back())
|
||||
|
||||
const lightThemeButton = document.getElementById('light-theme-button')
|
||||
lightThemeButton?.addEventListener('click', () => {
|
||||
localStorage.setItem('theme', 'light')
|
||||
toggleTheme(false)
|
||||
updateThemeButtons()
|
||||
})
|
||||
|
||||
const darkThemeButton = document.getElementById('dark-theme-button')
|
||||
darkThemeButton?.addEventListener('click', () => {
|
||||
localStorage.setItem('theme', 'dark')
|
||||
toggleTheme(true)
|
||||
updateThemeButtons()
|
||||
})
|
||||
|
||||
const systemThemeButton = document.getElementById('system-theme-button')
|
||||
systemThemeButton?.addEventListener('click', () => {
|
||||
localStorage.setItem('theme', 'system')
|
||||
toggleTheme(window.matchMedia('(prefers-color-scheme: dark)').matches)
|
||||
updateThemeButtons()
|
||||
})
|
||||
|
||||
window
|
||||
.matchMedia('(prefers-color-scheme: dark)')
|
||||
.addEventListener('change', (event) => {
|
||||
if (localStorage.theme === 'system') {
|
||||
toggleTheme(event.matches)
|
||||
}
|
||||
})
|
||||
|
||||
document.addEventListener('scroll', onScroll)
|
||||
}
|
||||
|
||||
function updateThemeButtons() {
|
||||
const theme = localStorage.getItem('theme')
|
||||
const lightThemeButton = document.getElementById('light-theme-button')
|
||||
const darkThemeButton = document.getElementById('dark-theme-button')
|
||||
const systemThemeButton = document.getElementById('system-theme-button')
|
||||
|
||||
function removeActiveButtonTheme(button) {
|
||||
button?.classList.remove('bg-black/5')
|
||||
button?.classList.remove('dark:bg-white/5')
|
||||
}
|
||||
|
||||
function addActiveButtonTheme(button) {
|
||||
button?.classList.add('bg-black/5')
|
||||
button?.classList.add('dark:bg-white/5')
|
||||
}
|
||||
|
||||
removeActiveButtonTheme(lightThemeButton)
|
||||
removeActiveButtonTheme(darkThemeButton)
|
||||
removeActiveButtonTheme(systemThemeButton)
|
||||
|
||||
if (theme === 'light') {
|
||||
addActiveButtonTheme(lightThemeButton)
|
||||
} else if (theme === 'dark') {
|
||||
addActiveButtonTheme(darkThemeButton)
|
||||
} else {
|
||||
addActiveButtonTheme(systemThemeButton)
|
||||
}
|
||||
}
|
||||
|
||||
function animate() {
|
||||
const animateElements = document.querySelectorAll('.animate')
|
||||
|
||||
animateElements.forEach((element, index) => {
|
||||
setTimeout(() => {
|
||||
element.classList.add('show')
|
||||
}, index * 100)
|
||||
})
|
||||
}
|
||||
|
||||
function onScroll() {
|
||||
if (window.scrollY > 0) {
|
||||
document.documentElement.classList.add('scrolled')
|
||||
|
@ -151,44 +67,6 @@ const { title, description, image = '/blog-placeholder-1.jpg' } = Astro.props
|
|||
})
|
||||
}
|
||||
|
||||
function toggleTheme(dark) {
|
||||
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)
|
||||
|
||||
if (dark) {
|
||||
document.documentElement.classList.add('dark')
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark')
|
||||
}
|
||||
|
||||
window.getComputedStyle(css).opacity
|
||||
document.head.removeChild(css)
|
||||
}
|
||||
|
||||
function preloadTheme() {
|
||||
const userTheme = localStorage.theme
|
||||
|
||||
if (userTheme === 'light' || userTheme === 'dark') {
|
||||
toggleTheme(true) // set default to dark theme
|
||||
} else {
|
||||
toggleTheme(window.matchMedia('(prefers-color-scheme: dark)').matches)
|
||||
}
|
||||
}
|
||||
|
||||
function addCopyCodeButtons() {
|
||||
let copyButtonLabel = '📋'
|
||||
let codeBlocks = Array.from(document.querySelectorAll('pre'))
|
||||
|
@ -228,5 +106,4 @@ const { title, description, image = '/blog-placeholder-1.jpg' } = Astro.props
|
|||
|
||||
document.addEventListener('DOMContentLoaded', () => init())
|
||||
document.addEventListener('astro:after-swap', () => init())
|
||||
preloadTheme()
|
||||
</script>
|
||||
|
|
|
@ -2,33 +2,30 @@
|
|||
import Container from '@components/Container.astro'
|
||||
import Link from '@components/Link.astro'
|
||||
import { SITE } from '@consts'
|
||||
|
||||
const items = [
|
||||
{ href: '/blog', label: 'blog' },
|
||||
{ href: '/authors', label: 'authors' },
|
||||
{ href: '/about', label: 'about' },
|
||||
{ href: '/tags', label: 'tags' },
|
||||
]
|
||||
---
|
||||
|
||||
<header transition:persist>
|
||||
<header class="sticky top-0 z-10" transition:persist>
|
||||
<Container>
|
||||
<div class="flex flex-wrap justify-between gap-y-2">
|
||||
<div class="flex items-center justify-between py-4">
|
||||
<Link href="/" underline={false}>
|
||||
<div class="font-semibold">
|
||||
{SITE.TITLE} 🍄
|
||||
</div>
|
||||
{SITE.TITLE}<span class="ml-1">🍄</span>
|
||||
</Link>
|
||||
<nav class="flex items-center gap-1 text-sm">
|
||||
<Link href="/blog">blog</Link>
|
||||
<span>
|
||||
{`/`}
|
||||
</span>
|
||||
<Link href="/authors">authors</Link>
|
||||
<span>
|
||||
{`/`}
|
||||
</span>
|
||||
<Link href="/about">about</Link>
|
||||
<span>
|
||||
{`/`}
|
||||
</span>
|
||||
<Link href="/tags">tags</Link>
|
||||
<span>
|
||||
{`/`}
|
||||
</span>
|
||||
<nav class="flex items-center space-x-1 text-sm">
|
||||
{
|
||||
items.map((item, index) => (
|
||||
<>
|
||||
<Link href={item.href}>{item.label}</Link>
|
||||
{index < items.length - 1 && <span class="text-gray-400">/</span>}
|
||||
</>
|
||||
))
|
||||
}
|
||||
</nav>
|
||||
</div>
|
||||
</Container>
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
---
|
||||
import type { CollectionEntry } from "astro:content";
|
||||
import { Image } from "astro:assets";
|
||||
import type { CollectionEntry } from 'astro:content'
|
||||
import { Image } from 'astro:assets'
|
||||
|
||||
type Props = {
|
||||
member: CollectionEntry<"authors">;
|
||||
};
|
||||
member: CollectionEntry<'authors'>
|
||||
}
|
||||
|
||||
const { member } = Astro.props;
|
||||
const { name, avatar, bio } = member.data;
|
||||
const { member } = Astro.props
|
||||
const { name, avatar, bio } = member.data
|
||||
---
|
||||
|
||||
<div
|
||||
class="animate not-prose flex flex-col sm:flex-row size-full sm:items-center gap-4 overflow-hidden rounded-xl border border-foreground bg-background p-6 hover:bg-secondary"
|
||||
class="not-prose flex size-full flex-col gap-4 overflow-hidden rounded-xl border border-foreground bg-background p-6 hover:bg-secondary sm:flex-row sm:items-center"
|
||||
>
|
||||
<Image
|
||||
src={avatar}
|
||||
|
|
|
@ -27,10 +27,7 @@ function buildToc(headings: Heading[]) {
|
|||
}
|
||||
---
|
||||
|
||||
<details
|
||||
open
|
||||
class="animate rounded-lg border border-black/15 dark:border-white/20"
|
||||
>
|
||||
<details open class="rounded-lg border border-black/15 dark:border-white/20">
|
||||
<summary>Table of Contents</summary>
|
||||
<nav class="">
|
||||
<ul class="py-3">
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue