Files
lab/ts/web/nextjs/polaris/Polaris 项目说明文档.md
T
labmem 7eaa9e6f80 docs(ts): 重组 Polaris 设计文档体系并迁移至 nextjs 目录
- 拆分为项目说明/首页设计/分类页设计三份文档,职责分离
- 新增项目说明文档:14 条决策记录、技术选型(Next.js 静态导出)、
  数据结构、Go API 草案、通用语法表结构、五阶段规划
- 融入决策:JSON 数据载体、Ctrl+K 仅首页生效、统一图标方案
  (si:/local:/url: 前缀 + 四级 fallback)、搜索按模式严格分离、
  首页补足 8 个常用链接(跨分类归属)
- 目录 ts/web/astro/polaris → ts/web/nextjs/polaris,
  删除过时 README,更新 ts/README.md 框架描述
2026-08-21 22:08:14 +08:00

12 KiB
Raw Blame History

Polaris 项目说明文档

关联文档: Polaris 首页设计文档 —— 首页布局、搜索交互、视觉规范 Polaris 分类页设计文档 —— 分类页布局、卡片、状态设计

配套资产:logo.svg(占位 Logo,后续替换)、Polaris页面设计图.png

1. 项目名称

Polaris

Polaris 原意为“北极星”,具有方向、导航、定位、指引的含义。该名称与个人导航站的产品定位非常契合。

本项目的核心目标是打造一个轻量、安静、高效、可长期维护的个人导航站,用于集中管理和访问常用网站、分类资源与个人入口。


2. 项目定位

Polaris 不是后台管理系统,也不是信息密集型 Dashboard。

一个具有个人审美、可自定义背景、可快速搜索和访问常用链接的浏览器起始页。

产品形态是动态可配置的个人导航站:第一版可以静态部署,数据写死在本地配置中,但页面具有动态交互(实时时钟、搜索、侧边栏折叠、快捷键等),后续将本地数据源替换为 Go 后端 API,不需要推翻前端整体结构。


3. 项目目标

第一阶段目标:

  1. 提供一个美观的个人导航首页;
  2. 支持快速访问常用链接;
  3. 支持左侧分类导航与分类页;
  4. 支持搜索框(Google / Bing / GitHub / 本地);
  5. 支持当前时间与日期展示;
  6. 支持左侧边栏折叠(状态持久化);
  7. 支持背景自定义的设计预留;
  8. 数据第一版写死在本地 JSON 数据配置中;
  9. 代码结构预留未来接入 Go 后端接口的能力。

后续阶段目标:

  1. 从 Go 后端 API 获取链接、分类、设置等数据;
  2. 使用数据库持久化配置;
  3. 支持后台或隐藏入口管理链接;
  4. 支持用户自定义背景;
  5. 支持主题色、深色模式、导入导出、移动端适配等个性化能力。

4. 已确认的关键决策

以下决策已于 2026-08-21 确认,作为实施基线:

# 决策项 结论
1 技术栈 以本文档为准:Next.js + TypeScript + Tailwind CSS + shadcn/ui + lucide-react(早期 README 中 Astro 设想作废)
2 渲染策略 静态导出(output: 'export'),时钟/搜索/侧边栏折叠为 client 岛屿
3 包管理器 pnpm
4 项目位置 ts/web/nextjs/polaris/
5 Logo 现有 logo.svg 仅作占位,后续替换,不投入设计精力
6 数据载体 本地 JSON 数据文件(links.json / categories.json / settings.json),结构以 Vitest 校验测试兜底
7 第一版数据范围 「开发工具」15 条 + 首页常用链接 8 条(跨分类条目归入真实分类,见首页设计文档 8.1);设计资源、学习资料、生活服务三个分类展示空状态
8 默认背景 CSS 低饱和青蓝渐变,不依赖图片资产;settings.background.type 预留 image
9 深色模式 第一版不做;CSS 变量按双主题友好组织,后续以 [data-theme="dark"] 覆盖
10 移动端 第一版不适配,仅桌面端
11 快捷键 Ctrl+K(macOS ⌘K)聚焦搜索框,仅首页生效;提示按平台检测显示
12 图标方案 四级 fallback:自定义图标 → Simple Icons / 本地图标库 → favicon 自动抓取 → 文字占位(见 6.4)
13 后端数据库 PostgreSQL(后续阶段);表结构不锁死 PG 特有语法(JSON 存通用 TEXT)
14 搜索行为 按模式严格分离:选中哪个引擎就只用哪个引擎搜索(回车直跳);仅 Local 模式显示本地结果下拉

