Skip to content

Commit bcee75c

Browse files
committed
feat: create all pages and add status
1 parent ed2d458 commit bcee75c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+859
-360
lines changed

app/[lang]/[[...mdxPath]]/page.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,12 @@ export default async function Page(props: PageProps) {
3535
)
3636

3737
const isHomepage = !params.mdxPath || params.mdxPath.length === 0
38+
const pageKey = `${params.lang}-${params.mdxPath?.join('-') || 'home'}`
3839

3940
return (
4041
<>
4142
<JsonLd data={schemaData} />
42-
<Wrapper toc={toc} metadata={metadata}>
43+
<Wrapper key={pageKey} toc={toc} metadata={metadata}>
4344
<MDXContent {...props} params={params} />
4445
{!isHomepage && <SuggestPattern />}
4546
</Wrapper>

app/_actions/patterns.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { PATTERNS_MAP } from '@/app/_constants/patterns'
2+
import * as Icons from 'lucide-react'
3+
import { type LucideIcon } from 'lucide-react'
4+
import type { MdxFile } from 'nextra'
5+
import { getPageMap } from 'nextra/page-map'
6+
import { existsSync } from 'node:fs'
7+
import { join } from 'node:path'
8+
import 'server-only'
9+
import { PatternCategory } from '../_utils/get-pattern-categories'
10+
11+
export type PatternStatus = 'complete' | 'draft' | 'coming-soon'
12+
13+
export type Pattern = {
14+
title: string
15+
description: string
16+
href: string
17+
icon?: LucideIcon
18+
status: PatternStatus
19+
frontMatter?: Record<string, unknown>
20+
}
21+
22+
export async function getRandomPatternServer(locale: string = 'en'): Promise<Pattern | null> {
23+
const categories = await getPatternCategories(locale)
24+
25+
const allPatterns = categories.flatMap(category => category.patterns)
26+
27+
const availablePatterns = allPatterns.filter(pattern =>
28+
pattern.href && pattern.status !== 'coming-soon'
29+
)
30+
31+
if (availablePatterns.length === 0) return null
32+
33+
const randomIndex = Math.floor(Math.random() * availablePatterns.length)
34+
const pattern = availablePatterns[randomIndex]
35+
36+
return pattern || null
37+
}
38+
39+
export async function getPatternCategories(locale: string): Promise<PatternCategory[]> {
40+
41+
// Get all pattern categories and check if they exist first
42+
const categories = Object.values(PATTERNS_MAP)
43+
.filter(category => {
44+
const categoryPath = join(process.cwd(), 'content', locale, 'patterns', category.path)
45+
return existsSync(categoryPath)
46+
})
47+
48+
const categoryData = await Promise.all(
49+
categories.map(async (category) => {
50+
const pageMap = await getPageMap(`/${locale}/patterns/${category.path}`)
51+
if (!pageMap) return null
52+
53+
const pages = pageMap.filter(page =>
54+
'name' in page &&
55+
page.name !== 'index'
56+
) as MdxFile[]
57+
58+
return {
59+
name: category.name,
60+
path: category.path,
61+
patterns: pages.map(page => {
62+
const iconName = page.frontMatter?.icon
63+
const status = (page.frontMatter?.status as PatternStatus) || 'coming-soon'
64+
65+
return {
66+
title: page.frontMatter?.title || page.name,
67+
description: page.frontMatter?.description || '',
68+
href: `/${locale}/patterns/${category.path}/${page.name}`,
69+
icon: iconName ? Icons[iconName] : undefined,
70+
status,
71+
frontMatter: page.frontMatter || {}
72+
}
73+
})
74+
}
75+
})
76+
)
77+
78+
return categoryData.filter((category) => category !== null)
79+
}

app/_components/featured.tsx

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,29 @@
11
'use client'
22

3-
import { Star } from "lucide-react";
4-
import { usePlausible } from 'next-plausible';
5-
import { getRandomPattern, Pattern } from "../_constants/patterns";
6-
import { LinkCustom } from "./link-custom";
3+
import { Star } from "lucide-react"
4+
import { usePlausible } from 'next-plausible'
5+
import { useEffect, useState } from 'react'
6+
import { Pattern } from "../_actions/patterns"
7+
import { LinkCustom } from "./link-custom"
78

8-
type FeaturedPatternProps = {
9-
pattern: Pattern;
10-
};
9+
async function getRandomPattern(locale: string = 'en') {
10+
// Try to get from sessionStorage first
11+
const cached = sessionStorage.getItem(`featured-pattern-${locale}`)
12+
if (cached) {
13+
return JSON.parse(cached)
14+
}
15+
16+
const response = await fetch(`/api/patterns/random?locale=${locale}`)
17+
if (!response.ok) return null
18+
19+
const pattern = await response.json()
20+
21+
// Cache in sessionStorage
22+
sessionStorage.setItem(`featured-pattern-${locale}`, JSON.stringify(pattern))
23+
return pattern
24+
}
1125

12-
const FeaturedPatternSection = ({ pattern }: FeaturedPatternProps) => {
26+
const FeaturedPatternSection = ({ pattern }: { pattern: Pattern }) => {
1327
const plausible = usePlausible()
1428

1529
return (
@@ -40,8 +54,12 @@ const FeaturedPatternSection = ({ pattern }: FeaturedPatternProps) => {
4054
);
4155
};
4256

43-
const pattern = getRandomPattern();
44-
4557
export const FeaturedPattern = () => {
58+
const [pattern, setPattern] = useState<Pattern | null>(null)
59+
60+
useEffect(() => {
61+
getRandomPattern().then(setPattern)
62+
}, [])
63+
4664
return pattern ? <FeaturedPatternSection pattern={pattern} /> : null;
4765
};

app/_components/link-custom.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ import Link, { LinkProps } from 'next/link'
55
import * as React from 'react'
66

77
const linkVariants = cva(
8-
"inline-flex items-center gap-2 cursor-pointer transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 !no-underline relative",
8+
"inline-flex items-center gap-2 cursor-pointer transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 relative",
99
{
1010
variants: {
1111
variant: {
12-
default: 'text-foreground hover:text-foreground/50',
13-
primary: 'text-primary hover:text-primary/80 hover:translate-x-0.5',
12+
default: 'text-foreground !underline',
13+
primary: 'text-primary hover:text-primary/80 hover:translate-x-0.5 underline',
1414
destructive: 'text-destructive hover:text-destructive/80 hover:scale-105',
1515
muted: 'text-muted-foreground hover:text-muted-foreground/80',
1616
neutral: 'flex items-center gap-2 dark:text-neutral-800 border border-neutral-400 bg-neutral-100 rounded-md px-4 py-2 !no-underline',
@@ -23,6 +23,7 @@ const linkVariants = cva(
2323
sm: 'text-sm',
2424
xs: 'text-xs',
2525
lg: 'text-lg',
26+
article: 'text-[17px]'
2627
},
2728
},
2829
defaultVariants: {

app/_components/sections/overview-grid.tsx

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
import { cn } from '@/app/_utils/cn'
2+
import { Pattern } from '@/app/_utils/get-pattern-categories'
23
import { getPatterns } from '@app/_utils/get-patterns'
3-
import { type LucideIcon } from 'lucide-react'
4+
45
import { LinkCustom } from '../link-custom'
56
import { Badge } from '../ui/badge'
67

7-
type Pattern = {
8-
title: string
9-
description: string
10-
icon?: LucideIcon;
11-
href?: string
12-
comingSoon?: boolean
8+
9+
type PatternWrapperProps = {
10+
pattern: Pattern
1311
}
1412

1513
export const OverviewGrid = async ({ lang }: { lang: string }) => {
@@ -33,20 +31,20 @@ export const OverviewGrid = async ({ lang }: { lang: string }) => {
3331
)
3432
}
3533

36-
const PatternWrapper = ({ pattern }: { pattern: Pattern }) => {
34+
const PatternWrapper = ({ pattern }: PatternWrapperProps) => {
3735
const wrapperClasses = cn(
3836
"relative rounded-xl border border-neutral-200 dark:border-neutral-800",
39-
!pattern.comingSoon && "border-neutral-400 dark:border-neutral-600 hover:bg-neutral-100 hover:border-neutral-200 dark:hover:bg-neutral-900 dark:hover:border-neutral-400 hover:scale-105 transition-all duration-100 ease-in-out"
37+
pattern.status !== 'coming-soon' && "border-neutral-400 dark:border-neutral-600 hover:bg-neutral-100 hover:border-neutral-200 dark:hover:bg-neutral-900 dark:hover:border-neutral-400 hover:scale-105 transition-all duration-100 ease-in-out"
4038
)
4139

4240
const content = <PatternContent pattern={pattern} />
4341

4442
return (
4543
<div className={wrapperClasses}>
46-
{pattern.href ? (
44+
{pattern.status !== 'coming-soon' ? (
4745
<LinkCustom
4846
href={pattern.href}
49-
className="!no-underline"
47+
className="!no-underline w-full"
5048
icon={false}
5149
>
5250
{content}
@@ -56,19 +54,24 @@ const PatternWrapper = ({ pattern }: { pattern: Pattern }) => {
5654
)
5755
}
5856

59-
const PatternContent = ({ pattern }: { pattern: Pattern }) => (
57+
const PatternContent = ({ pattern }: PatternWrapperProps) => (
6058
<div className={cn(
6159
"relative flex flex-col gap-4 overflow-hidden rounded-xl p-5 transition-all duration-300",
62-
!pattern.comingSoon ? "hover:animate-card-hover cursor-pointer" : "opacity-60 cursor-not-allowed"
60+
pattern.status !== 'coming-soon' ? "hover:animate-card-hover cursor-pointer" : "opacity-60 cursor-not-allowed"
6361
)}>
6462

6563
<div className="flex items-center justify-between">
6664
{pattern.icon && <pattern.icon className="h-8 w-8 text-primary" />}
67-
{pattern.comingSoon && (
65+
{pattern.status === 'coming-soon' && (
6866
<Badge variant="outline">
6967
<span className="text-[10px]">Coming soon</span>
7068
</Badge>
7169
)}
70+
{pattern.status === 'draft' && (
71+
<Badge variant="outline">
72+
<span className="text-[10px]">Draft</span>
73+
</Badge>
74+
)}
7275
</div>
7376
<div className="flex flex-col gap-2">
7477
<div className="flex items-center justify-between">

app/_constants/patterns.ts

Lines changed: 13 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
import { contentManagementPatterns } from './patterns/content-management'
2-
import { formPatterns } from './patterns/forms'
3-
import { navigationPatterns } from './patterns/navigation'
4-
import { userFeedbackPatterns } from './patterns/user-feedback'
1+
import { Pattern } from "../_utils/get-pattern-categories"
52

63
export const PATTERNS_MAP = {
74
navigation: {
@@ -22,42 +19,24 @@ export const PATTERNS_MAP = {
2219
}
2320
} as const
2421

25-
26-
27-
export const PATTERNS = {
28-
'Layout & Navigation': navigationPatterns,
29-
'Content Management': contentManagementPatterns,
30-
'User Feedback': userFeedbackPatterns,
31-
'Input & Forms': formPatterns
32-
} as const
33-
34-
35-
export type Pattern = {
36-
title: string
37-
description: string
38-
href?: string
39-
comingSoon?: boolean
40-
}
41-
4222
export type Category = {
4323
name: string
4424
patterns: Pattern[]
4525
}
4626

27+
export const getRandomPattern = async (locale: string = 'en'): Promise<Pattern | null> => {
28+
const { getPatternCategories } = await import('../_utils/get-pattern-categories')
29+
const categories = await getPatternCategories(locale)
4730

48-
export const getRandomPattern = (): Pattern | null => {
49-
const allPatterns = Object.values(PATTERNS).flatMap(category => [...category] as Pattern[]);
50-
const availablePatterns = allPatterns.filter(pattern => pattern.href);
31+
const allPatterns = categories.flatMap(category => category.patterns)
32+
const availablePatterns = allPatterns.filter(pattern =>
33+
pattern.href && pattern.status !== 'coming-soon'
34+
)
5135

52-
if (availablePatterns.length === 0) return null;
36+
if (availablePatterns.length === 0) return null
5337

54-
const randomIndex = Math.floor(Math.random() * availablePatterns.length);
55-
const pattern = availablePatterns[randomIndex];
56-
if (!pattern) return null;
38+
const randomIndex = Math.floor(Math.random() * availablePatterns.length)
39+
const pattern = availablePatterns[randomIndex]
5740

58-
return {
59-
title: pattern.title,
60-
description: pattern.description,
61-
href: pattern.href!
62-
};
63-
};
41+
return pattern || null
42+
}

app/_constants/patterns/content-management.ts

Lines changed: 0 additions & 29 deletions
This file was deleted.

0 commit comments

Comments
 (0)