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':