Files
Ubuntu 32b43f85bd a
2026-07-03 16:58:28 +08:00

13 KiB
Raw Permalink Blame History

Personal Blog - 前端设计文档

React 18 + Vite + Tailwind CSS + 双主题架构


1. 项目结构

frontend/
├── index.html              # HTML 入口(Vite 注入 JS)
├── vite.config.js          # Vite 配置(proxy、host、port)
├── tailwind.config.js      # Tailwind CSS 配置
├── package.json            # 依赖管理
└── src/
    ├── main.jsx            # React 根渲染
    ├── App.jsx             # 根路由配置
    ├── index.css           # 全局样式(双主题 CSS 变量 + 组件类)
    ├── api/                # API 封装层
    │   ├── config.js       # Axios 实例 + 拦截器
    │   ├── posts.js        # 文章 API
    │   └── categories.js   # 分类 API
    ├── pages/              # 页面组件(路由级)
    │   ├── Home.jsx           # 访客端首页
    │   ├── PostDetail.jsx     # 访客端文章详情
    │   ├── PostEdit.jsx       # 文章编辑/新建
    │   ├── Posts.jsx          # 文章管理列表
    │   ├── CrawlEdit.jsx      # 通用网页采集
    │   ├── WechatCrawlEdit.jsx # 公众号采集
    │   ├── Categories.jsx     # 分类管理
    │   ├── Tags.jsx           # 标签管理
    │   ├── Images.jsx         # 图片管理
    │   ├── Settings.jsx       # 系统设置
    │   ├── Login.jsx          # 登录页
    │   └── About.jsx          # 关于页面
    ├── components/         # 访客端通用组件
    │   ├── Layout.jsx      # 访客端页面布局(含导航、页脚)
    │   └── PostCard.jsx    # 文章列表卡片
    └── components-preline/ # 管理后台组件库
        ├── Sidebar.jsx     # 侧边栏导航
        ├── Card.jsx        # 卡片容器
        ├── Button.jsx      # 按钮
        └── Input.jsx       # 输入框/文本域

2. 路由架构 (App.jsx)

React Router v7 (BrowserRouter)
│
├── 访客端路径 (Layout 包裹)
│   ├── /                     → Home.jsx       首页文章列表
│   ├── /post/:slug           → PostDetail.jsx 文章详情
│   ├── /category/:id         → Home.jsx       分类筛选
│   ├── /tag/:name            → Home.jsx       标签筛选
│   ├── /about                → About.jsx      关于页面
│   └── /page/:slug           → PageView.jsx   自定义页面
│
└── 管理后台路径 (AdminLayout 包裹,需登录)
    ├── /admin                → Dashboard      仪表盘
    ├── /admin/posts          → Posts.jsx      文章列表
    ├── /admin/posts/new      → PostEdit.jsx   新建文章
    ├── /admin/posts/:id/edit → PostEdit.jsx   编辑文章
    ├── /admin/crawl          → CrawlEdit.jsx  通用采集
    ├── /admin/wechat-crawl   → WechatCrawlEdit.jsx 公众号采集
    ├── /admin/categories     → Categories.jsx 分类管理
    ├── /admin/tags           → Tags.jsx       标签管理
    ├── /admin/images         → Images.jsx     图片管理
    ├── /admin/settings       → Settings.jsx   系统设置
    └── /admin/login          → Login.jsx      登录页

2.1 路由守卫

管理后台路由通过 localStorage.getItem('admin_token') 判断登录状态:

// App.jsx 中的路由守卫逻辑
const isAdminRoute = location.pathname.startsWith('/admin')
const isLoginPage = location.pathname === '/admin/login'

useEffect(() => {
  if (isAdminRoute && !isLoginPage && !localStorage.getItem('admin_token')) {
    navigate('/admin/login')
  }
}, [location.pathname])
  • 未登录访问管理后台 → 强制跳转到登录页
  • 登录页不检查 Token(避免循环跳转)

3. 双主题设计

项目同时存在两种视觉风格,通过 CSS 变量和独立组件类实现共存。

3.1 主题对比

