diff --git a/app/components/Community.tsx b/app/components/Community.tsx
index a658180..9933f98 100644
--- a/app/components/Community.tsx
+++ b/app/components/Community.tsx
@@ -2,16 +2,26 @@
import { Link, useTranslation } from "@/i18n/navigation";
import ShopCard from "./ShopCard";
+import { TOPIC_IDS } from "@/config";
+
+const linkKeys = ["github", "destinations", "indieDev", "aiAgent", "cloudPhone", "unmannedLive", "appDownload"] as const;
-const linkKeys = ["github", "destinations", "appDownload"] as const;
const linkIcons: Record<(typeof linkKeys)[number], string> = {
github: "📦",
destinations: "🗺️",
+ indieDev: "🛠️",
+ aiAgent: "🤖",
+ cloudPhone: "☁️",
+ unmannedLive: "📺",
appDownload: "📱",
};
const linkHrefs: Record<(typeof linkKeys)[number], { href: string; newTab?: boolean }> = {
github: { href: "https://github.com" },
- destinations: { href: "#" },
+ 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" },
appDownload: { href: "/app" },
};
@@ -83,13 +93,21 @@ export default function Community() {
{linkKeys.map((key) => {
const { href, newTab } = linkHrefs[key];
+ const isTopic = (TOPIC_IDS as readonly string[]).includes(key);
const content = (
<>
{linkIcons[key]}
-
-
{t(`links.${key}.title`)}
+
+
+
{t(`links.${key}.title`)}
+ {isTopic && (
+
+ {t("topicTag")}
+
+ )}
+
{t(`links.${key}.desc`)}
{t(`links.${key}.label`)}
diff --git a/app/components/Footer.tsx b/app/components/Footer.tsx
index e75fb42..5590997 100644
--- a/app/components/Footer.tsx
+++ b/app/components/Footer.tsx
@@ -8,7 +8,7 @@ const footerSections = [
links: [
{ labelKey: "roadmap" as const, href: "#roadmap" },
{ labelKey: "tools" as const, href: "#tools" },
- { labelKey: "destinations" as const, href: "#" },
+ { labelKey: "destinations" as const, href: "https://meetup.hackrobot.cn/", openInNewTab: true },
],
},
{
@@ -78,6 +78,8 @@ export default function Footer() {
) : (
{t(`links.${link.labelKey}`)}
diff --git a/app/globals.css b/app/globals.css
index 05ec318..95a0ca6 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -5,8 +5,8 @@
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
- --font-sans: var(--font-geist-sans);
- --font-mono: var(--font-geist-mono);
+ --font-sans: "Geist Variable", system-ui, sans-serif;
+ --font-mono: "Geist Mono Variable", ui-monospace, monospace;
--color-primary: #0ea5e9;
--color-primary-dark: #0284c7;
--color-accent: #f59e0b;
diff --git a/app/layout.tsx b/app/layout.tsx
index 4f539ae..29bafef 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -1,19 +1,10 @@
import type { Metadata, Viewport } from "next";
-import { Geist, Geist_Mono } from "next/font/google";
+import "@fontsource-variable/geist";
+import "@fontsource-variable/geist-mono";
import "./globals.css";
import { ThemeProvider } from "./context/ThemeContext";
import { getThemeConfig } from "@/config";
-const geistSans = Geist({
- variable: "--font-geist-sans",
- subsets: ["latin"],
-});
-
-const geistMono = Geist_Mono({
- variable: "--font-geist-mono",
- subsets: ["latin"],
-});
-
export const viewport: Viewport = {
width: "device-width",
initialScale: 1,
@@ -57,7 +48,7 @@ export default function RootLayout({
return (
{children}
diff --git a/config/index.ts b/config/index.ts
index 045d8ef..60a72dd 100644
--- a/config/index.ts
+++ b/config/index.ts
@@ -2,9 +2,11 @@ export {
CURRENT_THEME,
THEME_IDS,
THEME_CONFIGS,
+ TOPIC_IDS,
getThemeConfig,
type ThemeId,
type ThemeConfig,
+ type TopicId,
} from "./site.config";
export {
diff --git a/config/site.config.ts b/config/site.config.ts
index cfef1b4..2c83d28 100644
--- a/config/site.config.ts
+++ b/config/site.config.ts
@@ -3,6 +3,11 @@
* 克隆新主题:复制 themes/digital-nomad 为 themes/your-theme,修改配置和内容
*/
+/** 专题 ID:子域名部署 + 项目复制架构(资源导航中带「专题」标记) */
+export const TOPIC_IDS = ["indieDev", "aiAgent", "cloudPhone", "unmannedLive"] as const;
+
+export type TopicId = (typeof TOPIC_IDS)[number];
+
export const THEME_IDS = [
"digital-nomad",
"solo-company",
diff --git a/content/themes/digital-nomad/messages/en.json b/content/themes/digital-nomad/messages/en.json
index d5cf070..0b0f8ac 100644
--- a/content/themes/digital-nomad/messages/en.json
+++ b/content/themes/digital-nomad/messages/en.json
@@ -99,12 +99,17 @@
"approveJoin": "Join after approval",
"applyNow": "Apply now →",
"applyHint": "Simple form, quick review",
- "resourcesTitle": "Resource Downloads",
+ "resourcesTitle": "Resource Navigation",
+ "topicTag": "Topic",
"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.",
"links": {
"github": { "title": "GitHub", "desc": "Open source—Star and PR welcome", "label": "View repo ↗" },
"destinations": { "title": "Destinations", "desc": "Global digital nomad city info", "label": "Explore cities ↗" },
+ "indieDev": { "title": "Indie Dev", "desc": "From idea to product, indie developer guide", "label": "View guide ↗" },
+ "aiAgent": { "title": "AI Agent", "desc": "AIGC & agents, Vibe Coding for creators", "label": "Learn more ↗" },
+ "cloudPhone": { "title": "Cloud Phone", "desc": "Low-cost self-hosted cloud phone for TikTok/YouTube", "label": "Setup guide ↗" },
+ "unmannedLive": { "title": "Unmanned Live", "desc": "TikTok/YouTube 24/7 automated live streaming", "label": "View tutorial ↗" },
"appDownload": { "title": "App Download", "desc": "Digital Nomad Guide mobile app", "label": "Download now ↗" }
},
"betterTitle": "🌟 Help Make Digital Nomad Guide Better",
diff --git a/content/themes/digital-nomad/messages/zh.json b/content/themes/digital-nomad/messages/zh.json
index 7639fb4..23f1011 100644
--- a/content/themes/digital-nomad/messages/zh.json
+++ b/content/themes/digital-nomad/messages/zh.json
@@ -99,12 +99,17 @@
"approveJoin": "审核通过入群",
"applyNow": "立即申请加入 →",
"applyHint": "简单表单,快速审核",
- "resourcesTitle": "资源下载",
+ "resourcesTitle": "资源导航",
+ "topicTag": "专题",
"contributeSubtitle": "数字游民指南是开源项目,致力于做最好的中文数字游民资源聚合站。",
"contributeSubtitle2": "欢迎补充资源、改进内容、分享经验。",
"links": {
"github": { "title": "GitHub", "desc": "开源项目,欢迎 Star 和 PR", "label": "访问仓库 ↗" },
"destinations": { "title": "目的地数据库", "desc": "全球数字游民城市信息", "label": "探索城市 ↗" },
+ "indieDev": { "title": "独立开发", "desc": "从想法到产品,独立开发者全流程指南", "label": "查看指南 ↗" },
+ "aiAgent": { "title": "AI Agent", "desc": "AIGC 与智能体,Vibe Coding 跨界创造", "label": "了解更多 ↗" },
+ "cloudPhone": { "title": "云手机", "desc": "低成本自建云手机,TikTok/YouTube 运营", "label": "搭建指南 ↗" },
+ "unmannedLive": { "title": "无人直播", "desc": "TikTok/YouTube 无人直播,24 小时自动化", "label": "查看教程 ↗" },
"appDownload": { "title": "App 下载", "desc": "数字游民指南移动端应用", "label": "立即下载 ↗" }
},
"betterTitle": "🌟 一起让数字游民指南变得更好",
diff --git a/package.json b/package.json
index 29d1931..a6365ce 100644
--- a/package.json
+++ b/package.json
@@ -9,7 +9,11 @@
"lint": "eslint"
},
"dependencies": {
+ "@fontsource-variable/geist": "^5.2.8",
+ "@fontsource-variable/geist-mono": "^5.2.7",
"@aws-sdk/client-s3": "^3.1004.0",
+ "@fontsource-variable/geist": "^5.2.8",
+ "@fontsource-variable/geist-mono": "^5.2.7",
"github-markdown-css": "^5.6.1",
"highlight.js": "^11.11.1",
"marked": "^14.1.2",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c7a5421..31003ca 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -11,6 +11,12 @@ importers:
'@aws-sdk/client-s3':
specifier: ^3.1004.0
version: 3.1004.0
+ '@fontsource-variable/geist':
+ specifier: ^5.2.8
+ version: 5.2.8
+ '@fontsource-variable/geist-mono':
+ specifier: ^5.2.7
+ version: 5.2.7
github-markdown-css:
specifier: ^5.6.1
version: 5.9.0
@@ -349,6 +355,12 @@ packages:
resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ '@fontsource-variable/geist-mono@5.2.7':
+ resolution: {integrity: sha512-ZKlZ5sjtalb2TwXKs400mAGDlt/+2ENLNySPx0wTz3bP3mWARCsUW+rpxzZc7e05d2qGch70pItt3K4qttbIYA==}
+
+ '@fontsource-variable/geist@5.2.8':
+ resolution: {integrity: sha512-cJ6m9e+8MQ5dCYJsLylfZrgBh6KkG4bOLckB35Tr9J/EqdkEM6QllH5PxqP1dhTvFup+HtMRPuz9xOjxXJggxw==}
+
'@humanfs/core@0.19.1':
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
engines: {node: '>=18.18.0'}
@@ -3367,6 +3379,10 @@ snapshots:
'@eslint/core': 0.17.0
levn: 0.4.1
+ '@fontsource-variable/geist-mono@5.2.7': {}
+
+ '@fontsource-variable/geist@5.2.8': {}
+
'@humanfs/core@0.19.1': {}
'@humanfs/node@0.16.7':