feat: integrate PhotoSwipe lightbox, enhance scrollbar functionality, and update layout components

- Added a new PhotoSwipe component for image lightbox functionality in the layout.
- Enhanced scrollbar component with an auto-hide delay feature.
- Updated global styles to improve scrollbar appearance and added styles for PhotoSwipe.
- Included new Head layout component for better SEO and meta tag management.
- Added images to existing posts for improved visual content.

This commit improves user experience with enhanced image viewing and layout consistency.
This commit is contained in:
radishzzz 2025-01-23 08:23:43 +00:00
parent ac9e839a75
commit 1af92d92c8
10 changed files with 131 additions and 51 deletions

146
src/layouts/Head.astro Normal file
View file

@ -0,0 +1,146 @@
---
import themeConfig from '@/config'
interface Props {
postTitle?: string
postDescription?: string
postImage?: string
}
const { postTitle, postDescription, postImage } = Astro.props
const { title, subtitle, description, author, url, favicon } = themeConfig.site
const { light: { background: lightMode }, dark: { background: darkMode } } = themeConfig.color
const { locale, moreLocale } = themeConfig.global
const { verification = {}, twitterID = '', facebookID = '', facebookLink = '', googleAnalyticsID = '', umamiAnalyticsID = '', siteScreenshot = '' } = themeConfig.seo ?? {}
const { google = '', bing = '', yandex = '', baidu = '' } = verification
const { cdn, commentURL = '', imageHostURL = '', customGoogleAnalyticsURL = '', customUmamiAnalyticsURL = '', customUmamiAnalyticsJS = '' } = themeConfig.preload
---
<head>
<!-- Basic -->
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
{favicon.toLowerCase().endsWith('.webp') && <link rel="icon" type="image/webp" href={favicon} />}
{favicon.toLowerCase().endsWith('.svg') && <link rel="icon" type="image/svg+xml" href={favicon} />}
{favicon.toLowerCase().endsWith('.png') && <link rel="icon" type="image/png" href={favicon} />}
<title>{postTitle ? `${postTitle} | ${title}` : `${title} - ${subtitle}`}</title>
<meta name="description" content={postDescription || description} />
<meta name="author" content={author} />
<meta name="generator" content={Astro.generator} />
<meta name="color-scheme" content="light dark" />
<meta name="theme-color" content={lightMode} media="(prefers-color-scheme: light)" />
<meta name="theme-color" content={darkMode} media="(prefers-color-scheme: dark)" />
<meta itemprop="name" content={postTitle || title} />
<meta itemprop="image" content={postImage || siteScreenshot} />
<meta itemprop="description" content={postDescription || subtitle} />
<!-- Preload -->
<link rel="preconnect" href={cdn} />
<link rel="preload" href={`${cdn}/gh/radishzzz/retypeset-font/font.css`} as="style" />
{commentURL && <link rel="dns-prefetch" href={commentURL} />}
{imageHostURL && <link rel="dns-prefetch" href={imageHostURL} />}
{customGoogleAnalyticsURL && <link rel="dns-prefetch" href={customGoogleAnalyticsURL} />}
{customUmamiAnalyticsURL && <link rel="dns-prefetch" href={customUmamiAnalyticsURL} />}
<link rel="stylesheet" href={`${cdn}/gh/radishzzz/retypeset-font/font.css`} />
<!-- Link -->
<link rel="author" href={url} />
<link rel="publisher" href={author} />
<link rel="canonical" href={Astro.url} />
<link rel="alternate" href="/rss.xml" type="application/rss+xml" title="RSS" />
<link rel="license" href="https://creativecommons.org/licenses/by-nc-sa/4.0/" />
<!-- i18n hreflang generate -->
{[locale, ...moreLocale].map(lang => (
<link
rel="alternate"
href={`${url}${lang === locale ? '' : lang}`}
hreflang={lang === 'zh-tw' ? 'zh-TW' : lang}
/>
))}
<!-- Facebook Open Graph -->
<meta property="fb:app_id" content={facebookID} />
<meta property="og:url" content={Astro.url} />
<meta property="og:type" content={postTitle ? 'article' : 'website'} />
<meta property="og:title" content={postTitle || title} />
<meta property="og:image" content={postImage || siteScreenshot} />
<meta property="og:image:alt" content={postTitle || title} />
<meta property="og:description" content={postDescription || subtitle} />
<meta property="og:site_name" content={title} />
<meta property="og:locale" content={Astro.currentLocale?.replace('-', '_') || 'en_US'} />
<meta property="article:author" content={facebookLink} />
<!-- Twitter Card -->
<meta name="twitter:card" content="summary" />
<meta name="twitter:url" content={Astro.url} />
<meta name="twitter:title" content={postTitle || title} />
<meta name="twitter:description" content={postDescription || subtitle} />
<meta name="twitter:image" content={postImage || siteScreenshot} />
<meta name="twitter:image:alt" content={postTitle || title} />
{twitterID && (
<>
<meta name="twitter:site" content={twitterID} />
<meta name="twitter:creator" content={twitterID} />
</>
)}
<meta name="twitter:dnt" content="on" />
<!-- Site Verification -->
{google && <meta name="google-site-verification" content={google} />}
{bing && <meta name="msvalidate.01" content={bing} />}
{yandex && <meta name="yandex-verification" content={yandex} />}
{baidu && <meta name="baidu-site-verification" content={baidu} />}
<!-- Theme Toggle -->
<script is:inline>
const theme = localStorage.getItem('theme')
?? (matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')
document.documentElement.classList.toggle('dark', theme === 'dark')
</script>
<!-- Google Analytics -->
{
googleAnalyticsID && (
<>
<script
type="text/partytown"
crossorigin="anonymous"
src={`${customGoogleAnalyticsURL || 'https://www.googletagmanager.com'}/gtag/js?id=${googleAnalyticsID}`}
/>
<script
type="text/partytown"
define:vars={{ googleAnalyticsID, customGoogleAnalyticsURL }}
>
window.dataLayer = window.dataLayer || []
function gtag(...args) {
dataLayer.push(args)
}
gtag('js', new Date())
if (customGoogleAnalyticsURL) {
gtag('config', googleAnalyticsID, {
transport_url: customGoogleAnalyticsURL,
})
}
else {
gtag('config', googleAnalyticsID)
}
</script>
</>
)
}
<!-- Umami Analytics -->
{
umamiAnalyticsID && (
<script
type="text/partytown"
crossorigin="anonymous"
data-website-id={umamiAnalyticsID}
src={customUmamiAnalyticsJS || 'https://analytics.umami.is/script.js'}
data-cache="true"
/>
)
}
</head>

View file

@ -1,9 +1,11 @@
---
import Head from '@/components/Head.astro'
import PhotoSwipe from '@/components/PhotoSwipe.astro'
import Scrollbar from '@/components/Scrollbar.astro'
import ThemeToggle from '@/components/ThemeToggle.astro'
import themeConfig from '@/config'
import Head from '@/layouts/Head.astro'
import '@/styles/global.css'
import '@/styles/photoswipe.css'
interface Props {
postTitle?: string
@ -22,9 +24,7 @@ const colorMode = themeConfig.color.mode
class:list={[fontStyle, colorMode]}
data-overlayscrollbars-initialize
>
<head>
<Head {postTitle} {postDescription} {postImage} />
</head>
<Head {postTitle} {postDescription} {postImage} />
<body data-overlayscrollbars-initialize>
<ThemeToggle />
<main
@ -34,5 +34,6 @@ const colorMode = themeConfig.color.mode
<slot />
</main>
<Scrollbar />
<PhotoSwipe />
</body>
</html>