Skip to content

Commit 2e6ef26

Browse files
committed
feat(landing): enhance landing page with privacy and terms of service
- Added new pages for Privacy Policy and Terms of Service, including markdown content rendering. - Integrated `react-markdown` for displaying legal documents. - Updated layout to include a footer with links to the new pages. - Refactored layout components to improve structure and maintainability. - Removed unused footer navigation items to streamline the design. Signed-off-by: Innei <tukon479@gmail.com>
1 parent d1dee58 commit 2e6ef26

File tree

13 files changed

+697
-115
lines changed

13 files changed

+697
-115
lines changed

apps/landing/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"react-dom": "19.2.0",
3838
"react-error-boundary": "6.0.0",
3939
"react-intersection-observer": "10.0.0",
40+
"react-markdown": "^9.0.1",
4041
"sonner": "2.0.7",
4142
"tailwind-merge": "3.4.0",
4243
"usehooks-ts": "3.1.1",

apps/landing/src/app/layout.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ import type { Viewport } from 'next'
44

55
import { HydrationEndDetector } from '~/components/common/HydrationEndDetector'
66
import { ScrollTop } from '~/components/common/ScrollTop'
7+
import { NocturneBackground } from '~/components/landing/NocturneBackground'
8+
import { Footer } from '~/components/layout'
9+
import { PageHeader } from '~/components/layout/PageHeader'
710
import { Root } from '~/components/layout/root/Root'
811
import { sansFont, serifFont } from '~/lib/fonts'
912

