's'
This commit is contained in:
@@ -1,84 +1,58 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { Link, useTranslation } from "@/i18n/navigation";
|
||||
import ShopCard from "./ShopCard";
|
||||
import { TOPIC_IDS } from "@/config";
|
||||
import type { ResourceData } from "@/app/lib/theme-data";
|
||||
import ResourceNavigation from "./ResourceNavigation";
|
||||
|
||||
const linkKeys = ["github", "destinations", "indieDev", "aiAgent", "cloudPhone", "unmannedLive", "appDownload"] as const;
|
||||
const mainModuleKeys = ["destinations", "vipEntry", "appDownload"] as const;
|
||||
const topicKeys = ["indieDev", "aiAgent", "cloudPhone", "unmannedLive"] as const;
|
||||
|
||||
const linkIcons: Record<(typeof linkKeys)[number], string> = {
|
||||
github: "📦",
|
||||
const linkIcons: Record<string, string> = {
|
||||
destinations: "🗺️",
|
||||
vipEntry: "👑",
|
||||
appDownload: "📱",
|
||||
indieDev: "🛠️",
|
||||
aiAgent: "🤖",
|
||||
cloudPhone: "☁️",
|
||||
unmannedLive: "📺",
|
||||
appDownload: "📱",
|
||||
};
|
||||
const linkHrefs: Record<(typeof linkKeys)[number], { href: string; newTab?: boolean }> = {
|
||||
github: { href: "https://github.com" },
|
||||
const linkHrefs: Record<string, { href: string; newTab?: boolean }> = {
|
||||
destinations: { href: "https://meetup.hackrobot.cn/", newTab: true },
|
||||
indieDev: { href: "/ebook" },
|
||||
aiAgent: { href: "/ebook" },
|
||||
cloudPhone: { href: "https://android.hackrobot.cn", newTab: true },
|
||||
unmannedLive: { href: "/ebook" },
|
||||
vipEntry: { href: "https://vip.hackrobot.cn/", newTab: true },
|
||||
appDownload: { href: "/app" },
|
||||
};
|
||||
|
||||
export default function Community() {
|
||||
type CommunityProps = {
|
||||
resourceData?: ResourceData;
|
||||
};
|
||||
|
||||
export default function Community({ resourceData }: CommunityProps) {
|
||||
const { t } = useTranslation("community");
|
||||
const [toast, setToast] = useState(false);
|
||||
|
||||
const showUpdating = () => {
|
||||
setToast(true);
|
||||
setTimeout(() => setToast(false), 2000);
|
||||
};
|
||||
|
||||
const renderCardContent = (key: string) => (
|
||||
<>
|
||||
<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]}
|
||||
</span>
|
||||
<div className="min-w-0 flex-1">
|
||||
<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>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<section id="community" className="py-20 sm:py-28 dark:bg-slate-950">
|
||||
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||
{/* 电商独立站卡片 */}
|
||||
<div id="shop">
|
||||
<ShopCard />
|
||||
</div>
|
||||
|
||||
{/* 数字游民社区 - 优化布局 */}
|
||||
<div className="mb-20">
|
||||
<Link
|
||||
href="/join"
|
||||
className="group block overflow-hidden rounded-2xl border border-sky-200/80 bg-gradient-to-br from-sky-50 via-white to-cyan-50/60 p-8 shadow-sm transition-all duration-300 hover:border-sky-300 hover:shadow-xl hover:shadow-sky-100/50 dark:border-sky-800/80 dark:from-sky-900/30 dark:via-slate-900 dark:to-cyan-900/20 dark:hover:border-sky-700 dark:hover:shadow-sky-900/30 sm:p-10"
|
||||
>
|
||||
<div className="flex flex-col gap-6 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div className="flex-1">
|
||||
<div className="mb-3 inline-flex items-center gap-2 rounded-full bg-sky-100 px-4 py-1.5 text-sm font-semibold text-sky-700 dark:bg-sky-900/50 dark:text-sky-300">
|
||||
<span className="text-lg">👥</span>
|
||||
{t("nomadCommunity")}
|
||||
</div>
|
||||
<h3 className="mb-3 text-2xl font-bold tracking-tight text-slate-900 dark:text-slate-100 sm:text-3xl">
|
||||
{t("joinTitle")}
|
||||
</h3>
|
||||
<p className="mb-4 max-w-xl text-base leading-relaxed text-slate-600 dark:text-slate-400">
|
||||
{t("joinDesc")}
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-3">
|
||||
<span className="rounded-lg bg-white/90 px-3 py-1.5 text-sm font-medium text-slate-600 shadow-sm dark:bg-slate-800/90 dark:text-slate-300">
|
||||
{t("applyForm")}
|
||||
</span>
|
||||
<span className="rounded-lg bg-white/90 px-3 py-1.5 text-sm font-medium text-slate-600 shadow-sm dark:bg-slate-800/90 dark:text-slate-300">
|
||||
{t("approveJoin")}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex shrink-0 items-center gap-4 rounded-2xl bg-white/90 p-6 shadow-md backdrop-blur-sm transition-transform dark:bg-slate-800/90 group-hover:scale-[1.02] sm:p-8">
|
||||
<div className="flex h-16 w-16 items-center justify-center rounded-2xl bg-gradient-to-br from-sky-400 to-cyan-500 text-3xl shadow-lg shadow-sky-200/50">
|
||||
📝
|
||||
</div>
|
||||
<div className="text-left">
|
||||
<div className="font-bold text-slate-800 dark:text-slate-200">
|
||||
{t("applyNow")}
|
||||
</div>
|
||||
<div className="mt-1 text-sm text-slate-500 dark:text-slate-400">
|
||||
{t("applyHint")}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div id="resources" className="text-center">
|
||||
<h2 className="text-3xl font-bold tracking-tight text-slate-900 dark:text-slate-100 sm:text-4xl">
|
||||
<span className="gradient-text">{t("resourcesTitle")}</span>
|
||||
@@ -90,44 +64,64 @@ export default function Community() {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="mt-12 grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{linkKeys.map((key) => {
|
||||
{/* 图书 / 商业数码 / 网盘 */}
|
||||
{resourceData && <ResourceNavigation data={resourceData} />}
|
||||
|
||||
{/* 目的地数据库 + 私域VIP入口 + App 下载 - 主模块 */}
|
||||
<div className="mt-12 grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{mainModuleKeys.map((key) => {
|
||||
const { href, newTab } = linkHrefs[key];
|
||||
const isTopic = (TOPIC_IDS as readonly string[]).includes(key);
|
||||
const content = (
|
||||
<>
|
||||
<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]}
|
||||
</span>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<h4 className="font-bold text-slate-900 dark:text-slate-100">{t(`links.${key}.title`)}</h4>
|
||||
{isTopic && (
|
||||
<span className="rounded-md bg-amber-100 px-1.5 py-0.5 text-xs font-medium text-amber-700 dark:bg-amber-900/50 dark:text-amber-400">
|
||||
{t("topicTag")}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<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>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
return (
|
||||
<Link
|
||||
key={key}
|
||||
href={href}
|
||||
target={newTab ? "_blank" : undefined}
|
||||
rel={newTab ? "noopener noreferrer" : undefined}
|
||||
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"
|
||||
className="card-hover flex items-start gap-5 rounded-2xl border-2 border-slate-200 bg-white p-6 shadow-md transition-all hover:border-sky-300 hover:shadow-lg dark:border-slate-700 dark:bg-slate-900 dark:hover:border-sky-600"
|
||||
>
|
||||
{content}
|
||||
{renderCardContent(key)}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* 4 个专题 - 小卡片,暂不可点击 */}
|
||||
<div className="mt-8">
|
||||
<h3 className="mb-4 text-center text-sm font-semibold uppercase tracking-wider text-slate-500 dark:text-slate-400">
|
||||
{t("topicTag")}
|
||||
</h3>
|
||||
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
||||
{topicKeys.map((key) => (
|
||||
<button
|
||||
key={key}
|
||||
type="button"
|
||||
onClick={showUpdating}
|
||||
className="flex cursor-not-allowed items-start gap-4 rounded-xl border border-slate-200 bg-slate-50/80 p-4 opacity-90 transition-opacity hover:opacity-100 dark:border-slate-700 dark:bg-slate-800/60"
|
||||
>
|
||||
<span className="flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-slate-200 text-lg dark:bg-slate-700">
|
||||
{linkIcons[key]}
|
||||
</span>
|
||||
<div className="min-w-0 flex-1 text-left">
|
||||
<h4 className="font-bold text-slate-700 dark:text-slate-300">{t(`links.${key}.title`)}</h4>
|
||||
<p className="mt-0.5 text-xs text-slate-500 dark:text-slate-400">{t(`links.${key}.desc`)}</p>
|
||||
<span className="mt-1.5 inline-block text-xs font-medium text-amber-600 dark:text-amber-400">
|
||||
{t("updating")}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 更新中 Toast */}
|
||||
{toast && (
|
||||
<div
|
||||
className="fixed bottom-8 left-1/2 z-50 -translate-x-1/2 rounded-lg bg-slate-800 px-6 py-3 text-sm font-medium text-white shadow-lg dark:bg-slate-700"
|
||||
role="alert"
|
||||
>
|
||||
{t("updating")}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user