5. 技术选型

5.1 前端技术栈

Next.js(App Router)
TypeScript
Tailwind CSS
shadcn/ui
lucide-react
simple-icons

说明:

  1. Next.js:适合从静态页面起步,后续接入动态接口;
  2. TypeScript:适合维护链接、分类、配置等结构化数据;
  3. Tailwind CSS:适合快速实现玻璃感、响应式、主题变量;
  4. shadcn/ui:用于基础组件,例如 Button、Input、Dialog、Command;
  5. lucide-react:用于侧边栏和操作图标;
  6. simple-icons:品牌图标库(npm 包,按 slug 引用)。

测试:Vitest + Testing Library,重点覆盖纯函数(问候语分段、本地搜索匹配排序、icon 解析、搜索 URL 模板)与核心交互组件。

5.2 渲染策略

采用静态导出:

// next.config.ts
const nextConfig = { output: "export" }
  • 首页与全部分类页在构建时从本地数据生成(generateStaticParams);
  • 时钟、搜索、侧边栏折叠等交互以 client 组件实现;
  • 产物为纯静态文件,可部署到任意静态服务器;
  • 后续接 Go 后端时,改造 service 层为 fetch,数据页面改为客户端获取。

5.3 数据访问层

页面组件不直接依赖数据文件,一律通过 service 层获取数据。

第一版:

import links from "@/data/links.json"

export function getLinks(): NavLink[] {
  return links
}

后续接 Go 后端时,只需要修改 service 层:

export async function getLinks() {
  const res = await fetch("/api/links")
  if (!res.ok) {
    throw new Error("Failed to fetch links")
  }
  return res.json()
}

这样页面组件不用大规模重构。

