'app下载页
This commit is contained in:
70
app/[locale]/app/AppDownloadContent.tsx
Normal file
70
app/[locale]/app/AppDownloadContent.tsx
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { useTranslation } from "@/i18n/navigation";
|
||||||
|
|
||||||
|
export default function AppDownloadContent() {
|
||||||
|
const { t } = useTranslation("appDownload");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.history.scrollRestoration = "manual";
|
||||||
|
window.scrollTo(0, 0);
|
||||||
|
return () => {
|
||||||
|
window.history.scrollRestoration = "auto";
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const features = [
|
||||||
|
{ key: "resources", icon: "📚" },
|
||||||
|
{ key: "community", icon: "👥" },
|
||||||
|
{ key: "tools", icon: "🛠️" },
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-slate-50 dark:bg-slate-950">
|
||||||
|
<section className="py-20 sm:py-28">
|
||||||
|
<div className="mx-auto max-w-4xl px-4 sm:px-6 lg:px-8">
|
||||||
|
<div className="text-center">
|
||||||
|
<div className="mb-6 inline-flex h-24 w-24 items-center justify-center rounded-2xl bg-gradient-to-br from-sky-400 to-cyan-500 text-5xl shadow-lg shadow-sky-200/50 dark:shadow-sky-900/30">
|
||||||
|
📱
|
||||||
|
</div>
|
||||||
|
<h1 className="text-4xl font-bold tracking-tight text-slate-900 dark:text-slate-100 sm:text-5xl">
|
||||||
|
{t("title")}
|
||||||
|
</h1>
|
||||||
|
<p className="mx-auto mt-4 max-w-2xl text-lg text-slate-600 dark:text-slate-400">
|
||||||
|
{t("subtitle")}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-16 grid gap-6 sm:grid-cols-3">
|
||||||
|
{features.map(({ key, icon }) => (
|
||||||
|
<div
|
||||||
|
key={key}
|
||||||
|
className="card-hover flex flex-col items-center rounded-2xl border border-slate-100 bg-white p-6 text-center shadow-sm dark:border-slate-800 dark:bg-slate-900"
|
||||||
|
>
|
||||||
|
<span className="mb-4 flex h-14 w-14 items-center justify-center rounded-xl bg-slate-50 text-2xl dark:bg-slate-800">
|
||||||
|
{icon}
|
||||||
|
</span>
|
||||||
|
<h3 className="text-lg font-bold text-slate-900 dark:text-slate-100">
|
||||||
|
{t(`features.${key}.title`)}
|
||||||
|
</h3>
|
||||||
|
<p className="mt-2 text-sm text-slate-500 dark:text-slate-400">
|
||||||
|
{t(`features.${key}.desc`)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-16 text-center">
|
||||||
|
<div className="inline-flex items-center gap-2 rounded-full bg-amber-100 px-4 py-2 text-sm font-medium text-amber-800 dark:bg-amber-900/50 dark:text-amber-200">
|
||||||
|
{t("comingSoon")}
|
||||||
|
</div>
|
||||||
|
<p className="mt-4 text-slate-500 dark:text-slate-400">
|
||||||
|
{t("comingSoonDesc")}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
21
app/[locale]/app/page.tsx
Normal file
21
app/[locale]/app/page.tsx
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import Header from "../../components/Header";
|
||||||
|
import Footer from "../../components/Footer";
|
||||||
|
import AppDownloadContent from "./AppDownloadContent";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "App 下载 | App Download",
|
||||||
|
description: "数字游民指南移动端应用,随时随地获取资源与社区动态。",
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function AppDownloadPage() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Header />
|
||||||
|
<main>
|
||||||
|
<AppDownloadContent />
|
||||||
|
</main>
|
||||||
|
<Footer />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -3,14 +3,16 @@
|
|||||||
import { Link, useTranslation } from "@/i18n/navigation";
|
import { Link, useTranslation } from "@/i18n/navigation";
|
||||||
import ShopCard from "./ShopCard";
|
import ShopCard from "./ShopCard";
|
||||||
|
|
||||||
const linkKeys = ["guide", "discord", "tools", "github", "feishu", "destinations"] as const;
|
const linkKeys = ["github", "destinations", "appDownload"] as const;
|
||||||
const linkIcons: Record<(typeof linkKeys)[number], string> = {
|
const linkIcons: Record<(typeof linkKeys)[number], string> = {
|
||||||
guide: "📖",
|
|
||||||
discord: "💬",
|
|
||||||
tools: "🛒",
|
|
||||||
github: "📦",
|
github: "📦",
|
||||||
feishu: "📝",
|
|
||||||
destinations: "🗺️",
|
destinations: "🗺️",
|
||||||
|
appDownload: "📱",
|
||||||
|
};
|
||||||
|
const linkHrefs: Record<(typeof linkKeys)[number], { href: string; newTab?: boolean }> = {
|
||||||
|
github: { href: "https://github.com" },
|
||||||
|
destinations: { href: "#" },
|
||||||
|
appDownload: { href: "/app" },
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Community() {
|
export default function Community() {
|
||||||
@@ -67,12 +69,9 @@ export default function Community() {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="text-center">
|
<div id="resources" className="text-center">
|
||||||
<div className="mb-2 text-sm font-semibold text-slate-400 dark:text-slate-500">
|
|
||||||
{t("openSource")}
|
|
||||||
</div>
|
|
||||||
<h2 className="text-3xl font-bold tracking-tight text-slate-900 dark:text-slate-100 sm:text-4xl">
|
<h2 className="text-3xl font-bold tracking-tight text-slate-900 dark:text-slate-100 sm:text-4xl">
|
||||||
{t("contributeTitle")} <span className="gradient-text">{t("contributeHighlight")}</span>
|
<span className="gradient-text">{t("resourcesTitle")}</span>
|
||||||
</h2>
|
</h2>
|
||||||
<p className="mx-auto mt-4 max-w-2xl text-lg text-slate-600 dark:text-slate-400">
|
<p className="mx-auto mt-4 max-w-2xl text-lg text-slate-600 dark:text-slate-400">
|
||||||
{t("contributeSubtitle")}
|
{t("contributeSubtitle")}
|
||||||
@@ -82,37 +81,34 @@ export default function Community() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mt-12 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
<div className="mt-12 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||||
{linkKeys.map((key) => (
|
{linkKeys.map((key) => {
|
||||||
<div
|
const { href, newTab } = linkHrefs[key];
|
||||||
key={key}
|
const content = (
|
||||||
className="card-hover flex items-start gap-4 rounded-xl border border-slate-100 bg-white p-5 shadow-sm dark:border-slate-800 dark:bg-slate-900"
|
<>
|
||||||
>
|
<span className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-slate-50 text-xl dark:bg-slate-800">
|
||||||
<span className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-slate-50 text-xl dark:bg-slate-800">
|
{linkIcons[key]}
|
||||||
{linkIcons[key]}
|
|
||||||
</span>
|
|
||||||
<div>
|
|
||||||
<h4 className="font-bold text-slate-900 dark:text-slate-100">{t(`links.${key}.title`)}</h4>
|
|
||||||
<p className="mt-1 text-sm text-slate-500 dark:text-slate-400">{t(`links.${key}.desc`)}</p>
|
|
||||||
<span className="mt-2 inline-block text-sm font-medium text-sky-600">
|
|
||||||
{t(`links.${key}.label`)}
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
<div>
|
||||||
</div>
|
<h4 className="font-bold text-slate-900 dark:text-slate-100">{t(`links.${key}.title`)}</h4>
|
||||||
))}
|
<p className="mt-1 text-sm text-slate-500 dark:text-slate-400">{t(`links.${key}.desc`)}</p>
|
||||||
</div>
|
<span className="mt-2 inline-block text-sm font-medium text-sky-600">
|
||||||
|
{t(`links.${key}.label`)}
|
||||||
<div className="mt-12 text-center">
|
</span>
|
||||||
<div className="mb-4 text-lg font-bold text-slate-900 dark:text-slate-100">
|
</div>
|
||||||
{t("betterTitle")}
|
</>
|
||||||
</div>
|
);
|
||||||
<p className="mb-6 text-slate-600 dark:text-slate-400">
|
return (
|
||||||
{t("betterDesc")}
|
<Link
|
||||||
<br />
|
key={key}
|
||||||
{t("betterDesc2")}
|
href={href}
|
||||||
</p>
|
target={newTab ? "_blank" : undefined}
|
||||||
<button className="inline-flex items-center gap-2 rounded-full bg-slate-900 px-8 py-3 font-semibold text-white transition-colors hover:bg-slate-800 dark:bg-slate-100 dark:text-slate-900 dark:hover:bg-slate-200">
|
rel={newTab ? "noopener noreferrer" : undefined}
|
||||||
{t("starFork")}
|
className="card-hover flex items-start gap-4 rounded-xl border border-slate-100 bg-white p-5 shadow-sm dark:border-slate-800 dark:bg-slate-900"
|
||||||
</button>
|
>
|
||||||
|
{content}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ const navLinks = [
|
|||||||
{ labelKey: "tools" as const, href: "#tools" },
|
{ labelKey: "tools" as const, href: "#tools" },
|
||||||
{ labelKey: "community" as const, href: "#community" },
|
{ labelKey: "community" as const, href: "#community" },
|
||||||
{ labelKey: "shop" as const, href: "#shop" },
|
{ labelKey: "shop" as const, href: "#shop" },
|
||||||
|
{ labelKey: "resources" as const, href: "#resources" },
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function Header() {
|
export default function Header() {
|
||||||
|
|||||||
@@ -11,7 +11,8 @@
|
|||||||
"roadmap": "Learning Path",
|
"roadmap": "Learning Path",
|
||||||
"tools": "Tools",
|
"tools": "Tools",
|
||||||
"community": "Community",
|
"community": "Community",
|
||||||
"shop": "Shop"
|
"shop": "Shop",
|
||||||
|
"resources": "Resources"
|
||||||
},
|
},
|
||||||
"hero": {
|
"hero": {
|
||||||
"badge": "Open source · 200+ curated resources",
|
"badge": "Open source · 200+ curated resources",
|
||||||
@@ -98,18 +99,13 @@
|
|||||||
"approveJoin": "Join after approval",
|
"approveJoin": "Join after approval",
|
||||||
"applyNow": "Apply now →",
|
"applyNow": "Apply now →",
|
||||||
"applyHint": "Simple form, quick review",
|
"applyHint": "Simple form, quick review",
|
||||||
"openSource": "🤝 Open Source",
|
"resourcesTitle": "Resource Downloads",
|
||||||
"contributeTitle": "Community &",
|
|
||||||
"contributeHighlight": "Contribution",
|
|
||||||
"contributeSubtitle": "Digital Nomad Guide is open source, building the best Chinese digital nomad resource hub.",
|
"contributeSubtitle": "Digital Nomad Guide is open source, building the best Chinese digital nomad resource hub.",
|
||||||
"contributeSubtitle2": "Welcome to add resources, improve content, and share experience.",
|
"contributeSubtitle2": "Welcome to add resources, improve content, and share experience.",
|
||||||
"links": {
|
"links": {
|
||||||
"guide": { "title": "Getting Started", "desc": "Complete digital nomad tutorial", "label": "Start learning ↗" },
|
|
||||||
"discord": { "title": "Discord", "desc": "Chat with global digital nomads", "label": "Join community ↗" },
|
|
||||||
"tools": { "title": "Tool Marketplace", "desc": "Discover, review, and share remote tools", "label": "Browse tools ↗" },
|
|
||||||
"github": { "title": "GitHub", "desc": "Open source—Star and PR welcome", "label": "View repo ↗" },
|
"github": { "title": "GitHub", "desc": "Open source—Star and PR welcome", "label": "View repo ↗" },
|
||||||
"feishu": { "title": "Feishu Docs", "desc": "7-day guide · Chinese tutorials", "label": "View docs ↗" },
|
"destinations": { "title": "Destinations", "desc": "Global digital nomad city info", "label": "Explore cities ↗" },
|
||||||
"destinations": { "title": "Destinations", "desc": "Global digital nomad city info", "label": "Explore cities ↗" }
|
"appDownload": { "title": "App Download", "desc": "Digital Nomad Guide mobile app", "label": "Download now ↗" }
|
||||||
},
|
},
|
||||||
"betterTitle": "🌟 Help Make Digital Nomad Guide Better",
|
"betterTitle": "🌟 Help Make Digital Nomad Guide Better",
|
||||||
"betterDesc": "Found a great resource? Wrote travel notes? Have tool recommendations?",
|
"betterDesc": "Found a great resource? Wrote travel notes? Have tool recommendations?",
|
||||||
@@ -178,6 +174,18 @@
|
|||||||
"resumeUpload": "Click to upload resume",
|
"resumeUpload": "Click to upload resume",
|
||||||
"submit": "Submit Application"
|
"submit": "Submit Application"
|
||||||
},
|
},
|
||||||
|
"appDownload": {
|
||||||
|
"title": "App Download",
|
||||||
|
"subtitle": "Digital Nomad Guide mobile app—resources and community on the go",
|
||||||
|
"features": {
|
||||||
|
"resources": { "title": "Curated Resources", "desc": "200+ articles, offline reading" },
|
||||||
|
"community": { "title": "Community Updates", "desc": "Latest digital nomad community news" },
|
||||||
|
"tools": { "title": "Tool Recommendations", "desc": "Essential remote work tools" }
|
||||||
|
},
|
||||||
|
"download": "Download Now",
|
||||||
|
"comingSoon": "Coming Soon",
|
||||||
|
"comingSoonDesc": "App is under development, stay tuned"
|
||||||
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"title": "Login / Sign up",
|
"title": "Login / Sign up",
|
||||||
"email": "Email",
|
"email": "Email",
|
||||||
|
|||||||
@@ -11,7 +11,8 @@
|
|||||||
"roadmap": "学习路径",
|
"roadmap": "学习路径",
|
||||||
"tools": "工具推荐",
|
"tools": "工具推荐",
|
||||||
"community": "社区",
|
"community": "社区",
|
||||||
"shop": "商店"
|
"shop": "商店",
|
||||||
|
"resources": "资源"
|
||||||
},
|
},
|
||||||
"hero": {
|
"hero": {
|
||||||
"badge": "开源免费 · 收录 200+ 篇实用资源",
|
"badge": "开源免费 · 收录 200+ 篇实用资源",
|
||||||
@@ -98,18 +99,13 @@
|
|||||||
"approveJoin": "审核通过入群",
|
"approveJoin": "审核通过入群",
|
||||||
"applyNow": "立即申请加入 →",
|
"applyNow": "立即申请加入 →",
|
||||||
"applyHint": "简单表单,快速审核",
|
"applyHint": "简单表单,快速审核",
|
||||||
"openSource": "🤝 开源共建",
|
"resourcesTitle": "资源下载",
|
||||||
"contributeTitle": "社区与",
|
|
||||||
"contributeHighlight": "贡献",
|
|
||||||
"contributeSubtitle": "数字游民指南是开源项目,致力于做最好的中文数字游民资源聚合站。",
|
"contributeSubtitle": "数字游民指南是开源项目,致力于做最好的中文数字游民资源聚合站。",
|
||||||
"contributeSubtitle2": "欢迎补充资源、改进内容、分享经验。",
|
"contributeSubtitle2": "欢迎补充资源、改进内容、分享经验。",
|
||||||
"links": {
|
"links": {
|
||||||
"guide": { "title": "入门指南", "desc": "完整的数字游民入门教程", "label": "开始学习 ↗" },
|
|
||||||
"discord": { "title": "Discord 社区", "desc": "与全球数字游民实时交流", "label": "加入社区 ↗" },
|
|
||||||
"tools": { "title": "工具集市", "desc": "发现、评测和分享远程工具", "label": "浏览工具 ↗" },
|
|
||||||
"github": { "title": "GitHub", "desc": "开源项目,欢迎 Star 和 PR", "label": "访问仓库 ↗" },
|
"github": { "title": "GitHub", "desc": "开源项目,欢迎 Star 和 PR", "label": "访问仓库 ↗" },
|
||||||
"feishu": { "title": "飞书知识库", "desc": "7天入门指南 · 中文图文教程", "label": "查看文档 ↗" },
|
"destinations": { "title": "目的地数据库", "desc": "全球数字游民城市信息", "label": "探索城市 ↗" },
|
||||||
"destinations": { "title": "目的地数据库", "desc": "全球数字游民城市信息", "label": "探索城市 ↗" }
|
"appDownload": { "title": "App 下载", "desc": "数字游民指南移动端应用", "label": "立即下载 ↗" }
|
||||||
},
|
},
|
||||||
"betterTitle": "🌟 一起让数字游民指南变得更好",
|
"betterTitle": "🌟 一起让数字游民指南变得更好",
|
||||||
"betterDesc": "发现了好资源?写了旅居心得?有工具推荐?",
|
"betterDesc": "发现了好资源?写了旅居心得?有工具推荐?",
|
||||||
@@ -178,6 +174,18 @@
|
|||||||
"resumeUpload": "点击上传简历",
|
"resumeUpload": "点击上传简历",
|
||||||
"submit": "提交申请"
|
"submit": "提交申请"
|
||||||
},
|
},
|
||||||
|
"appDownload": {
|
||||||
|
"title": "App 下载",
|
||||||
|
"subtitle": "数字游民指南移动端应用,随时随地获取资源与社区动态",
|
||||||
|
"features": {
|
||||||
|
"resources": { "title": "精选资源", "desc": "200+ 篇实用文章,离线阅读" },
|
||||||
|
"community": { "title": "社区动态", "desc": "实时获取数字游民社区最新资讯" },
|
||||||
|
"tools": { "title": "工具推荐", "desc": "远程工作必备工具一览" }
|
||||||
|
},
|
||||||
|
"download": "立即下载",
|
||||||
|
"comingSoon": "即将上线",
|
||||||
|
"comingSoonDesc": "App 正在开发中,敬请期待"
|
||||||
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"title": "登录 / 注册",
|
"title": "登录 / 注册",
|
||||||
"email": "邮箱",
|
"email": "邮箱",
|
||||||
|
|||||||
Reference in New Issue
Block a user