Skip to content

Commit fb89b07

Browse files
committed
perf: optimize data fetching and add lazy loading for images
Performance improvements to reduce initial load time and network usage: 1. Database query optimization - Add getRecentPublishedArticles() to fetch only needed articles with LIMIT - Add listRecentProjects() to fetch only needed projects with LIMIT - Home page now fetches only 3 articles and 5 projects instead of all 2. Image lazy loading - Add loading="lazy" to all content images (articles, projects, members) - Excludes logos and above-the-fold images - Improves initial page load performance Files modified: - src/lib/server/database/articles.server.ts - src/lib/server/database/projects.server.ts - src/lib/data/public/index.remote.ts - src/routes/(site)/+page.svelte - All article/project/member listing and detail pages
1 parent 8863034 commit fb89b07

File tree

16 files changed

+104
-213
lines changed

16 files changed

+104
-213
lines changed

docs/knowledges/ui-design.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,17 @@ Applied to:
6969

7070
## Navigation Structure
7171

72-
**Header Navigation** (3 groups max for UX)
73-
- **About** dropdown: About, Activities, Join
74-
- **Content** dropdown: Articles, Projects
75-
- **Members**: Direct link
72+
**Header Navigation** (Simple direct links)
73+
- Articles
74+
- Projects
75+
- Members
7676

77-
Mobile: All items in drawer menu
77+
**Footer Navigation** (Comprehensive links)
78+
- About section: About, Activities, Join, Donation
79+
- Content section: Articles, Projects, Members
80+
- Social section: GitHub, Twitter
81+
82+
Mobile: Drawer menu mirrors header navigation (Articles, Projects, Members)
7883

7984
## Public Pages Structure
8085

src/lib/components/home/ArticlesSection.svelte

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
src={article.coverUrl}
4040
alt={article.title}
4141
class="aspect-[5/3] w-full object-cover"
42+
loading="lazy"
4243
/>
4344
{/if}
4445
<div class="p-6">

src/lib/components/home/HeroSection.svelte

Lines changed: 37 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,5 @@
11
<script lang="ts">
22
import { ArrowRight, Code2 } from "lucide-svelte";
3-
4-
type Props = {
5-
members: number;
6-
projects: number;
7-
years: number;
8-
};
9-
10-
const { members, projects, years }: Props = $props();
113
</script>
124

135
<section class="relative min-h-screen overflow-hidden bg-white">
@@ -29,117 +21,49 @@
2921
></div>
3022