维度 访客端 (Neobrutalism) 管理后台 (Preline Admin)
定位 面向读者,活泼有趣 面向管理员,专业高效
色彩 奶油色底 + 高饱和撞色(粉/黄/青/紫) 白色底 + 深蓝灰
边框 粗黑实线(2px),直角 细灰实线(1px),圆角(rounded-lg)
阴影 硬阴影偏移(4px 4px 0) 柔和阴影(shadow-sm/md)
按钮 块状,hover 位移凹陷 圆角,hover 背景加深
滚动条 自定义粗黑风格 浏览器默认
选中文字 黄色背景 默认

3.2 CSS 变量体系

:root {
  /* Neobrutalism 默认配色 */
  --brutal-cream: #FEF9E7;
  --brutal-yellow: #FFDE59;
  --brutal-pink: #FF6B9D;
  --brutal-cyan: #00D9FF;
  --brutal-lavender: #C084FC;
  --brutal-green: #4ADE80;

  /* 默认使用 Neobrutalism */
  --color-bg: var(--brutal-cream);
  --color-card: #FFFFFF;
  --color-primary: var(--brutal-pink);
  --color-text: #000000;
  --border-width: 2px;
  --border-radius: 0px;
  --shadow: 4px 4px 0px 0px rgba(0,0,0,1);
}

3.3 组件类映射

访客端使用 @layer components 中定义的 *-brutal 类:

  • .btn-brutal / .btn-brutal-sm
  • .card-brutal / .card-brutal-sm
  • .input-brutal
  • .nav-link / .nav-link-active

管理后台使用 *-preline 类或直接写 Tailwind 工具类:

  • .btn-preline / .btn-preline-secondary / .btn-preline-danger
  • .card-preline / .card-preline-header / .card-preline-body
  • .input-preline / .label-preline
  • .sidebar-preline 等

3.4 实现方式

两种主题不是通过切换 CSS 变量实现的,而是:

  • 访客端组件 硬编码使用 *-brutal 类
  • 管理后台组件 硬编码使用 *-preline 类或 Tailwind 工具类

共存于同一个 index.css 文件中,按页面路由分别加载对应组件。


4. API 层 (api/config.js)

4.1 Axios 实例配置

const api = axios.create({
  baseURL: 'http://localhost:8889/api',  // 开发环境
  timeout: 30000,
})

4.2 请求拦截器

自动注入 Authorization 头部:

api.interceptors.request.use(config => {
  const token = localStorage.getItem('admin_token')
  if (token) {
    config.headers.Authorization = `Bearer ${token}`
  }
  return config
})

4.3 响应拦截器

Token 过期时自动跳转登录页:

api.interceptors.response.use(
  response => response,
  error => {
    if (error.response?.status === 401) {
      localStorage.removeItem('admin_token')
      window.location.href = '/admin/login'
    }
    return Promise.reject(error)
  }
)

5. 管理后台布局 (AdminLayout)

┌─────────────────────────────────────────────────────────────┐
│  ┌──────┐                    Header                         │
│  │ Logo │  面包屑 / 页面标题          管理员 / 退出          │
│  └──────┘────────────────────────────────────────────────── │
│  ┌────────┐  ┌────────────────────────────────────────────┐ │
│  │  首页   │  │                                            │ │
│  │  文章   │  │            页面内容区域                     │ │
│  │  采集   │  │                                            │ │
│  │  分类   │  │                                            │ │
│  │  标签   │  │                                            │ │
│  │  图片   │  │                                            │ │
│  │  设置   │  │                                            │ │
│  └────────┘  └────────────────────────────────────────────┘ │
│     Sidebar              Main Content                        │
└─────────────────────────────────────────────────────────────┘

5.1 侧边栏导航 (Sidebar.jsx)

const menuItems = [
  { name: '首页', path: '/admin', icon: Home },
  { name: '文章管理', path: '/admin/posts', icon: FileText },
  { name: '文章采集', path: '/admin/crawl', icon: Globe },
  { name: '公众号采集', path: '/admin/wechat-crawl', icon: MessageSquare },
  { name: '分类管理', path: '/admin/categories', icon: Folder },
  { name: '标签管理', path: '/admin/tags', icon: Tag },
  { name: '图片管理', path: '/admin/images', icon: Image },
  { name: '系统设置', path: '/admin/settings', icon: Settings },
]
  • 固定左侧,宽度 64 (折叠) / 256 (展开) px
  • 当前路由高亮
  • 移动端自适应汉堡菜单

