Files
eryao/web/src/components/LegalPage.astro
T

123 lines
5.4 KiB
Plaintext
Raw Normal View History

---
import { t, localePath, type Locale } from '../i18n/utils';
import fs from 'node:fs';
import path from 'node:path';
import { marked } from 'marked';
interface Props {
locale: Locale;
docType: 'privacy_policy' | 'terms_of_service' | 'about_us';
}
const { locale, docType } = Astro.props;
const footer = t(locale, 'footer');
const about = t(locale, 'about');
const titleMap: Record<string, Record<Locale, string>> = {
privacy_policy: { zh: '隐私政策', zh_Hant: '隱私政策', en: 'Privacy Policy' },
terms_of_service: { zh: '服务条款', zh_Hant: '服務條款', en: 'Terms of Service' },
};
const subtitleMap: Record<string, Record<Locale, string>> = {
privacy_policy: { zh: '最后更新日期:2026年4月27日', zh_Hant: '最後更新日期:2026年4月27日', en: 'Last updated: April 27, 2026' },
terms_of_service: { zh: '最后更新日期:2026年4月27日', zh_Hant: '最後更新日期:2026年4月27日', en: 'Last updated: April 27, 2026' },
};
const title = titleMap[docType]?.[locale] ?? '';
const subtitle = subtitleMap[docType]?.[locale] ?? '';
const filePath = path.resolve('public/legal', locale, `${docType}.md`);
let raw = '';
try {
raw = fs.readFileSync(filePath, 'utf-8');
raw = raw.replace(/^#\s+.+\n*/m, '');
} catch {
raw = `Content not available.`;
}
const content = await marked(raw);
const sideInfo: Record<string, Record<Locale, { type: string; date: string; law?: string; email: string }>> = {
privacy_policy: {
zh: { type: '隐私政策', date: '2026年4月27日', email: 'ann@xunmee.com' },
zh_Hant: { type: '隱私政策', date: '2026年4月27日', email: 'ann@xunmee.com' },
en: { type: 'Privacy Policy', date: 'April 27, 2026', email: 'ann@xunmee.com' },
},
terms_of_service: {
zh: { type: '服务条款', date: '2026年4月27日', law: '美国加利福尼亚州法律', email: 'ann@xunmee.com' },
zh_Hant: { type: '服務條款', date: '2026年4月27日', law: '美國加利福尼亞州法律', email: 'ann@xunmee.com' },
en: { type: 'Terms of Service', date: 'April 27, 2026', law: 'California, USA', email: 'ann@xunmee.com' },
},
};
const info = sideInfo[docType]?.[locale];
const isActive = (linkType: string) => linkType === docType;
---
<!-- Header -->
<section class="w-full bg-gradient-to-b from-white to-violet-50 py-16 md:py-20 px-6 md:px-20 text-center">
<h1 class="reveal text-slate-900 text-4xl md:text-[48px] font-extrabold">{title}</h1>
<p class="reveal stagger-1 text-slate-500 text-lg mt-4">{subtitle}</p>
</section>
<!-- Content: Left article + Right info card -->
<section class="w-full py-16 md:py-20 px-6 md:px-20 bg-white">
<div class="max-w-6xl mx-auto flex flex-col md:flex-row gap-16">
<!-- Article -->
<div class="reveal flex-1 prose prose-slate max-w-none
[&_h2]:text-[28px] [&_h2]:font-bold [&_h2]:text-slate-900 [&_h2]:mt-8 [&_h2]:mb-2
[&_h3]:text-2xl [&_h3]:font-bold [&_h3]:text-slate-900 [&_h3]:mt-6 [&_h3]:mb-2
[&_p]:text-slate-500 [&_p]:text-base [&_p]:leading-loose
[&_strong]:text-slate-700 [&_ul]:list-disc [&_ul]:pl-6 [&_li]:text-slate-500 [&_li]:leading-loose
[&_a]:text-violet-600 [&_hr]:border-slate-200 [&_hr]:my-6">
<Fragment set:html={content} />
</div>
<!-- Side card -->
{info && (
<div class="reveal-right w-full md:w-[320px] bg-slate-50 border border-slate-200 rounded-2xl p-8 flex flex-col gap-6 shrink-0 self-start sticky top-28">
<h3 class="text-slate-900 text-xl font-bold">
{locale === 'en' ? 'Document Info' : '文档信息'}
</h3>
<div class="h-px bg-slate-200"></div>
<div>
<p class="text-slate-400 text-sm font-semibold">{locale === 'en' ? 'Type' : '文档类型'}</p>
<p class="text-slate-600 text-[15px]">{info.type}</p>
</div>
<div>
<p class="text-slate-400 text-sm font-semibold">{locale === 'en' ? 'Last Updated' : '最后更新'}</p>
<p class="text-slate-600 text-[15px]">{info.date}</p>
</div>
{info.law && (
<div>
<p class="text-slate-400 text-sm font-semibold">{locale === 'en' ? 'Governing Law' : '适用法律'}</p>
<p class="text-slate-600 text-[15px]">{info.law}</p>
</div>
)}
<div>
<p class="text-slate-400 text-sm font-semibold">{locale === 'en' ? 'Contact' : '联系邮箱'}</p>
<p class="text-slate-600 text-[15px]">{info.email}</p>
</div>
</div>
)}
</div>
</section>
<!-- Warning -->
<section class="w-full bg-amber-50 py-20 px-6 md:px-20">
<div class="reveal max-w-[800px] mx-auto text-center flex flex-col gap-5">
<h3 class="text-amber-600 text-2xl font-bold">{about.warningTitle}</h3>
<p class="text-amber-700 text-[15px] leading-loose">{about.warningBody}</p>
</div>
</section>
<!-- Legal Links -->
<section class="w-full bg-slate-50 py-12 px-6 md:px-20">
<div class="reveal max-w-[600px] mx-auto text-center flex flex-col gap-5">
<h3 class="text-slate-900 text-xl font-bold">{about.legalTitle}</h3>
<div class="flex justify-center gap-8">
<a href={localePath(locale, '/privacy')} class={`text-[15px] hover:underline ${isActive('privacy_policy') ? 'text-violet-600 font-semibold' : 'text-slate-500'}`}>{footer.col3Link1}</a>
<a href={localePath(locale, '/terms')} class={`text-[15px] hover:underline ${isActive('terms_of_service') ? 'text-violet-600 font-semibold' : 'text-slate-500'}`}>{footer.col3Link2}</a>
</div>
</div>
</section>