Skip to content

Commit fc19b3c

Browse files
authored
Feat/single collection page directory browsing (#412)
* feat(collection-card): wrap collection card with Next.js Link for navigation * feat(collection-detail): update filters and layout structure * refactor(collection-detail): disable category filters on collection detail pages * refactor(collection-detail): disable category filters on collection detail pages * refactor(collection-detail): remove the nav to align with other design pages * fix: resolve hero description nesting warning on collection detail * fix: reset collection card spinner on route change * feat(collections): apply sorting to filtered items in collection detail * chore: remove unused featured-items hook/logic. * chore: add custom backdropBlur 2px o support existing * Restore previously removed code for home 2 filter categories * Integrate Home 2 layout and filtering for the single collection page * fix: harden collection detail hero props and count display
1 parent ac2ed92 commit fc19b3c

File tree

7 files changed

+545
-153
lines changed

7 files changed

+545
-153
lines changed
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import { getCachedItems } from "@/lib/content";
2+
import { notFound } from "next/navigation";
3+
import { CollectionDetail } from "@/components/collections";
4+
5+
export const revalidate = 10;
6+
7+
// Allow non-English locales to be generated on-demand (ISR)
8+
export const dynamicParams = true;
9+
10+
// Disable static params generation - handle dynamically
11+
export async function generateStaticParams() {
12+
return [];
13+
}
14+
15+
export default async function CollectionPage({
16+
params,
17+
}: {
18+
params: Promise<{ locale: string; slug: string }>;
19+
}) {
20+
const { locale, slug } = await params;
21+
22+
// TODO: Fetch collection from your data source
23+
// For now, using mock data - replace with actual data fetching
24+
const collections = {
25+
"ai-tools": {
26+
id: "1",
27+
slug: "ai-tools",
28+
name: "AI & Machine Learning Tools",
29+
description: "Discover powerful AI and machine learning tools to enhance your projects. From neural networks to natural language processing, find the best open source solutions.",
30+
icon_url: "🤖",
31+
item_count: 24,
32+
isActive: true,
33+
},
34+
"dev-tools": {
35+
id: "2",
36+
slug: "dev-tools",
37+
name: "Developer Tools",
38+
description: "Essential tools every developer needs. IDEs, version control, debugging tools, and productivity enhancers to streamline your development workflow.",
39+
icon_url: "🛠️",
40+
item_count: 42,
41+
isActive: true,
42+
},
43+
"web-frameworks": {
44+
id: "3",
45+
slug: "web-frameworks",
46+
name: "Web Frameworks",
47+
description: "Modern web frameworks for building scalable applications. From frontend libraries to full-stack solutions, explore frameworks that power the web.",
48+
icon_url: "🌐",
49+
item_count: 18,
50+
isActive: true,
51+
},
52+
"data-science": {
53+
id: "4",
54+
slug: "data-science",
55+
name: "Data Science & Analytics",
56+
description: "Tools and libraries for data analysis, visualization, and scientific computing. Transform raw data into actionable insights with these powerful solutions.",
57+
icon_url: "📊",
58+
item_count: 31,
59+
isActive: true,
60+
},
61+
"cloud-native": {
62+
id: "5",
63+
slug: "cloud-native",
64+
name: "Cloud Native Tools",
65+
description: "Build, deploy, and manage cloud-native applications. Container orchestration, service mesh, monitoring, and other tools for modern cloud infrastructure.",
66+
icon_url: "☁️",
67+
item_count: 27,
68+
isActive: true,
69+
},
70+
"security": {
71+
id: "6",
72+
slug: "security",
73+
name: "Security & Privacy",
74+
description: "Protect your applications and data with these security tools. From encryption libraries to vulnerability scanners, stay secure with open source solutions.",
75+
icon_url: "🔒",
76+
item_count: 19,
77+
isActive: true,
78+
},
79+
"mobile-dev": {
80+
id: "7",
81+
slug: "mobile-dev",
82+
name: "Mobile Development",
83+
description: "Cross-platform and native mobile development frameworks. Build stunning iOS and Android apps with React Native, Flutter, and other modern tools.",
84+
icon_url: "📱",
85+
item_count: 35,
86+
isActive: true,
87+
},
88+
"devops": {
89+
id: "8",
90+
slug: "devops",
91+
name: "DevOps & CI/CD",
92+
description: "Automate your deployment pipeline with CI/CD tools, infrastructure as code, and DevOps best practices for faster, more reliable releases.",
93+
icon_url: "🚀",
94+
item_count: 29,
95+
isActive: true,
96+
},
97+
"databases": {
98+
id: "9",
99+
slug: "databases",
100+
name: "Databases & Storage",
101+
description: "Relational, NoSQL, and distributed databases. From PostgreSQL to MongoDB, find the right data storage solution for your application.",
102+
icon_url: "💾",
103+
item_count: 22,
104+
isActive: true,
105+
},
106+
"testing": {
107+
id: "10",
108+
slug: "testing",
109+
name: "Testing & QA",
110+
description: "Unit testing, integration testing, and end-to-end testing frameworks. Ensure code quality with comprehensive testing tools.",
111+
icon_url: "🧪",
112+
item_count: 16,
113+
isActive: true,
114+
},
115+
"ui-libraries": {
116+
id: "11",
117+
slug: "ui-libraries",
118+
name: "UI Component Libraries",
119+
description: "Pre-built UI components and design systems. Speed up development with beautiful, accessible component libraries for React, Vue, and more.",
120+
icon_url: "🎨",
121+
item_count: 38,
122+
isActive: true,
123+
},
124+
"monitoring": {
125+
id: "12",
126+
slug: "monitoring",
127+
name: "Monitoring & Observability",
128+
description: "Application performance monitoring, logging, and tracing tools. Keep your systems healthy with real-time insights and alerts.",
129+
icon_url: "📈",
130+
item_count: 14,
131+
isActive: true,
132+
},
133+
"api-tools": {
134+
id: "13",
135+
slug: "api-tools",
136+
name: "API Development",
137+
description: "REST, GraphQL, and gRPC tools for building robust APIs. Documentation generators, testing tools, and API gateways for modern backends.",
138+
icon_url: "🔌",
139+
item_count: 26,
140+
isActive: true,
141+
},
142+
};
143+
144+
const collection = collections[slug as keyof typeof collections];
145+
146+
if (!collection) {
147+
notFound();
148+
}
149+
150+
// Fetch all items
151+
const { categories, tags, items } = await getCachedItems({ lang: locale });
152+
153+
return (
154+
<CollectionDetail
155+
collection={collection}
156+
tags={tags}
157+
items={items}
158+
total={items.length}
159+
start={0}
160+
page={1}
161+
basePath={`/collections/${slug}`}
162+
/>
163+
);
164+
}

components/collections/collection-card.tsx

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
"use client";
22
import Link from "next/link";
33
import { useTranslations } from "next-intl";
4+
import { Spinner } from "@heroui/react";
5+
import { useEffect, useState } from "react";
6+
import { usePathname } from "next/navigation";
47
import { Collection } from "@/types/collection";
58

69
interface CollectionCardProps {
@@ -9,9 +12,18 @@ interface CollectionCardProps {
912

1013
export function CollectionCard({ collection }: CollectionCardProps) {
1114
const t = useTranslations("common");
15+
const [isNavigating, setIsNavigating] = useState(false);
16+
const pathname = usePathname();
17+
18+
// Reset spinner when route changes (e.g., back navigation)
19+
useEffect(() => {
20+
setIsNavigating(false);
21+
}, [pathname]);
1222

1323
return (
14-
<div
24+
<Link
25+
href={`/collections/${collection.slug}`}
26+
onClick={() => setIsNavigating(true)}
1527
className="group relative block p-6 bg-linear-to-br from-white via-red-50/30 to-red-100/20
1628
dark:from-gray-800 dark:via-red-900/10 dark:to-red-900/5
1729
rounded-2xl border border-gray-200 dark:border-gray-700
@@ -97,6 +109,12 @@ return (
97109
<div className="absolute top-0 right-0 w-32 h-32 -translate-y-1/2 translate-x-1/2
98110
bg-theme-primary/5 rounded-full blur-2xl group-hover:blur-2xl
99111
transition-all duration-500"></div>
100-
</div>
112+
113+
{isNavigating && (
114+
<div className="absolute inset-0 bg-white/80 dark:bg-gray-900/80 backdrop-blur-xs rounded-2xl flex items-center justify-center z-50 transition-opacity duration-300">
115+
<Spinner size="lg" color="primary" />
116+
</div>
117+
)}
118+
</Link>
101119
);
102120
}

0 commit comments

Comments
 (0)