Files
ymb-site/src/layouts/AppShell.jsx
T
Zhou Weidong d6da152dec feat: 官网补充公司主体信息与隐私政策、服务条款页
新增 /privacy、/terms 页面,提供英文与印尼文版本,覆盖 Google 登录数据、Play 内购与订阅、账号删除及印尼个人数据保护要求;关于页补充法定主体、注册地址与联系方式,页脚下沉法律入口,下载区仅保留 Google Play。
2026-11-13 13:29:15 +08:00

51 lines
2.0 KiB
React

// Author: fruit.com.cn
import { Suspense, useState } from 'react';
import { Link, Outlet, useLocation } from 'react-router-dom';
import { useLocale, useUi } from '../app/providers/AppProviders';
import { Sidebar } from './components/Sidebar';
import { TopBar } from './components/TopBar';
import { UploadVideoDialog } from './components/UploadVideoDialog';
const FOOTER_LINKS = {
id: { privacy: 'Privasi', terms: 'Ketentuan', about: 'Tentang YMB' },
en: { privacy: 'Privacy', terms: 'Terms', about: 'About YMB' },
zh: { privacy: '隐私政策', terms: '服务条款', about: '关于 YMB' },
};
export function AppShell() {
const { locale } = useLocale();
const { sidebarOpen, setSidebarOpen } = useUi();
const location = useLocation();
const [uploadOpen, setUploadOpen] = useState(false);
const immersive = location.pathname === '/shorts';
const links = FOOTER_LINKS[locale.code] || FOOTER_LINKS.en;
return (
<>
<TopBar onToggleSidebar={() => setSidebarOpen(!sidebarOpen)} onUpload={() => setUploadOpen(true)} />
<Sidebar />
<main className={`content ${sidebarOpen ? '' : 'content-wide'}`}>
<Suspense fallback={<div className="route-loading" aria-busy="true" />}>
<Outlet />
</Suspense>
{!immersive && (
<footer className="site-footer">
<div>© {new Date().getFullYear()} {locale.copyright}</div>
<nav className="site-footer-links" aria-label="Legal and company information">
<Link to="/privacy">{links.privacy}</Link>
<span aria-hidden="true">·</span>
<Link to="/terms">{links.terms}</Link>
<span aria-hidden="true">·</span>
<Link to="/about">{links.about}</Link>
</nav>
</footer>
)}
</main>
{sidebarOpen && (
<button className="scrim mobile-only" onClick={() => setSidebarOpen(false)} aria-label="Close" type="button" />
)}
<UploadVideoDialog open={uploadOpen} onClose={() => setUploadOpen(false)} />
</>
);
}