5.2 退出登录

const handleLogout = () => {
  localStorage.removeItem('admin_token')
  window.location.href = '/admin/login'
}

6. 访客端布局 (Layout.jsx)

┌─────────────────────────────────────────────┐
│  Logo      首页 · 文章 · 分类 · 关于 · 管理后台 │
├─────────────────────────────────────────────┤
│                                             │
│            页面内容 (Outlet)                 │
│                                             │
├─────────────────────────────────────────────┤
│          Footer (版权 / 备案)                │
└─────────────────────────────────────────────┘

6.1 导航栏

  • Neobrutalism 风格:粗黑边框、黄底高亮当前项
  • 移动端:汉堡菜单 + 抽屉式导航
  • 导航项从后端 /api/settings 动态获取(自定义页面)

6.2 页脚

  • 左侧:站点名称 + 描述 + 版权
  • 右侧:备案号链接 + 社交媒体图标(可选)
  • 返回顶部按钮

7. 核心页面详解

7.1 访客端首页 (Home.jsx)

功能:

  • 展示文章卡片网格
  • 支持按分类/标签筛选
  • 搜索框
  • 分页

文章卡片 (PostCard.jsx):

  • 封面图(如有)
  • 标题
  • 摘要(截断至 120 字符)
  • 分类标签
  • 日期 + 阅读数

7.2 访客端文章详情 (PostDetail.jsx)

功能:

  • 文章标题、元信息(日期/分类/标签)
  • 封面图
  • 正文渲染(见 05-markdown-rendering.md)
  • 分享按钮
  • 上一篇/下一篇导航

7.3 文章编辑 (PostEdit.jsx)

功能:

  • 新建/编辑双模式
  • 左右双栏布局:
    • 左栏:标题、摘要、正文(Markdown textarea)、操作按钮
    • 右栏:分类、标签、封面图上传、文章状态
  • Markdown 实时预览(react-markdown)
  • 保存草稿 / 发布 / 取消

7.4 文章列表 (Posts.jsx)

功能:

  • 表格展示所有文章
  • 搜索、分类筛选、状态筛选
  • 分页
  • 批量操作(删除)
  • 快捷操作:编辑、删除、预览

8. 状态管理

项目未使用 Redux/Zustand 等全局状态库,采用 React 内置状态 + 服务端状态:

数据 管理方式
登录 Token localStorage
文章列表 useState + useEffect 调用 API
文章详情 useState + useEffect
分类/标签 useState + useEffect
系统设置 useState + useEffect
表单数据 useState (受控组件)

8.1 典型数据获取模式

const [posts, setPosts] = useState([])
const [loading, setLoading] = useState(true)

useEffect(() => {
  api.get('/posts', { params: { skip: 0, limit: 10 } })
    .then(res => setPosts(res.data.items))
    .catch(err => console.error(err))
    .finally(() => setLoading(false))
}, [])

9. 构建配置 (vite.config.js)

export default defineConfig({
  plugins: [react()],
  server: {
    host: '0.0.0.0',
    port: 8888,
    proxy: {
      '/api': { target: 'http://localhost:8889', changeOrigin: true },
      '/uploads': { target: 'http://localhost:8889', changeOrigin: true },
    },
  },
})

9.1 代理配置

开发环境下,前端请求 /api/* 和 /uploads/* 自动代理到后端(:8889),解决跨域问题。

9.2 生产部署

npm run build  # 输出到 dist/ 目录

生产环境使用 serve 或 Nginx 托管静态文件:

npx serve -s dist -l 8888 --cors

10. Tailwind 配置

10.1 自定义颜色

// tailwind.config.js
theme: {
  extend: {
    colors: {
      'brutal-cream': '#FEF9E7',
      'brutal-yellow': '#FFDE59',
      'brutal-pink': '#FF6B9D',
      'brutal-cyan': '#00D9FF',
      'brutal-lavender': '#C084FC',
      'brutal-green': '#4ADE80',
    },
  },
}

10.2 插件

  • @tailwindcss/forms — 表单元素基础样式
  • preline — Preline UI JavaScript 组件交互

本文档由 nanobot 根据项目源码自动生成。