feat: head component with excellent SEO

This commit is contained in:
radishzzz 2025-01-16 07:48:40 +00:00
parent 5d3a3b0321
commit 7659bbd1e2
8 changed files with 221 additions and 75 deletions

134
src/components/Head.astro Normal file
View file

@ -0,0 +1,134 @@
---
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 { language } = themeConfig.global
const { light: { backgroundStart: lightMode }, dark: { backgroundStart: darkMode } } = themeConfig.color
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
---
<!-- 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="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/astro-theme-retypeset@master/src/style/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 -->
<link rel="author" href={url} />
<link rel="publisher" href={author} />
<link rel="canonical" href={Astro.url} />
<!-- todo language -->
<link rel="alternate" href="/en/" hreflang="en" />
<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/" />
<!-- 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={language} />
<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} />}
<!-- Google Analytics -->
{
googleAnalyticsID && (
<>
<script
type="text/partytown"
async
defer
crossorigin="anonymous"
src={`${customGoogleAnalyticsURL || 'https://www.googletagmanager.com'}/gtag/js?id=${googleAnalyticsID}`}
/>
<script
type="text/partytown"
async
defer
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.replace(/\/$/, ''),
})
}
else {
gtag('config', googleAnalyticsID)
}
</script>
</>
)
}
<!-- Umami Analytics -->
{
umamiAnalyticsID && (
<script
type="text/partytown"
async
defer
crossorigin="anonymous"
data-website-id={umamiAnalyticsID}
src={customUmamiAnalyticsJS || 'https://analytics.umami.is/script.js'}
data-cache="true"
/>
)
}

View file

@ -1,20 +0,0 @@
---
import themeConfig from '@/config'
const { title, subtitle, favicon } = themeConfig.site
---
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href={favicon} />
<meta name="generator" content={Astro.generator} />
<title>{title} - {subtitle}</title>
<link
rel="alternate"
type="application/rss+xml"
title={title}
href={`${themeConfig.site.url}/rss.xml`}
/>
</head>

View file

@ -8,7 +8,7 @@ export const themeConfig: ThemeConfig = {
description: '一个优美的博客主题',
author: 'radishzz',
url: 'https://retypeset.netlify.app',
favicon: '#',
favicon: '#', // only support webp, svg, png
},
// SITE INFORMATION >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> END
@ -26,18 +26,18 @@ export const themeConfig: ThemeConfig = {
backgroundEnd: '#000000',
},
},
// COLOR SETTINGS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> END
// COLOR SETTINGS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> END
// GLOBAL SETTINGS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> START
// GLOBAL SETTINGS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> START
global: {
language: 'zh',
font: 'sans',
rss: true,
toc: true,
language: 'zh-CN', // en-US, zh-CN
font: 'sans', // sans, serif, choose the font style for posts
rss: true, // true, false, whether to enable RSS
toc: true, // true, false, whether to enable table of contents in posts
},
// GLOBAL SETTINGS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> END
// GLOBAL SETTINGS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> END
// COMMENT SETTINGS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> START
// COMMENT SETTINGS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> START
comment: {
waline: {
serverURL: '#',
@ -49,27 +49,33 @@ export const themeConfig: ThemeConfig = {
imageUploader: true,
},
},
// COMMENT SETTINGS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> END
// COMMENT SETTINGS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> END
// SEO SETTINGS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> START
// SEO SETTINGS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> START
seo: {
twitter: 'https://twitter.com/radishzz',
meta: {
twitterID: '#', // @twitter ID
facebookID: '#', // @facebook ID
facebookLink: '#', // facebook profile link
// site verification
verification: {
google: '#',
bing: '#',
yandex: '#',
baidu: '#',
},
link: '#',
// site analytics
googleAnalyticsID: '#',
umamiAnalyticsID: '#',
// follow verification
follow: {
feedID: '#',
userID: '#',
},
siteScreenshot: '#', // Take a screenshot of website homepage to show on twitter card
},
// SEO SETTINGS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> END
// SEO SETTINGS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> END
// FOOTER SETTINGS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> START
// FOOTER SETTINGS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> START
footer: {
linkA: {
name: 'RSS',
@ -84,7 +90,19 @@ export const themeConfig: ThemeConfig = {
url: '#',
},
},
// FOOTER SETTINGS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> END
// FOOTER SETTINGS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> END
// PRELOAD SETTINGS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> START
preload: {
cdn: 'https://cdn.jsdelivr.net/', // Recommended to keep default, unless you can proxy https://cdn.jsdelivr.net/gh/radishzzz/astro-theme-retypeset@master/src/style/font.css
commentURL: '', // https://comment.example.com/
imageHostURL: '', // https://image.example.com/
// If you proxy analytics requests to the custom domain, you can fill in below
customGoogleAnalyticsURL: '', // https://whatever.example.com/
customUmamiAnalyticsURL: '', // https://whatever.example.com/
customUmamiAnalyticsJS: '', // https://whatever.example.com/whatever.js
},
// PRELOAD SETTINGS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> END
}
export default themeConfig

View file

@ -1,10 +1,12 @@
---
import Header from '@/components/Header.astro'
import Head from '@/components/Head.astro'
---
<!doctype html>
<html lang="en">
<Header />
<head>
<Head />
</head>
<body>
<slot />
</body>

18
src/types/index.d.ts vendored
View file

@ -40,19 +40,22 @@ export interface ThemeConfig {
}
seo?: {
twitter?: string
meta?: {
twitterID?: string
facebookID?: string
facebookLink?: string
verification?: {
google?: string
bing?: string
yandex?: string
baidu?: string
}
link?: string
googleAnalyticsID?: string
umamiAnalyticsID?: string
follow?: {
feedID?: string
userID?: string
}
siteScreenshot: string
}
footer: {
@ -69,6 +72,15 @@ export interface ThemeConfig {
url: string
}
}
preload: {
cdn: string
commentURL?: string
imageHostURL?: string
customGoogleAnalyticsURL?: string
customUmamiAnalyticsURL?: string
customUmamiAnalyticsJS?: string
}
}
export default ThemeConfig