Skip to content

Commit a2b9349

Browse files
committed
update page style
1 parent 3298b1b commit a2b9349

27 files changed

+570
-3642
lines changed

.npmrc

Lines changed: 0 additions & 1 deletion
This file was deleted.

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ RUN apk add --no-cache libc6-compat
77
WORKDIR /app
88

99
# Install dependencies based on the preferred package manager
10-
COPY .npmrc package.json pnpm-lock.yaml* ./
10+
COPY package.json pnpm-lock.yaml* ./
1111
RUN \
1212
if [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i --frozen-lockfile; \
1313
else echo "Lockfile not found." && exit 1; \

app/about/page.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
export default function About() {
2+
return (
3+
<div className="mx-auto max-w-screen-md px-5">
4+
<div className="space-y-4">
5+
<p>
6+
正在疯狂码字
7+
<span className="ml-2 animate-pulse">⌨️</span>
8+
</p>
9+
<p> 预计不久后完工(应该吧...)</p>
10+
</div>
11+
</div>
12+
);
13+
}

app/globals.css

Lines changed: 43 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,49 +2,55 @@
22
@tailwind components;
33
@tailwind utilities;
44

5-
@layer base {
6-
.light {
7-
--color-primary-blue: 138 230 251;
8-
--color-text-muted: 100 116 139;
9-
--color-text-link: 6 182 212;
10-
}
5+
html {
6+
color-scheme: light;
7+
}
118

12-
.dark {
13-
--color-primary-blue: 59 130 246;
14-
--color-text-muted: 212 212 212;
15-
--color-text-link: 96 165 250;
16-
}
9+
html.dark {
10+
color-scheme: dark;
1711
}
1812

19-
@layer components {
20-
.animated-link {
21-
position: relative;
22-
box-decoration-break: clone;
23-
text-decoration: none;
24-
}
13+
html,
14+
body {
15+
@apply size-full;
16+
}
2517

26-
.animated-link:hover:after {
27-
transform: translateZ(0) scale(1);
28-
}
18+
body {
19+
@apply font-sans antialiased;
20+
@apply flex flex-col;
21+
@apply bg-stone-100 dark:bg-stone-900;
22+
@apply text-black/50 dark:text-white/75;
23+
}
24+
25+
header {
26+
@apply fixed top-0 left-0 right-0 z-50 py-5;
27+
@apply bg-stone-100/75 dark:bg-stone-900/25;
28+
@apply backdrop-blur-sm saturate-200;
29+
}
30+
31+
main {
32+
@apply flex-1 py-32;
33+
}
34+
35+
footer {
36+
@apply py-5 text-sm;
37+
}
38+
39+
article {
40+
@apply max-w-full prose dark:prose-invert prose-img:mx-auto prose-img:my-auto;
41+
@apply prose-headings:font-semibold prose-p:font-serif;
42+
@apply prose-headings:text-black prose-headings:dark:text-white;
43+
}
2944

30-
.animated-link:after {
31-
left: 0;
32-
right: 0;
33-
bottom: -3px;
34-
content: '';
35-
height: 2px;
36-
position: absolute;
37-
transform: translateZ(0) scaleX(0);
38-
transform-origin: left center;
39-
transition: all 0.15s ease-in-out;
40-
background-image: linear-gradient(
41-
to right,
42-
theme('colors.text.link'),
43-
theme('colors.text.link')
44-
);
45+
@layer utilities {
46+
article a {
47+
@apply font-sans text-current underline underline-offset-2;
48+
@apply decoration-black/15 dark:decoration-white/30;
49+
@apply transition-colors duration-300 ease-in-out;
4550
}
4651

47-
.animated-link.active:after {
48-
transform: translateZ(0) scale(1);
52+
article a:hover {
53+
@apply text-black dark:text-white;
54+
@apply decoration-black/25 dark:decoration-white/50;
4955
}
5056
}

app/layout.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
11
import type { Metadata } from 'next';
2-
import { Space_Grotesk } from 'next/font/google';
2+
import { Inter } from 'next/font/google';
33

4-
import { Navbar } from '@/components/navbar';
5-
import { Footer } from '@/components/footer';
4+
import Header from '@/components/header';
5+
import Footer from '@/components/footer';
66

7-
import { Providers } from './providers';
7+
import Providers from './providers';
88
import './globals.css';
99

10-
const spaceGrotesk = Space_Grotesk({ subsets: ['latin'], display: 'swap' });
10+
const inter = Inter({ subsets: ['latin'] });
1111

1212
export const metadata: Metadata = {
1313
title: {
1414
template: '%s - Jee',
15-
default: 'Jee 的 Web 开发日志',
15+
default: 'Jee 的数字花园',
1616
},
17-
description: "Jee's portfolio",
17+
description: "Jee's digital garden",
1818
authors: [{ name: 'Jee' }],
1919
};
2020

2121
export default function RootLayout({ children }: { children: React.ReactNode }) {
2222
return (
2323
<html lang="en" suppressHydrationWarning>
24-
<body className={`${spaceGrotesk.className} mx-auto max-w-5xl text-lg`}>
24+
<body className={`${inter.className}`}>
2525
<Providers>
26-
<Navbar />
27-
<main className="px-6">{children}</main>
26+
<Header />
27+
<main>{children}</main>
2828
<Footer />
2929
</Providers>
3030
</body>

app/page.tsx

Lines changed: 59 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,69 @@
11
import { TinaMarkdown } from 'tinacms/dist/rich-text';
2+
3+
import Link from '@/components/link';
4+
import ArrowCard from '@/components/arrow-card';
25
import client from '@/tina/__generated__/client';
36

47
export const revalidate = 3600; // invalidate every hour
58

9+
async function getPageData() {
10+
const response = await client.queries.page({ relativePath: 'home.mdx' });
11+
12+
if (response.errors) {
13+
throw new Error('Failed to fetch page data');
14+
}
15+
16+
return response.data.page;
17+
}
18+
19+
async function getLatestPosts() {
20+
const response = await client.queries.postConnection({ last: 3, sort: 'date' });
21+
22+
if (response.errors) {
23+
throw new Error('Failed to fetch latest posts');
24+
}
25+
26+
return response.data.postConnection.edges;
27+
}
28+
629
export default async function Home() {
7-
const { data } = await client.queries.page({ relativePath: 'home.mdx' });
30+
const [page, posts] = await Promise.all([getPageData(), getLatestPosts()]);
831

932
return (
10-
<section>
11-
<h1 className="my-10 font-extrabold text-4xl">{data.page.title}</h1>
12-
13-
<TinaMarkdown
14-
content={data.page.body}
15-
components={{
16-
p: (props) => <p className="mb-10" {...props} />,
17-
ul: (props) => <ul className="my-6 ml-6 list-disc [&>li]:mt-2" {...props} />,
18-
}}
19-
/>
20-
</section>
33+
<div className="mx-auto max-w-screen-md px-5">
34+
<h3 className="font-semibold text-black dark:text-white">{page.title}</h3>
35+
36+
<div className="space-y-16">
37+
<section>
38+
<article className="space-y-4">
39+
<TinaMarkdown
40+
content={page.body}
41+
components={{
42+
p: (props) => <p {...props} />,
43+
bold: (props) => <b className="font-black" {...props} />,
44+
}}
45+
/>
46+
</article>
47+
</section>
48+
49+
<section className="space-y-6">
50+
<div className="flex justify-between items-center">
51+
<h3 className="font-semibold text-black dark:text-white">最近的文章</h3>
52+
<Link href="/posts" underline>
53+
查看所有文章
54+
</Link>
55+
</div>
56+
<ul className="flex flex-col gap-4">
57+
{posts?.map((post) => (
58+
<li key={post?.node?.id}>
59+
<Link href={`/posts/${post?.node?._sys.breadcrumbs.join('/')}`} className="block">
60+
<ArrowCard title={post?.node?.title} />
61+
</Link>
62+
</li>
63+
))}
64+
</ul>
65+
</section>
66+
</div>
67+
</div>
2168
);
2269
}

app/posts/[slug]/page.tsx

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { format } from 'date-fns';
22

3-
import { Markdown } from '@/components/markdown';
3+
import Markdown from '@/components/markdown';
4+
import BackTo from '@/components/back-to';
5+
import { readingTime } from '@/lib/utils';
46
import client from '@/tina/__generated__/client';
57

68
export const revalidate = 3600; // invalidate every hour
@@ -33,14 +35,22 @@ export default async function Post({ params }: { params: Promise<{ slug: string
3335
const { data } = await client.queries.post({ relativePath: `${slug}.mdx` });
3436

3537
return (
36-
<article className="prose dark:prose-invert prose-pre:rounded-none prose-a:underline-offset-4 prose-a:decoration-text-link hover:prose-a:text-text-link">
37-
<h1 className="mb-5">{data.post.title}</h1>
38-
39-
<time className="block text-text-muted" dateTime={data.post.date}>
40-
{format(new Date(data.post.date), 'MMM dd, yyyy')}
41-
</time>
42-
43-
<Markdown content={data.post.body} />
44-
</article>
38+
<div className="mx-auto max-w-screen-md px-5">
39+
<BackTo href="/posts">返回文章</BackTo>
40+
41+
<div className="space-y-3 my-10">
42+
<div className="flex items-center gap-2 text-sm">
43+
<time dateTime={data.post.date}>{format(new Date(data.post.date), 'yyyy-MM-dd')}</time>
44+
&bull;
45+
<span>阅读时间 {readingTime(JSON.stringify(data.post.body))} 分钟</span>
46+
</div>
47+
48+
<h1 className="text-3xl font-semibold text-black dark:text-white">{data.post.title}</h1>
49+
</div>
50+
51+
<article className="">
52+
<Markdown content={data.post.body} />
53+
</article>
54+
</div>
4555
);
4656
}

app/posts/page.tsx

Lines changed: 36 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import type { Metadata } from 'next';
22
import Link from 'next/link';
3-
import { format, isSameYear } from 'date-fns';
43

4+
import ArrowCard from '@/components/arrow-card';
55
import client from '@/tina/__generated__/client';
6+
import type { PostConnectionQuery } from '@/tina/__generated__/types';
67

78
export const revalidate = 3600; // invalidate every hour
89

910
export const metadata: Metadata = {
10-
title: '博客',
11+
title: '文章',
1112
};
1213

1314
export default async function Posts() {
@@ -17,40 +18,40 @@ export default async function Posts() {
1718
filter: { draft: { eq: false } },
1819
});
1920

21+
const posts = data.postConnection.edges?.reduce((acc, post) => {
22+
const year = new Date(post?.node?.date!).getFullYear().toString();
23+
24+
acc[year] ??= [];
25+
acc[year]?.push(post);
26+
27+
return acc;
28+
}, {} as Record<string, PostConnectionQuery['postConnection']['edges']>);
29+
30+
const years = Object.keys(posts ?? {}).sort((a, b) => parseInt(b) - parseInt(a));
31+
2032
return (
21-
<div>
22-
<ul className="my-6 ml-6 list-disc [&>li]:mt-2">
23-
{data.postConnection.edges?.map((post) => {
24-
const date = new Date(post?.node?.date!);
25-
26-
return (
27-
<li key={post?.node?.id}>
28-
<div className="flex flex-col sm:flex-row sm:gap-2">
29-
<div className="flex-1">
30-
<Link
31-
href={`/posts/${post?.node?._sys.breadcrumbs.join('/')}`}
32-
className="transition-[background-size] duration-300
33-
bg-gradient-to-r bg-left-bottom bg-no-repeat
34-
bg-[length:0%_55%] hover:bg-[length:100%_55%] dark:bg-[length:0%_2px] hover:dark:bg-[length:100%_2px]
35-
from-primary-blue to-primary-blue dark:from-primary-blue dark:to-primary-blue"
36-
>
37-
{post?.node?.title}
38-
</Link>
39-
</div>
40-
41-
<div className="pt-1 italic text-sm text-text-muted">
42-
<time dateTime={post?.node?.date}>
43-
{format(
44-
date,
45-
isSameYear(new Date(), date) ? 'MM-dd' : 'yyyy-MM-dd'
46-
)}
47-
</time>
48-
</div>
49-
</div>
50-
</li>
51-
);
52-
})}
53-
</ul>
33+
<div className="mx-auto max-w-screen-md px-5">
34+
<div className="space-y-10">
35+
<div className="font-semibold text-black dark:text-white">文章</div>
36+
37+
<div className="space-y-4">
38+
{years.map((year) => (
39+
<section className="space-y-4" key={year}>
40+
<div className="font-semibold text-black dark:text-white">{year}</div>
41+
42+
<ul className="flex flex-col gap-4">
43+
{posts?.[year]?.map((post) => (
44+
<li key={post?.node?.id}>
45+
<Link href={`/posts/${post?.node?._sys.breadcrumbs.join('/')}`}>
46+
<ArrowCard title={post?.node?.title} />
47+
</Link>
48+
</li>
49+
))}
50+
</ul>
51+
</section>
52+
))}
53+
</div>
54+
</div>
5455
</div>
5556
);
5657
}

app/providers.tsx

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
'use client';
22

3-
import { useRouter } from 'next/navigation';
4-
import { NextUIProvider } from '@nextui-org/react';
53
import { ThemeProvider } from 'next-themes';
64

7-
export function Providers({ children }: { children: React.ReactNode }) {
8-
const router = useRouter();
9-
5+
const Providers: React.FC<{ children: React.ReactNode }> = ({ children }) => {
106
return (
11-
<NextUIProvider navigate={router.push}>
12-
<ThemeProvider attribute="class" defaultTheme="light">
13-
{children}
14-
</ThemeProvider>
15-
</NextUIProvider>
7+
<ThemeProvider attribute="class" defaultTheme="light">
8+
{children}
9+
</ThemeProvider>
1610
);
17-
}
11+
};
12+
13+
export default Providers;

0 commit comments

Comments
 (0)