3123
<div class="relative z-10 mx-auto flex min-h-screen max-w-6xl flex-col justify-center px-6 py-20">
32-
<div class="grid items-center gap-12 lg:grid-cols-12 lg:gap-16">
33-
<!-- Left content -->
34-
<div class="lg:col-span-7">
35-
<div class="mb-8 flex flex-wrap items-center gap-3">
36-
<div
37-
class="flex items-center gap-2 rounded-full border border-[#00D372]/30 bg-[#00D372]/10 px-4 py-2"
38-
>
39-
<div class="h-2 w-2 rounded-full bg-[#00D372] shadow-[0_0_8px_rgba(0,211,114,0.6)]"></div>
40-
<span class="font-mono text-xs font-medium text-zinc-700">SINCE 2019</span>
41-
</div>
42-
<div
43-
class="flex items-center gap-2 rounded-full border border-zinc-200 bg-zinc-50 px-4 py-2"
44-
>
45-
<Code2 class="h-3.5 w-3.5 text-zinc-500" />
46-
<span class="font-mono text-xs text-zinc-600">The University of Tokyo</span>
47-
</div>
48-
</div>
49-
50-
<h1 class="mb-10 text-5xl font-bold leading-[1.1] tracking-tight text-zinc-900 sm:text-6xl lg:text-7xl">
51-
Build<br />
52-
<span class="text-zinc-400">the</span>
53-
<span class="text-[#00D372]">Future</span><br />
54-
<span class="text-zinc-400">with</span> Code<span class="text-[#00D372]">;</span>
55-
</h1>
56-
57-
<p class="mb-10 max-w-xl text-lg leading-relaxed text-zinc-600 sm:text-xl">
58-
東京大学のソフトウェアエンジニアリングサークル。
59-
<span class="font-semibold text-zinc-800">学生が実際にプロダクトを作り、世に届ける。</span>
60-
</p>
61-
62-
<div class="flex flex-wrap items-center gap-4">
63-
<a
64-
href="/join"
65-
class="group inline-flex items-center gap-2 rounded-lg bg-[#00D372] px-8 py-4 font-semibold text-white shadow-lg shadow-[#00D372]/30 transition-all hover:shadow-xl hover:shadow-[#00D372]/40 focus:outline-none focus:ring-2 focus:ring-[#00D372] focus:ring-offset-2"
66-
>
67-
<span>参加する</span>
68-
<ArrowRight class="h-5 w-5 transition-transform group-hover:translate-x-1" />
69-
</a>
70-
<a
71-
href="/projects"
72-
class="group inline-flex items-center gap-2 rounded-lg bg-zinc-900 px-8 py-4 font-semibold text-white transition-all hover:bg-zinc-800 focus:outline-none focus:ring-2 focus:ring-[#00D372] focus:ring-offset-2"
73-
>
74-
プロジェクトを見る
75-
<ArrowRight class="h-5 w-5 transition-transform group-hover:translate-x-1" />
76-
</a>
24+
<div class="mx-auto max-w-3xl text-center">
25+
<div class="mb-8 flex flex-wrap items-center justify-center gap-3">
26+
<div
27+
class="flex items-center gap-2 rounded-full border border-[#00D372]/30 bg-[#00D372]/10 px-4 py-2"
28+
>
29+
<div class="h-2 w-2 rounded-full bg-[#00D372] shadow-[0_0_8px_rgba(0,211,114,0.6)]"></div>
30+
<span class="font-mono text-xs font-medium text-zinc-700">SINCE 2019</span>
7731
</div>
78-
</div>
79-
80-
<!-- Right stats card -->
81-
<div class="lg:col-span-5">
8232
<div
83-
class="group relative overflow-hidden rounded-3xl border border-zinc-200/50 bg-white/80 p-8 shadow-xl shadow-zinc-900/5 backdrop-blur-md transition-all hover:border-[#00D372]/30 hover:bg-[#00D372]/5 hover:shadow-2xl hover:shadow-[#00D372]/10"
84-
aria-hidden="true"
33+
class="flex items-center gap-2 rounded-full border border-zinc-200 bg-zinc-50 px-4 py-2"
8534
>
86-
<div class="space-y-6">
87-
<div class="flex items-center justify-between">
88-
<span class="font-mono text-xs text-zinc-400">// stats</span>
89-
<div class="h-2 w-2 rounded-full bg-[#00D372]"></div>
90-
</div>
91-
92-
<div class="space-y-4">
93-
<div>
94-
<div class="mb-1 font-mono text-xs uppercase tracking-wider text-zinc-400">
95-
Members
96-
</div>
97-
<div class="flex items-baseline gap-2">
98-
<span class="text-5xl font-bold text-zinc-900">
99-
{members}
100-
</span>
101-
<span class="text-2xl text-[#00D372]">+</span>
102-
</div>
103-
</div>
104-
105-
<div class="h-px bg-zinc-100"></div>
106-
107-
<div>
108-
<div class="mb-1 font-mono text-xs uppercase tracking-wider text-zinc-400">
109-
Projects
110-
</div>
111-
<div class="flex items-baseline gap-2">
112-
<span class="text-5xl font-bold text-zinc-900">
113-
{projects}
114-
</span>
115-
<span class="text-2xl text-[#00D372]">+</span>
116-
</div>
117-
</div>
35+
<Code2 class="h-3.5 w-3.5 text-zinc-500" />
36+
<span class="font-mono text-xs text-zinc-600">The University of Tokyo</span>
37+
</div>
38+
</div>
11839

119-
<div class="h-px bg-zinc-100"></div>
40+
<h1 class="mb-10 text-5xl font-bold leading-[1.1] tracking-tight text-zinc-900 sm:text-6xl lg:text-7xl">
41+
Build<br />
42+
<span class="text-zinc-400">the</span>
43+
<span class="text-[#00D372]">Future</span><br />
44+
<span class="text-zinc-400">with</span> Code<span class="text-[#00D372]">;</span>
45+
</h1>
12046

