diff --git a/README.md b/README.md index c6de9dd..8bf0906 100644 --- a/README.md +++ b/README.md @@ -1,50 +1,64 @@ # nomadro · 数字游民旅居平台 -全栈数字游民旅居指南,品牌 **nomadro** — 用一行代码环游世界 🌏 +品牌 **nomadro** — 用一行代码环游世界 🌏 **线上:** [https://nomadweb.nomadro.com](https://nomadweb.nomadro.com) -核心产品闭环:**发现目的地 → 智能匹配 / 城市对比 → 旅居计划中心 → 登录云端同步** +## 产品路径(环环相扣) + +功能很多,但**不一次全部展示**。导航与首页按三条环串联,每页只露出「接下来」: + +| 环 | 做什么 | 主要入口 | +|----|--------|----------| +| **探索 Explore** | 发现去哪 | 目的地、地图、下一站、签证;(离首页后再出现计划 / 对比) | +| **连接 Connect** | 遇见同行 | 活动 → 社区 → 匹配 → 私信 | +| **成长 Grow** | 路上做事 | 学院 → 赏金 → 工具箱(按需)→ 电子书 | + +``` +发现城市 ──► 写入计划 / 同城活动 ──► 社区 / 匹配 ──► 学院 / 赏金 +``` + +- 顶栏:**探索 / 连接 / 成长** 三组下拉,**EN · 主题 · 通知** 固定在右上 +- `Ctrl+K` 空态只给三环捷径;次要页面要搜索才出现 +- 工具箱默认精选 +「展开全部」,不再当全站站点地图 ## 技术栈 | 层级 | 技术 | 说明 | |------|------|------| -| 前端 | Next.js 16 + React 19 | App Router、ISR、Turbopack、standalone | -| 后端 | FastAPI | REST API、业务逻辑、账号计划同步 | -| 数据 | PocketBase + Mock 降级 | 内容库;用户收藏/计划可落盘 | -| 部署 | Caddy + systemd(原生优先) | 生产非 Docker 跑 Web/API | +| 前端 | Next.js 16 + React 19 | **仅 UI**;App Router、standalone | +| 后端 | FastAPI | **全部业务逻辑**(无 Next.js 业务 API Route) | +| 数据 | PocketBase | 主存储;本地可 Mock 降级 | +| 对象存储 | S3 兼容(生产 SeaweedFS) | 媒体上传 | +| 部署 | Caddy + systemd | 原生进程;勿与同机 dylive 业务互相干扰 | ## 项目结构 ``` nomadweb/ -├── frontend/ # Next.js -│ ├── src/app/ # 路由:/ /plan /compare /tools /profile … -│ ├── src/components/ # UI 与工具组件 -│ └── src/lib/ # API、auth、trip/plan 存储与同步 +├── frontend/ # Next.js(页面与组件) +│ ├── src/app/ # 路由 +│ ├── src/components/ # UI(含 RingNext 下一步条) +│ └── src/lib/ # api / auth / i18n / rings ├── backend/ # FastAPI -│ ├── app/routers/ # API 路由 -│ ├── app/services/ # PocketBase、Auth(含计划同步) -│ └── app/data/ # Mock 降级 + user_store(运行时) -├── deploy/ # Caddy、systemd 单元 -├── scripts/ # 本地开发、生产部署脚本 -├── pocketbase/ # PocketBase 数据目录 -└── docker-compose*.yml # 本地 / 备选生产 Compose +│ ├── app/routers/ # REST +│ ├── app/services/ # PocketBase、S3、城市深度等 +│ └── app/data/ # Mock 降级(开发) +├── deploy/ # Caddy、systemd、env 模板 +├── scripts/ # 本地开发与生产更新 +└── pocketbase/ # PB 数据目录(本地可选) ``` ## 快速开始 ### 1. PocketBase(可选) -不启动则 API 自动使用 `backend/app/data/mock_data.py`。 +不启动则 API 使用 Mock。 ```bash docker run -d -p 8090:8090 -v ./pocketbase/pb_data:/pb_data ghcr.io/muchobien/pocketbase:latest ``` -管理后台:http://localhost:8090/_/ - ### 2. FastAPI ```bash @@ -67,190 +81,109 @@ npm run dev 访问:http://localhost:3000 -### 其他方式 - ```powershell -.\scripts\dev.ps1 # Windows 一键 -docker compose up -d # Compose 全栈 +.\scripts\dev.ps1 # Windows 一键 ``` -## 核心产品 +## 核心功能一览 -| 能力 | 路径 / 入口 | 说明 | -|------|-------------|------| -| 🗺️ 地图 & 目的地 | `/#map` `/#destinations` | 筛选、收藏、勾选对比(最多 4 城) | -| 🎯 智能匹配 | FAB / `M` | 4 步问卷;偏好本地保存;Top 结果可写入计划 / 对比 | -| ⚖️ 城市对比台 | `/compare` | 可分享 `?cities=`;指标并排;写入计划 | -| 🗓️ 旅居计划中心 | `/plan` | 多城时间轴、出发月、预算、站内备注、签证方案与超期提醒、就绪清单、MD / ICS 导出、分享链接 | -| ☁️ 账号同步 | `/login?next=/plan` | 登录后合并本机与云端计划;收藏同步;服务重启落盘保留 | -| 👤 个人中心 | `/profile` | 计划仪表盘、就绪度、收藏写入计划、成就 | +按环归类(深度页会互相引导,避免平铺): + +### 探索 +| 能力 | 路径 | +|------|------| +| 地图 / 目的地 | `/#map` `/#destinations` `/destinations/[slug]` | +| 智能匹配 | 首页 CTA / `M` | +| 下一站决策 | `/next-stop` | +| 城市对比 | `/compare` | +| 旅居计划 | `/plan`(时间轴、预算、签证提醒、清单、ICS) | +| 签证指南 | `/#visa` | + +### 连接 +| 能力 | 路径 | +|------|------| +| 活动 RSVP / 直播间 | `/meetups` `/meetups/[id]/live` | +| 社区讨论 | `/community` | +| 游民匹配 | `/dating` | +| 私信 | `/chat` | +| 通知 | `/notifications` | + +### 成长 +| 能力 | 路径 | +|------|------| +| 游民学院 | `/digital` | +| 赏金任务 | `/gigs` | +| 工具箱 | `/tools`(实用小工具,非功能总览) | +| 电子书 | `/book` | +| 会员 | `/join` `/pricing` | 演示账号:`demo@nomadro.com` / `demo123` -## 首页与工具箱 - -首页仍聚合大量旅居工具(按视口懒加载),完整列表见 `/tools` 与 `/changelog`。常见能力包括: - -- 费用计算器、多币种、启动金 / 跑道、落地首月成本 -- 时区看板、会议重叠、日照办公窗、时差估算 -- 签证指南 + 停留倒计时、保险、税居天数 -- 联合办公、住宿、SIM、电源、紧急联系、防坑与取现 -- 行李清单、到站清单、专注时钟、博客与 FAQ 等 - -导航、Hero、快捷条、底栏与新手引导优先导向 **计划 / 对比**,小工具集中在工具箱。 - -## 体验与性能 - -- 首屏:地图 + 目的地;中屏及以下 `WhenVisible` + 动态拆包 -- Outfit 自托管;中文系统字体;缩短 Loader;粒子延后、无连线 -- 深浅色主题、`Ctrl+K` 全局搜索、Toast、Cookie 提示 -- 响应式布局;`.section` 使用 `content-visibility` - -## 页面路由 - -| 路径 | 说明 | -|------|------| -| `/` | 首页 | -| `/plan` | 旅居计划中心 | -| `/compare` | 城市对比台 | -| `/tools` | 工具箱 | -| `/destinations/[slug]` | 目的地详情(画像、停留月数、加入计划) | -| `/login` | 登录 / 注册(`?next=` 回流,默认 `/plan`) | -| `/profile` | 用户中心 | -| `/blog/[slug]` | 博客 | -| `/about` `/privacy` `/changelog` | 关于 / 隐私 / 更新日志 | -| `/sitemap.xml` | 含 `/plan`、`/compare` 等 | - -## 后端 API(节选) - -| 端点 | 方法 | 说明 | -|------|------|------| -| `/api/v1/destinations` | GET | 列表(region / search / sort) | -| `/api/v1/destinations/{slug}` | GET | 详情 | -| `/api/v1/destinations/compare` | POST | 按 slug 取城 | -| `/api/v1/calculator` | POST | 费用估算 | -| `/api/v1/search` | GET | 全局搜索 | -| `/api/v1/visas` 等 | GET | 签证 / FAQ / 博客 / 图表 | -| `/api/v1/auth/register` | POST | 注册 | -| `/api/v1/auth/login` | POST | 登录 | -| `/api/v1/auth/demo` | GET | 演示登录 | -| `/api/v1/auth/favorites` | GET/POST | 收藏 | -| `/api/v1/auth/plan` | GET/PUT | **旅居计划云端读写** | -| `/api/v1/auth/profile/stats` | GET | 个人统计 | -| `/api/v1/subscribe` | POST | 邮件订阅 | -| `/api/v1/health` | GET | 健康检查 | - -PocketBase 不可用时内容接口降级 Mock。用户收藏与计划写入 `backend/app/data/user_store.json`(运行时生成,勿提交密钥与生产数据)。 - ## 环境变量 -**Backend `backend/.env`** +**Backend** ```env POCKETBASE_URL=http://127.0.0.1:8090 -POCKETBASE_ADMIN_EMAIL=admin@nomadro.com -POCKETBASE_ADMIN_PASSWORD=admin123456 +POCKETBASE_ADMIN_EMAIL=... +POCKETBASE_ADMIN_PASSWORD=... CORS_ORIGINS=http://localhost:3000 +# S3(生产见服务器 deploy/nomadro-api.env) ``` -**Frontend `frontend/.env.local`** +**Frontend** ```env NEXT_PUBLIC_API_URL=http://localhost:8000/api/v1 NEXT_PUBLIC_SITE_URL=http://localhost:3000 ``` -生产前端构建时: +生产构建: ```env NEXT_PUBLIC_API_URL=https://nomadweb.nomadro.com/api/v1 NEXT_PUBLIC_SITE_URL=https://nomadweb.nomadro.com ``` -## Git 工作流 +## Git 与部署 -仓库:[gitea.dsx2020.com/eric/nomadweb](https://gitea.dsx2020.com/eric/nomadweb) · 主开发分支 **`dev1`** +仓库:[gitea.dsx2020.com/eric/nomadweb](https://gitea.dsx2020.com/eric/nomadweb) · 分支 **`dev1`** ```bash -# 日常开发 git checkout dev1 git pull origin dev1 # … 改代码 … -git add -A -git status # 确认未包含 .env、密钥、运行时 json -git commit -m "feat: 简述改动" git push origin dev1 - -# 部署到生产(服务器 git pull + 增量构建) -python scripts/deploy_update.py +python scripts/deploy_update.py # 服务器 pull + 增量构建重启 ``` -| 步骤 | 说明 | -|------|------| -| `dev1` | 功能开发、联调、上线均在此分支 | -| `main` | 稳定快照,按需从 `dev1` 合并 | -| 密钥 | `deploy/nomadro-api.env` 仅放服务器,模板见 `deploy/nomadro-api.env.example` | -| 运行时数据 | `user_store.json` / `social_store.json` / `community_store.json` 不提交 | - -**不要用 SFTP 全量同步当主流程** — `deploy_direct_sync.py` 仅作 Gitea 不可用时的应急备份(慢且易漏文件)。 - -## 部署 - -### 生产(已上线) - -| 项目 | 地址 | -|------|------| +| 生产进程 | 地址 | +|----------|------| | 网站 | https://nomadweb.nomadro.com | -| API 健康检查 | https://nomadweb.nomadro.com/api/v1/health | -| API 文档 | https://nomadweb.nomadro.com/docs | -| 仓库 | https://gitea.dsx2020.com/eric/nomadweb | - -**架构(原生 systemd,Caddy 反代):** - -| 进程 | 地址 | -|------|------| -| Caddy | HTTPS → 见 `deploy/caddy/nomadweb.caddy` | -| `nomadro-web` | `127.0.0.1:3055`(Next standalone) | -| `nomadro-api` | `127.0.0.1:8055`(uvicorn) | +| `nomadro-web` | `127.0.0.1:3055` | +| `nomadro-api` | `127.0.0.1:8055` | | PocketBase | `127.0.0.1:8090` | +| S3 | `s3.nomadro.com` → SeaweedFS | -单元:`deploy/systemd/nomadro-web.service`、`nomadro-api.service`。 +**注意:** 同机还跑有 [dylive.nomadro.com](https://dylive.nomadro.com/)(`/opt/douyinWEB`)。更新 nomadweb 时**不要**改动 / 限流 / 杀掉直播相关进程。 -**推荐更新(Git):** - -```bash -git push origin dev1 -python scripts/deploy_update.py -``` - -服务器执行 `git pull` → 按变更只重建前端或后端 → `systemctl restart`;比 SFTP 全量同步快且可回滚。 - -**应急(Gitea 不可用 / 未 push 的本地提交):** - -```bash -python scripts/deploy_direct_sync.py -``` - -SFTP 同步变更文件 → 重建前端(并重启 API)→ 健康检查。 - -**备选 Docker Compose:** 见 `docker-compose.prod.yml`(生产默认以原生为准)。 +密钥仅放服务器 `deploy/nomadro-api.env`(模板见 `*.env.example`),勿提交。 ## 快捷键 | 按键 | 功能 | |------|------| -| `Ctrl+K` | 全局搜索 | +| `Ctrl+K` | 全局搜索(三环捷径) | | `M` | 智能匹配 | -| `P` | 打开旅居计划中心 | -| `T` | 打开工具箱 | -| `G` | 命运转盘(首页) | -| `?` | 快捷键帮助 | +| `P` | 旅居计划 | +| `T` | 工具箱 | +| `?` | 帮助 | | `Esc` | 关闭弹窗 | -## 相关文档 +## 相关 -- 产品迭代:[`/changelog`](https://nomadweb.nomadro.com/changelog) -- 本地变更记录:`frontend/src/app/changelog/page.tsx` +- 迭代说明:[/changelog](https://nomadweb.nomadro.com/changelog) +- 前端脚手架说明:`frontend/README.md`(以本文件为准) ## License diff --git a/frontend/README.md b/frontend/README.md index e215bc4..0af1100 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -1,36 +1,20 @@ -This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). +# frontend · nomadro -## Getting Started +Next.js App Router UI for [nomadro](https://nomadweb.nomadro.com). -First, run the development server: +**业务逻辑全部在 FastAPI**(`../backend`)。本目录只负责页面与交互。 + +完整架构、三环产品路径、环境变量与部署说明见仓库根目录 **[README.md](../README.md)**。 ```bash +cp .env.local.example .env.local +npm install --legacy-peer-deps npm run dev -# or -yarn dev -# or -pnpm dev -# or -bun dev ``` -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. +生产构建需设置: -You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. - -This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. - -## Learn More - -To learn more about Next.js, take a look at the following resources: - -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. - -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! - -## Deploy on Vercel - -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. - -Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. +```env +NEXT_PUBLIC_API_URL=https://nomadweb.nomadro.com/api/v1 +NEXT_PUBLIC_SITE_URL=https://nomadweb.nomadro.com +``` diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css index 48124cc..3939ecd 100644 --- a/frontend/src/app/globals.css +++ b/frontend/src/app/globals.css @@ -141,7 +141,42 @@ img { max-width: 100%; display: block; } height: 100%; display: flex; align-items: center; - justify-content: space-between; + gap: 16px; +} + +.nav-container > .logo { + flex-shrink: 0; +} + +.nav-container > .nav-links { + flex: 1; + justify-content: center; + min-width: 0; +} + +.nav-utils { + display: flex; + align-items: center; + justify-content: flex-end; + gap: 8px; + margin-left: auto; + flex-shrink: 0; +} + +.nav-utils .nav-lang-btn, +.nav-utils .nav-cta, +.nav-utils .nav-notify { + flex-shrink: 0; +} + +.nav-utils .nav-cta { + width: 36px; + height: 36px; + font-size: 1.05rem; +} + +.nav-notify-guest { + opacity: 0.85; } .logo { @@ -9477,17 +9512,20 @@ img { max-width: 100%; display: block; } padding-top: 12px; border-top: var(--border-glass); } -.nav-lang-desktop { margin-left: 4px; } -.nav-login-desktop { margin-left: 4px; } @media (max-width: 768px) { - .nav-lang-desktop, - .nav-login-desktop { display: none; } + .nav-login-desktop, + .nav-user-desktop { display: none; } .nav-mobile-extras { display: flex; } .nav-mobile-extras .nav-login-btn { text-align: center; display: block; } + .nav-utils { gap: 6px; } + .nav-utils .nav-lang-btn { + min-width: 40px; + padding: 6px 8px; + } .plan-page, .compare-page, @@ -10743,7 +10781,7 @@ img { max-width: 100%; display: block; } .live-chat { border-left: none; border-top: var(--border-glass); min-height: 320px; } } -/* —— Feature rings / progressive IA —— */ +/* -- Feature rings / progressive IA -- */ .nav-group { position: relative; } diff --git a/frontend/src/components/Navbar.tsx b/frontend/src/components/Navbar.tsx index bdabb66..7f319ab 100644 --- a/frontend/src/components/Navbar.tsx +++ b/frontend/src/components/Navbar.tsx @@ -197,9 +197,6 @@ export default function Navbar() { ))}
- {!user && ( )} + {user && ( + + {t.footer.profile} + + )}
- - - {user ? ( - <> + {/* Right chrome: language / theme / notifications — always top-right */} +
+ + + {user ? ( 🔔{unread > 0 && {unread}} - + ) : ( + + 🔔 + + )} + {user ? ( + {user.avatar} {user.name} - - ) : ( - - {t.nav.login} - - )} - + ) : ( + + {t.nav.login} + + )} + +
);