JSON 缺少编译期类型检查,用 Vitest 数据校验测试兜底:校验 data/*.json 满足 Category[] / NavLink[] / AppSettings 结构(必填字段齐全、类型正确、categoryId 存在于分类中),字段拼错或漏填在测试阶段即报错。

5.4 后端技术栈(后续阶段)

后端由 Go 实现,数据库 PostgreSQL。

候选组合:

Go + Chi + sqlc     —— 结构清晰、SQL 可控(推荐)
Go + Gin + GORM     —— 开发更快、上手成本低

6. 数据结构

6.1 分类数据

{
  id: "dev",
  title: "开发工具",
  description: "高效的开发工具和资源集合,提升你的开发体验和效率。",
  icon: "code",
  sort: 20
}

字段说明:

id:          分类唯一标识
title:       分类名称
description: 分类描述(分类页标题下方展示)
icon:        图标名称(侧边栏,lucide 图标名)
sort:        排序值

6.2 链接数据

{
  id: "github",
  title: "GitHub",
  description: "全球最大的代码托管平台",
  url: "https://github.com",
  icon: "si:github",
  categoryId: "dev",
  pinned: true,
  keywords: ["代码", "仓库", "开源", "git"],
  sort: 10
}

字段说明:

id:          链接唯一标识
title:       链接名称
description: 简短描述(分类页卡片展示,8-16 个中文字)
url:         链接地址
icon:        图标引用,格式见 6.4
categoryId:  所属分类
pinned:      是否展示在首页常用链接区域
keywords:    本地搜索关键词
sort:        排序值

6.3 设置数据

{
  siteName: "Polaris",
  theme: "light-glass",
  search: {
    defaultProvider: "google",
    enabledProviders: ["google", "bing", "github", "local"]
  },
  background: {
    type: "gradient",      // "gradient" | "image"
    url: null,             // type 为 image 时生效
    blur: 8,
    overlay: 0.32
  },
  sidebar: {
    defaultCollapsed: false
  }
}

6.4 统一图标方案

链接卡片与搜索结果的图标按以下顺序解析,逐级 fallback:

1. 自定义图标       icon: "local:xxx"        → public/icons/xxx.svg
2. Simple Icons    icon: "si:github"        → simple-icons npm 包按 slug 渲染品牌图标
3. favicon 抓取    icon: "url:https://..."  → 远程图标;icon 缺省时按链接 url 域名自动抓取
4. 文字占位         以上全部失败             → 标题首字符 + 圆角玻璃底兜底

侧边栏分类导航图标使用 lucide-react(如 home / code / palette),不参与此 fallback 链。


7. 未来 Go 后端 API 设计

后续接入 Go 后端时,推荐 API:

GET /api/categories
GET /api/links
GET /api/links?categoryId=dev
GET /api/settings

后续管理能力:

POST   /api/links
PUT    /api/links/:id
DELETE /api/links/:id

POST   /api/categories
PUT    /api/categories/:id
DELETE /api/categories/:id

PUT    /api/settings

背景相关:

POST /api/backgrounds
GET  /api/backgrounds
PUT  /api/settings/background

8. 数据库表设计草案

草案使用跨数据库通用语法;JSON 以 TEXT 存储。PostgreSQL 下可将 TEXT(存 JSON)字段替换为 JSONB 以获得索引与查询能力。

8.1 categories

CREATE TABLE categories (
  id TEXT PRIMARY KEY,
  title TEXT NOT NULL,
  description TEXT NOT NULL DEFAULT '',
  icon TEXT NOT NULL,
  sort INTEGER NOT NULL DEFAULT 0,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE links (
  id TEXT PRIMARY KEY,
  title TEXT NOT NULL,
  description TEXT NOT NULL DEFAULT '',
  url TEXT NOT NULL,
  icon TEXT,
  category_id TEXT NOT NULL,
  pinned BOOLEAN NOT NULL DEFAULT FALSE,
  keywords TEXT NOT NULL DEFAULT '[]',  -- JSON 数组字符串
  sort INTEGER NOT NULL DEFAULT 0,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,

  CONSTRAINT fk_links_category
    FOREIGN KEY (category_id)
    REFERENCES categories(id)
);

8.3 settings

CREATE TABLE settings (
  key TEXT PRIMARY KEY,
  value TEXT NOT NULL,                  -- JSON 字符串
  updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);

9. 开发阶段

第一阶段:前端静态版(当前阶段)

目标:完成首页与分类页基础体验。

页面背景(CSS 渐变)与背景遮罩
左侧边栏 + 折叠(localStorage 持久化)+ 导航选中态
时间 / 日期 / 问候语
搜索框(Google / Bing / GitHub / 本地搜索)+ Ctrl+K 快捷键
常用链接(pinned,8 个)
分类页路由 + 卡片网格 + 空状态
桌面端响应式

数据范围:开发工具 15 个链接 + 首页 8 个常用链接(跨分类条目归入真实分类:ChatGPT → AI 工具,Gmail / Notion → 效率工具,YouTube / Bilibili → 娱乐媒体);设计资源、学习资料、生活服务三个分类展示空状态。

第二阶段:数据补全与体验完善

补全其余 6 个分类的链接数据
深色玻璃主题
移动端 / 平板适配

第三阶段:数据访问层抽象

封装 links / categories / settings service
统一 TypeScript 类型
统一错误处理与 loading 状态

此阶段完成后,页面组件不直接关心数据来自本地配置还是 API。

第四阶段:Go 后端 API

Go API 服务
数据库连接(PostgreSQL)
links / categories / settings 查询接口
基础 CORS 配置
Docker 部署预留

第五阶段:管理能力

新增 / 编辑 / 删除链接
调整排序、修改分类
修改背景、主题
导入导出配置

管理能力不进入首页主视觉,放到独立管理页或隐藏入口。


10. 项目目录结构

polaris/
  public/
    icons/              # 自定义 SVG 图标(icon: "local:xxx" 引用)
    logo.svg

  src/
    app/
      layout.tsx        # 背景层 + 字体
      page.tsx          # 首页
      categories/
        [categoryId]/
          page.tsx      # 分类页(generateStaticParams 生成)
      globals.css       # Tailwind + CSS 变量(浅色值,深色预留覆盖位)

    components/
      layout/           # AppShell / Sidebar / SidebarNavItem
      home/             # ClockGreeting / SearchBox / SearchResults / QuickLinks
      category/         # CategoryHeader / ToolGrid / ToolCard
      common/           # SiteIcon(四级 fallback)/ GlassPanel

    data/               # links.json / categories.json / settings.json
    services/           # links.ts / categories.ts / settings.ts / search.ts
    types/              # navigation.ts / settings.ts / search.ts
    lib/                # cn.ts / greeting.ts / local-search.ts / search-providers.ts / icon.ts(纯函数)

  next.config.ts        # output: 'export'
  vitest.config.ts

11. 最终目标

打开 Polaris 后,用户可以立刻搜索、立刻访问常用网站,也可以通过侧边栏进入分类页面。页面具有个人氛围,但保持干净、高效、克制。第一版数据本地配置,后续平滑切换到 Go 后端。