121-
<div>
122-
<div class="mb-1 font-mono text-xs uppercase tracking-wider text-zinc-400">
123-
Years Active
124-
</div>
125-
<div class="flex items-baseline gap-2">
126-
<span class="text-5xl font-bold text-zinc-900">
127-
{years}
128-
</span>
129-
<span class="text-2xl text-[#00D372]">+</span>
130-
</div>
131-
</div>
132-
</div>
47+
<p class="mb-10 mx-auto max-w-2xl text-lg leading-relaxed text-zinc-600 sm:text-xl">
48+
東京大学のソフトウェアエンジニアリングサークル。
49+
<span class="font-semibold text-zinc-800">学生が実際にプロダクトを作り、世に届ける。</span>
50+
</p>
13351

134-
<div class="pt-4">
135-
<div
136-
class="rounded-xl border border-zinc-100 bg-zinc-50 p-4 font-mono text-sm text-zinc-600"
137-
>
138-
<span class="text-[#00D372]">"</span>Ship it<span class="text-[#00D372]">"</span>
139-
</div>
140-
</div>
141-
</div>
142-
</div>
52+
<div class="flex flex-wrap items-center justify-center gap-4">
53+
<a
54+
href="/join"
55+
class="group inline-flex items-center gap-2 rounded-lg bg-[#00D372] px-8 py-4 font-semibold text-white shadow-lg shadow-[#00D372]/30 transition-all hover:shadow-xl hover:shadow-[#00D372]/40 focus:outline-none focus:ring-2 focus:ring-[#00D372] focus:ring-offset-2"
56+
>
57+
<span>参加する</span>
58+
<ArrowRight class="h-5 w-5 transition-transform group-hover:translate-x-1" />
59+
</a>
60+
<a
61+
href="/projects"
62+
class="group inline-flex items-center gap-2 rounded-lg bg-zinc-900 px-8 py-4 font-semibold text-white transition-all hover:bg-zinc-800 focus:outline-none focus:ring-2 focus:ring-[#00D372] focus:ring-offset-2"
63+
>
64+
プロジェクトを見る
65+
<ArrowRight class="h-5 w-5 transition-transform group-hover:translate-x-1" />
66+
</a>
14367
</div>
14468
</div>
14569
</div>

src/lib/components/home/ProjectsSection.svelte

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
src={featuredProject.coverUrl}
5252
alt={featuredProject.name}
5353
class="aspect-[5/3] w-full object-cover transition-transform duration-500 group-hover:scale-105"
54+
loading="lazy"
5455
/>
5556
</div>
5657
{/if}
@@ -84,6 +85,7 @@
8485
src={project.coverUrl}
8586
alt={project.name}
8687
class="aspect-[5/3] w-full object-cover transition-transform duration-500 group-hover:scale-105"
88+
loading="lazy"
8789
/>
8890
</div>
8991
{/if}

src/lib/data/public/index.remote.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as v from "valibot";
22
import { query } from "$app/server";
33
import {
44
getPublishedArticle,
5+
getRecentPublishedArticles,
56
getRelatedArticles,
67
listPublishedArticles,
78
searchPublishedArticles,
@@ -10,6 +11,7 @@ import { getMemberBySlug, listMembers, searchMembers } from "$lib/server/databas
1011
import {
1112
getProjectBySlug,
1213
listProjects,
14+
listRecentProjects,
1315
searchProjects,
1416
} from "$lib/server/database/projects.server";
1517
import type { SearchResult } from "$lib/shared/logic/search";
@@ -28,6 +30,11 @@ export const getPublicRelatedArticles = query(
2830
export const getPublicProjects = query(async () => listProjects());
2931
export const getPublicProject = query(v.string(), async (slug) => getProjectBySlug(slug));
3032

33+
export const getHomeArticles = query(v.number(), async (limit) =>
34+
getRecentPublishedArticles(limit),
35+
);
36+
export const getHomeProjects = query(v.number(), async (limit) => listRecentProjects(limit));
37+
3138
export const getPublicMembers = query(async () => listMembers());
3239
export const getPublicMember = query(v.string(), async (slug) => getMemberBySlug(slug));
3340

src/lib/server/database/articles.server.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,3 +191,12 @@ export async function getRecentDraftArticles(limit: number) {
191191
limit,
192192
});
193193
}
194+
195+
export async function getRecentPublishedArticles(limit: number) {
196+
return db.query.article.findMany({
197+
where: eq(article.published, true),
198+
orderBy: desc(article.publishedAt),
199+
limit,
200+
with: { author: true },
201+
});
202+
}

src/lib/server/database/projects.server.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,13 @@ export async function getRecentProjects(limit: number) {
133133
limit,
134134
});
135135
}
136+
137+
export async function listRecentProjects(limit: number) {
138+
return db.query.project.findMany({
139+
orderBy: (t, { desc }) => desc(t.createdAt),
140+
limit,
141+
with: {
142+
projectMembers: { with: { member: true } },
143+
},
144+
});
145+
}

