Skip to content

Commit

Permalink
feat: Add global config.yml for user settings and improve SEO. (#19)
Browse files Browse the repository at this point in the history
- Add yaml package to parse config.yml.
  - Introduce getConfig as a global utility to access config values.
- Replace hardcoded values across multiple files with config.yml
settings.
- Fix issue #10 : Default thumbnail now uses the background image from
config.
- Enable custom JavaScript in <head> and before </body> as defined in
config.yml.
- Allow users to define their own comment system with a reserved slot in
config.yml.

- Improve SEO: Add custom titles to post pages and update the site-wide
layout.
  - Use roobots.ts to generate robots.txt instead of hardcoded. 

- Replace Google Font import with nextjs built in.
- Extend the footer with more social media links and optimize for mobile
view.
- Merge frontmatter process logic into 1 single function.
  - Add logic avoid parsing not md files.
  • Loading branch information
ZL-Asica authored Oct 20, 2024
1 parent 59c1383 commit 432b3fa
Show file tree
Hide file tree
Showing 19 changed files with 352 additions and 126 deletions.
43 changes: 43 additions & 0 deletions config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
title: 'Suzu'
subTitle: 'Next.js Blog Template'
description: 'Suzu is a minimalist blog template with a serene sakura-inspired theme, blending modern design with a touch of traditional Japanese aesthetics.'
keywords: 'Suzu, Next.js, markdown blog, Tailwind CSS, blog template, sakura, ZL Asica'
author:
name: 'ZL Asica'
link: 'https://www.zla.app'
# Please use the ISO 639-1 code for the language
lang: 'zh'

# Relative path from /public/*, or full URL(include http(s)://)
avatar: '/images/avatar.jpg'
# This will be both your background and default post thumbnail
background: '/images/background.jpg'
# Shows on home page below your avatar
slogan: "As long as the code or the developer is able to run, it's all good."

# Set your social media links
socialMedia:
github: 'https://www.github.com/ZL-Asica:'
linkedin: 'https://www.linkedin.com/in/elara-liu'
x: '' # Twitter
instagram: 'https://www.instagram.com/zl_asica'
youtube: 'https://www.youtube.com/@ZL-Asica'
telegram: 'https://t.me/ZL_Asica'
bilibili: 'https://space.bilibili.com/29018759'
zhihu: 'https://www.zhihu.com/people/zl-asica'
email: '[email protected]' # Only put your email address here, no mailto: prefix
rss: ''

# Set your own js script inside <head>
scriptSlotHeader:
-

# Set your own js script before </body>
scriptSlotFooter:
- 'https://cdn.jsdelivr.net/gh/zl-asica/web-cdn/js/zlasica.js'

# HTML code inside <footer>
slotFooter: |
# Comment system for blog posts
slotComment: |
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"next": "14.2.15",
"react": "^18",
"react-dom": "^18",
"react-icons": "^5.3.0"
"react-icons": "^5.3.0",
"yaml": "^2.6.0"
},
"devDependencies": {
"@tailwindcss/typography": "^0.5.15",
Expand Down
32 changes: 0 additions & 32 deletions pages/_document.tsx

This file was deleted.

File renamed without changes
2 changes: 1 addition & 1 deletion src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
body {
color: var(--foreground);
background: var(--background);
font-family: var(--font-roboto), 'Noto Sans SC', 'PingFang SC',
font-family: var(--font-roboto), var(--font-noto-sans-sc), 'PingFang SC',
'Microsoft YaHei', Arial, Helvetica, sans-serif;
}

Expand Down
45 changes: 35 additions & 10 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import React from 'react';
import type { Metadata } from 'next';
import { Roboto } from 'next/font/google';
// eslint-disable-next-line camelcase
import { Roboto, Noto_Sans_SC } from 'next/font/google';
import './globals.css';
import ThemeProvider from '@/components/ThemeProvider';
import Header from '@/components/common/Header';
import Footer from '@/components/common/Footer';
import { getConfig } from '@/lib/getConfig';
import Script from 'next/script';

const config = getConfig();

const roboto = Roboto({
subsets: ['latin'],
Expand All @@ -13,27 +18,47 @@ const roboto = Roboto({
style: ['normal', 'italic'],
});

const notoSansSC = Noto_Sans_SC({
subsets: ['latin'],
weight: ['100', '400', '700', '900'],
variable: '--font-noto-sans-sc',
style: ['normal'],
});

export const metadata: Metadata = {
title: 'Suzu - Next.js Blog Template',
description:
'Suzu is a minimalist blog template with a serene sakura-inspired theme, blending modern design with a touch of traditional Japanese aesthetics.',
keywords:
'Suzu, Next.js, markdown blog, Tailwind CSS, blog template, sakura, ZL Asica',
authors: [{ name: 'ZL Asica' }],
title: `${config.title} - ${config.subTitle}`,
description: config.description,
keywords: config.keywords,
authors: [{ url: config.author.link, name: config.author.name }],
openGraph: {
title: `${config.title} - ${config.subTitle}`,
description: config.description,
type: 'website',
locale: config.lang,
},
};

export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const config = getConfig();

return (
<html lang='zh'>
<body className={`${roboto.variable} antialiased`}>
<html lang={config.lang}>
{config.scriptSlotHeader?.map((scriptUrl, index) => (
<Script key={index} src={scriptUrl} strategy='beforeInteractive' />
))}
<body className={`${roboto.variable} ${notoSansSC.variable} antialiased`}>
<ThemeProvider />
<Header />
<Header siteTitle={config.title} />
<main>{children}</main>
<Footer />

{config.scriptSlotFooter.map((scriptUrl, index) => (
<Script key={index} src={scriptUrl} strategy='lazyOnload' />
))}
</body>
</html>
);
Expand Down
11 changes: 3 additions & 8 deletions src/app/not-found.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use client';

import Link from 'next/link';
import { useEffect, useState } from 'react';

export default function Custom404() {
Expand Down Expand Up @@ -37,18 +38,12 @@ export default function Custom404() {
<span className='font-bold'>{countdown}</span> seconds.
</p>
<div className='mt-10 flex items-center justify-center gap-x-6'>
<a
<Link
href='/'
className='hover:bg-sakuraPink-dark rounded-md bg-sakuraPink px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600'
>
Go back home
</a>
<a
href='/'
className='text-skyblue hover:text-skyblue-dark text-sm font-semibold'
>
Contact support <span aria-hidden='true'>&rarr;</span>
</a>
</Link>
</div>
</div>
</main>
Expand Down
11 changes: 7 additions & 4 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import Image from 'next/image';
import PostsPage from './posts/page';
import { getConfig } from '@/lib/getConfig';

export default function Home() {
const config = getConfig();

return (
<div>
{/* Top Banner */}
<div
className='relative h-[40vh] w-full bg-cover bg-center sm:h-[40vh] md:h-[600px] lg:h-[800px]'
style={{ backgroundImage: "url('/images/katomegumi.jpg')" }}
style={{ backgroundImage: `url(${config.background})` }}
>
{/* Avatar */}
<div className='absolute left-1/2 top-[40%] -translate-x-1/2 transform'>
<Image
src='/images/avatar.jpg'
src={config.avatar}
alt='Avatar'
width={150}
height={150}
Expand All @@ -22,8 +25,8 @@ export default function Home() {
</div>

{/* Slogan */}
<div className='mt-4 text-center'>
<h1 className='text-2xl font-semibold'>Your Slogan Goes Here</h1>
<div className='mt-4 px-6 text-center'>
<h1 className='text-2xl font-semibold'>{config.slogan}</h1>
</div>

{/* Posts List - centered */}
Expand Down
8 changes: 8 additions & 0 deletions src/app/posts/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { PostData } from '@/types';
import '@/styles/codeblock.css';
import '@/styles/postContent.css';
import 'highlight.js/styles/an-old-hope.css';
import { getConfig } from '@/lib/getConfig';

interface PostPageProps {
params: {
Expand All @@ -12,6 +13,7 @@ interface PostPageProps {
}

export default async function PostPage({ params }: PostPageProps) {
const config = getConfig();
const post: PostData = await getPostData(params.slug);

return (
Expand Down Expand Up @@ -47,6 +49,12 @@ export default async function PostPage({ params }: PostPageProps) {
className='post-content mx-auto mt-10 w-full max-w-3xl'
dangerouslySetInnerHTML={{ __html: post.contentHtml }}
/>

{/* Comment */}
<div
className='mx-auto mt-10 w-full max-w-3xl'
dangerouslySetInnerHTML={{ __html: config.slotComment }}
/>
</article>
);
}
24 changes: 24 additions & 0 deletions src/app/posts/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react';
import type { Metadata } from 'next';
import { getConfig } from '@/lib/getConfig';

const config = getConfig();

export const metadata: Metadata = {
title: `Posts - ${config.title}`,
description: `Posts page of ${config.title} - ${config.description}`,
openGraph: {
title: `Posts - ${config.title}`,
description: `Posts page of ${config.title} - ${config.description}`,
type: 'website',
locale: config.lang,
},
};

export default function PostsLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return <>{children}</>;
}
12 changes: 12 additions & 0 deletions src/app/robots.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { MetadataRoute } from 'next';

export default function robots(): MetadataRoute.Robots {
return {
rules: {
userAgent: '*',
// allow: '/',
disallow: '/',
},
// sitemap: '',
};
}
3 changes: 0 additions & 3 deletions src/app/robots.txt

This file was deleted.

Loading

0 comments on commit 432b3fa

Please sign in to comment.