Skip to content

Commit 592c5ef

Browse files
committed
feat: enhance image handling and optimize loading performance
1 parent 867b130 commit 592c5ef

File tree

5 files changed

+99
-35
lines changed

5 files changed

+99
-35
lines changed

app/components/EditOnGithub.tsx

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,26 @@
11
import Link from "next/link";
22

3-
// 复用的编辑链接按钮,统一封装图标与样式
4-
interface EditOnGithubProps {
5-
href: string;
6-
}
7-
8-
export function EditOnGithub({ href }: EditOnGithubProps) {
3+
export function EditOnGithub({ href }: { href: string }) {
94
return (
105
<Link
116
href={href}
12-
target="_blank"
13-
rel="noopener noreferrer"
14-
className="inline-flex items-center justify-center rounded-md border border-transparent w-9 h-9 text-muted-foreground transition-colors hover:bg-muted/80 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
15-
aria-label="Edit on GitHub"
7+
className="inline-flex items-center gap-2 rounded-md px-4 h-11 text-base font-medium hover:bg-muted/80 hover:text-foreground no-underline"
168
>
17-
<span
18-
aria-hidden
19-
className="material-symbols-outlined text-lg flex items-center justify-center"
9+
<svg
10+
aria-hidden="true"
11+
className="h-8 w-8"
12+
viewBox="0 0 24 24"
13+
fill="none"
14+
stroke="currentColor"
15+
strokeWidth={1.8}
16+
strokeLinecap="round"
17+
strokeLinejoin="round"
2018
>
21-
edit
22-
</span>
19+
<path d="M12 20h9" />
20+
<path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4Z" />
21+
<path d="m15 5 4 4" />
22+
</svg>
23+
Edit Me
2324
</Link>
2425
);
2526
}

app/components/Hero.tsx

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import Link from "next/link";
2-
import { ZoteroFeed } from "@/app/components/ZoteroFeed";
2+
import ZoteroFeedLazy from "@/app/components/ZoteroFeedLazy";
33
import { Contribute } from "@/app/components/Contribute";
4+
import Image from "next/image";
45

56
export function Hero() {
67
const categories: { title: string; desc: string; href: string }[] = [
@@ -30,19 +31,18 @@ export function Hero() {
3031
<section className="relative">
3132
<div className="container mx-auto px-6 pt-12 pb-0 text-center">
3233
<div className="relative mx-auto max-w-5xl mt-12">
33-
<picture>
34-
<source srcSet="/mascot.webp" type="image/webp" />
35-
<source srcSet="/mascot.png" type="image/png" />
36-
<img
37-
src="/mascot.webp"
38-
alt="Mascot"
39-
className="mx-auto h-[25vh] w-auto object-contain"
40-
loading="eager"
41-
fetchPriority="high"
42-
width="420"
43-
height="400"
44-
/>
45-
</picture>
34+
<Image
35+
src="/mascot.webp"
36+
alt="Mascot"
37+
width={420}
38+
height={400}
39+
priority
40+
loading="eager"
41+
fetchPriority="high"
42+
sizes="216px"
43+
className="mx-auto w-auto max-h-[25vh] object-contain"
44+
style={{ maxWidth: "216px", height: "auto" }}
45+
/>
4646
<h1 className="pointer-events-none select-none text-4xl md:text-6xl font-semibold leading-tight bg-gradient-primary bg-clip-text text-transparent">
4747
内卷地狱
4848
</h1>
@@ -75,7 +75,7 @@ export function Hero() {
7575
</ul>
7676
</div>
7777
{/* 最新文献(Zotero,避免被 iframe 拒绝) */}
78-
<ZoteroFeed groupId={6053219} limit={8} />
78+
<ZoteroFeedLazy groupId={6053219} limit={8} />
7979
</div>
8080
</section>
8181
);

app/components/ZoteroFeedLazy.tsx

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
"use client";
2+
import { useEffect, useRef, useState } from "react";
3+
import dynamic from "next/dynamic";
4+
5+
/**
6+
* 懒加载 ZoteroFeed 的 props
7+
* @param groupId - Zotero 组 ID
8+
* @param limit - 显示的文献数量
9+
*/
10+
interface ZoteroFeedLazyProps {
11+
groupId?: number;
12+
limit?: number;
13+
}
14+
15+
/**
16+
* 动态导入真正组件
17+
* @returns ZoteroFeed 组件
18+
*/
19+
const ZoteroFeed = dynamic(() => import("./ZoteroFeed"), {
20+
ssr: false,
21+
loading: () => null,
22+
});
23+
24+
/**
25+
* 懒加载 ZoteroFeed
26+
* @param groupId - Zotero 组 ID
27+
* @param limit - 显示的文献数量
28+
* @returns 懒加载的 ZoteroFeed 组件
29+
*/
30+
export default function ZoteroFeedLazy({
31+
groupId = 6053219,
32+
limit = 8,
33+
}: ZoteroFeedLazyProps) {
34+
const ref = useRef<HTMLDivElement | null>(null);
35+
const [visible, setVisible] = useState(false);
36+
37+
useEffect(() => {
38+
if (!ref.current || visible) return;
39+
const io = new IntersectionObserver(
40+
(entries) => {
41+
if (entries[0]?.isIntersecting) {
42+
setVisible(true);
43+
io.disconnect();
44+
}
45+
},
46+
{ rootMargin: "200px 0px" },
47+
);
48+
io.observe(ref.current);
49+
return () => io.disconnect();
50+
}, [visible]);
51+
52+
return (
53+
<div ref={ref}>
54+
{visible ? <ZoteroFeed groupId={groupId} limit={limit} /> : null}
55+
</div>
56+
);
57+
}

app/layout.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,15 @@ export default function RootLayout({
133133
return (
134134
<html lang="en" suppressHydrationWarning>
135135
<head>
136-
{/* 谷歌图标字体用于 Edit 按钮的 material symbol */}
136+
{/* Preconnect to critical third-party origins to shrink the critical request chain */}
137+
<link rel="preconnect" href="https://www.google-analytics.com" />
138+
{/* Preload the decorative sky texture so the LCP background image is discovered immediately */}
137139
<link
138-
rel="stylesheet"
139-
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&icon_names=edit"
140+
rel="preload"
141+
href="/cloud_2.png"
142+
as="image"
143+
type="image/png"
144+
fetchPriority="high"
140145
/>
141146
</head>
142147
<body
@@ -162,9 +167,9 @@ export default function RootLayout({
162167
{/* 谷歌分析 */}
163168
<Script
164169
src="https://www.googletagmanager.com/gtag/js?id=G-ED4GVN8YVW"
165-
strategy="afterInteractive"
170+
strategy="lazyOnload"
166171
/>
167-
<Script id="gtag-init" strategy="afterInteractive">
172+
<Script id="gtag-init" strategy="lazyOnload">
168173
{`
169174
window.dataLayer = window.dataLayer || [];
170175
function gtag(){dataLayer.push(arguments);}

next.config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ const config = {
4848
},
4949
],
5050
unoptimized: true,
51+
formats: ["image/avif", "image/webp"],
5152
},
5253
};
5354

0 commit comments

Comments
 (0)