@@ -100,7 +103,12 @@ export default async function RootLayout({
100103
>
101104
<Providers>
102105
<div data-theme>
103-
<Root>{children}</Root>
106+
<Root>
107+
<NocturneBackground />
108+
<PageHeader />
109+
{children}
110+
<Footer />
111+
</Root>
104112
</div>
105113
</Providers>
106114

apps/landing/src/app/page.tsx

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
'use client'
22

3-
import { NocturneBackground } from '~/components/landing/NocturneBackground'
43
import {
54
ArtistNote,
65
ClosingCTA,
@@ -9,22 +8,17 @@ import {
98
NocturneHero,
109
PillarsSection,
1110
} from '~/components/landing/NocturneSections'
12-
import { Footer } from '~/components/layout/Footer'
13-
import { PageHeader } from '~/components/layout/PageHeader'
1411

1512
export default function Home() {
1613
return (
1714
<div className="relative min-h-screen overflow-hidden bg-[#020202] text-white">
18-
<NocturneBackground />
1915
<main className="relative z-10 mx-auto flex w-full max-w-6xl flex-col gap-20 px-4 py-16 sm:px-6 lg:px-0">
20-
<PageHeader />
2116
<NocturneHero />
2217
<PillarsSection />
2318
<JourneySection />
2419
<GalleryPreview />
2520
<ArtistNote />
2621
<ClosingCTA />
27-
<Footer />
2822
</main>
2923
</div>
3024
)
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { readFile } from 'node:fs/promises'
2+
import { resolve } from 'node:path'
3+
4+
import { MarkdownContent } from '~/components/common/MarkdownContent'
5+
import { NormalContainer } from '~/components/layout/container/Normal'
6+
7+
export const metadata = {
8+
title: 'Privacy Policy',
9+
description: 'Afilmory Privacy Policy',
10+
}
11+
12+
export default async function PrivacyPage() {
13+
// Resolve path - try both monorepo root and app root
14+
const cwd = process.cwd()
15+
const filePath =
16+
cwd.endsWith('apps/landing') || cwd.endsWith('apps/landing/')
17+
? resolve(cwd, 'src/legal/privacy.md')
18+
: resolve(cwd, 'apps/landing/src/legal/privacy.md')
19+
const content = await readFile(filePath, 'utf-8')
20+
21+
return (
22+
<div className="relative min-h-screen text-white">
23+
<NormalContainer>
24+
<article className="py-16">
25+
<MarkdownContent content={content} />
26+
</article>
27+
</NormalContainer>
28+
</div>
29+
)
30+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { readFile } from 'node:fs/promises'
2+
import { resolve } from 'node:path'
3+
4+
import { MarkdownContent } from '~/components/common/MarkdownContent'
5+
import { NormalContainer } from '~/components/layout/container/Normal'
6+
7+
export const metadata = {
8+
title: 'Terms of Service',
9+
description: 'Afilmory Terms of Service',
10+
}
11+
12+
export default async function TermsPage() {
13+
// Resolve path - try both monorepo root and app root
14+
const cwd = process.cwd()
15+
const filePath =
16+
cwd.endsWith('apps/landing') || cwd.endsWith('apps/landing/')
17+
? resolve(cwd, 'src/legal/tos.md')
18+
: resolve(cwd, 'apps/landing/src/legal/tos.md')
19+
const content = await readFile(filePath, 'utf-8')
20+
21+
return (
22+
<div className="relative min-h-screen text-white">
23+
<NormalContainer>
24+
<article className="py-16">
25+
<MarkdownContent content={content} />
26+
</article>
27+
</NormalContainer>
28+
</div>
29+
)
30+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
'use client'
2+
3+
import type { FC } from 'react'
4+
import ReactMarkdown from 'react-markdown'
5+
6+
interface MarkdownContentProps {
7+
content: string
8+
}
9+
10+
export const MarkdownContent: FC<MarkdownContentProps> = ({ content }) => {
11+
return (
12+
<div className="prose prose-invert prose-headings:text-white prose-p:text-white/80 prose-a:text-white prose-strong:text-white prose-ul:text-white/80 prose-ol:text-white/80 prose-li:text-white/80 prose-hr:border-white/20 max-w-none">
13+
<ReactMarkdown
14+
components={{
15+
h1: ({ children }) => (
16+
<h1 className="mt-8 mb-6 text-3xl font-bold text-white first:mt-0">
17+
{children}
18+
</h1>
19+
),
20+
h2: ({ children }) => (
21+
<h2 className="mt-8 mb-4 text-2xl font-semibold text-white">
22+
{children}
23+
</h2>
24+
),
25+
h3: ({ children }) => (
26+
<h3 className="mt-6 mb-3 text-xl font-semibold text-white">
27+
{children}
28+
</h3>
29+
),
30+
p: ({ children }) => (
31+
<p className="mb-4 leading-7 text-white/80">{children}</p>
32+
),
33+
ul: ({ children }) => (
34+
<ul className="mb-4 ml-6 list-disc space-y-2 text-white/80">
35+
{children}
36+
</ul>
37+
),
38+
ol: ({ children }) => (
39+
<ol className="mb-4 ml-6 list-decimal space-y-2 text-white/80">
40+
{children}
41+
</ol>
42+
),
43+
li: ({ children }) => (
44+
<li className="leading-7 text-white/80">{children}</li>
45+
),
46+
strong: ({ children }) => (
47+
<strong className="font-semibold text-white">{children}</strong>
48+
),
49+
a: ({ href, children }) => (
50+
<a
51+
href={href}
52+
className="text-white underline underline-offset-2 hover:text-white/80"
53+
target={href?.startsWith('http') ? '_blank' : undefined}
54+
rel={href?.startsWith('http') ? 'noopener noreferrer' : undefined}
55+
>
56+
{children}
57+
</a>
58+
),
59+
hr: () => <hr className="my-8 border-white/20" />,
60+
}}
61+
>
62+
{content}
63+
</ReactMarkdown>
64+
</div>
65+
)
66+
}

apps/landing/src/components/layout/Footer.tsx

Lines changed: 5 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -2,43 +2,6 @@
22

33
import Link from 'next/link'
44

5-
const footerNav = [
6-
{
7-
title: '策展主题',
8-
links: [
9-
{ label: '城市夜行', href: '#' },
10-
{ label: '肖像诗篇', href: '#' },
11-
{ label: '记忆胶片', href: '#' },
12-
],
13-
},
14-
{
15-
title: '体验',
16-
links: [
17-
{ label: '预约沉浸导览', href: '#' },
18-
{ label: '私享展陈', href: '#' },
19-
{ label: '影像叙事工作坊', href: '#' },
20-
],
21-
},
22-
{
23-
title: '合作',
24-
links: [
25-
{ label: '品牌共创', href: '#' },
26-
{ label: '艺术项目', href: '#' },
27-
{ label: '驻地策展', href: '#' },
28-
],
29-
},
30-
]
31-
32-
const ContactRow = () => (
33-
<div className="flex flex-wrap gap-4 text-sm text-white/70">
34-
<span>hello@afilmory.studio</span>
35-
<span className="text-white/40">/</span>
36-
<span>WeChat · AFILMORY</span>
37-
<span className="text-white/40">/</span>
38-
<span>IG · @afilmory.gallery</span>
39-
</div>
40-
)
41-
425
export const Footer = () => {
436
return (
447
<footer className="relative mt-24 overflow-hidden rounded-t-[48px] border border-white/10 bg-linear-to-b from-black/80 via-black/60 to-black px-6 py-14 text-white sm:px-10">
@@ -60,42 +23,17 @@ export const Footer = () => {
6023
Afilmory
6124
致力于为摄影师、策展人和品牌打造沉浸的展示体验。我们以黑色背景延展出一条长廊,观众在其中聆听故事,而非参数。
6225
</p>
63-
<ContactRow />
64-
</div>
65-
<div className="grid gap-8 sm:grid-cols-3">
66-
{footerNav.map((column) => (
67-
<div key={column.title} className="space-y-4">
68-
<p className="text-xs tracking-[0.4em] text-white/45 uppercase">
69-
{column.title}
70-
</p>
71-
<ul className="space-y-3 text-sm text-white/70">
72-
{column.links.map((link) => (
73-
<li key={link.label}>
74-
<Link
75-
href={link.href}
76-
className="transition hover:text-white"
77-
>
78-
{link.label}
79-
</Link>
80-
</li>
81-
))}
82-
</ul>
83-
</div>
84-
))}
8526
</div>
8627
</div>
8728
<div className="border-t border-white/10 pt-6 text-sm text-white/60">
8829
<div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
89-
<p>© 2025 Afilmory Studio · 光与记忆的私享馆</p>
30+
<p>© 2025 Afilmory.art</p>
9031
<div className="flex gap-6 text-white/70">
91-
<Link href="#" className="transition hover:text-white">
92-
策展预约
93-
</Link>
94-
<Link href="#" className="transition hover:text-white">
95-
私人藏家
32+
<Link href="/privacy" className="transition hover:text-white">
33+
Privacy Policy
9634
</Link>
97-
<Link href="#" className="transition hover:text-white">
98-
媒体合作
35+
<Link href="/terms" className="transition hover:text-white">
36+
Terms of Service
9937
</Link>
10038
</div>
10139
</div>

apps/landing/src/components/layout/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
*/
55

66
export { Footer } from './Footer'
7-
export { Header } from './Header'
7+
export { PageHeader } from './PageHeader'

0 commit comments

Comments
 (0)