src/routes/(site)/+layout.svelte

Lines changed: 7 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
<img src={logo} alt="ut.code();" class="h-8" />
5050
</a>
5151
</div>
52-
<div class="hidden items-center gap-4 md:flex">
52+
<div class="hidden items-center gap-6 md:flex">
5353
<button
5454
type="button"
5555
onclick={openSearch}
@@ -63,73 +63,12 @@
6363
>
6464
</button>
6565

66-
<div class="dropdown dropdown-hover">
67-
<div
68-
tabindex="0"
69-
role="button"
70-
class="text-sm text-zinc-500 transition-colors hover:text-zinc-900"
71-
>
72-
About
73-
</div>
74-
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
75-
<ul
76-
tabindex="0"
77-
class="menu dropdown-content z-[1] mt-3 w-52 rounded-lg border border-zinc-200 bg-white p-2 shadow"
78-
>
79-
<li>
80-
<a
81-
href="/about"
82-
class="text-sm text-zinc-600 transition-colors hover:bg-primary/5 hover:text-primary"
83-
>About</a
84-
>
85-
</li>
86-
<li>
87-
<a
88-
href="/activities"
89-
class="text-sm text-zinc-600 transition-colors hover:bg-primary/5 hover:text-primary"
90-
>Activities</a
91-
>
92-
</li>
93-
<li>
94-
<a
95-
href="/join"
96-
class="text-sm text-zinc-600 transition-colors hover:bg-primary/5 hover:text-primary"
97-
>Join</a
98-
>
99-
</li>
100-
</ul>
101-
</div>
102-
103-
<div class="dropdown dropdown-hover">
104-
<div
105-
tabindex="0"
106-
role="button"
107-
class="text-sm text-zinc-500 transition-colors hover:text-zinc-900"
108-
>
109-
Content
110-
</div>
111-
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
112-
<ul
113-
tabindex="0"
114-
class="menu dropdown-content z-[1] mt-3 w-52 rounded-lg border border-zinc-200 bg-white p-2 shadow"
115-
>
116-
<li>
117-
<a
118-
href="/articles"
119-
class="text-sm text-zinc-600 transition-colors hover:bg-primary/5 hover:text-primary"
120-
>Articles</a
121-
>
122-
</li>
123-
<li>
124-
<a
125-
href="/projects"
126-
class="text-sm text-zinc-600 transition-colors hover:bg-primary/5 hover:text-primary"
127-
>Projects</a
128-
>
129-
</li>
130-
</ul>
131-
</div>
132-
66+
<a href="/articles" class="text-sm text-zinc-500 transition-colors hover:text-zinc-900"
67+
>Articles</a
68+
>
69+
<a href="/projects" class="text-sm text-zinc-500 transition-colors hover:text-zinc-900"
70+
>Projects</a
71+
>
13372
<a href="/members" class="text-sm text-zinc-500 transition-colors hover:text-zinc-900"
13473
>Members</a
13574
>
@@ -236,20 +175,6 @@
236175
<span>検索...</span>
237176
</button>
238177
<ul class="space-y-2">
239-
<li>
240-
<a
241-
href="/about"
242-
class="block rounded-lg px-4 py-2 text-sm text-zinc-600 transition-colors hover:bg-primary/5 hover:text-primary"
243-
>About</a
244-
>
245-
</li>
246-
<li>
247-
<a
248-
href="/activities"
249-
class="block rounded-lg px-4 py-2 text-sm text-zinc-600 transition-colors hover:bg-primary/5 hover:text-primary"
250-
>Activities</a
251-
>
252-
</li>
253178
<li>
254179
<a
255180
href="/articles"
@@ -271,13 +196,6 @@
271196
>Members</a
272197
>
273198
</li>
274-
<li>
275-
<a
276-
href="/join"
277-
class="block rounded-lg px-4 py-2 text-sm text-zinc-600 transition-colors hover:bg-primary/5 hover:text-primary"
278-
>Join</a
279-
>
280-
</li>
281199
</ul>
282200
</div>
283201
</div>

0 commit comments

Comments
 (0)