Files
nanocode/personal-blog/PRELINE_MIGRATION_PLAN.md
T
Ubuntu 32b43f85bd a
2026-07-03 16:58:28 +08:00

17 KiB
Raw Blame History

Personal Blog - Preline UI 迁移方案

迁移目标: 逐步将管理后台从 Neobrutalism 迁移到 Preline UI
迁移策略: 渐进式迁移,不影响现有功能
预计工作量: 2-3 天(分阶段进行)


1. 迁移总览

1.1 迁移范围

区域 当前风格 目标风格 优先级
访客端 (Home/PostDetail) Neobrutalism 保持 Neobrutalism -
登录页 (Login) Neobrutalism Preline Modern P1
后台首页 (Dashboard) Neobrutalism Preline Admin P1
文章管理 (Posts) Neobrutalism Preline Admin P2
文章编辑 (PostEdit) Neobrutalism Preline Admin P2
分类/标签/图片管理 Neobrutalism Preline Admin P3
系统设置 (Settings) Neobrutalism Preline Admin P1 (试点)
采集页面 (CrawlEdit) Neobrutalism Preline Admin P3

1.2 为什么这样分?

  • 访客端保持原样: 博客展示需要个性风格,Neobrutalism 很适合
  • 后台用 Preline: 管理后台需要专业、高效、统一
  • 渐进式迁移: 每次只改一个页面,确保稳定

2. 技术准备

2.1 已安装依赖

npm install preline @tailwindcss/forms

2.2 需要修改的配置文件

步骤 1: 更新 CSS 入口文件

文件: src/index.css

/* ========== Preline UI 迁移 - 双主题共存方案 ========== */

/* 基础 Tailwind */
@tailwind base;
@tailwind components;
@tailwind utilities;

/* Preline UI 支持 */
@source "./node_modules/preline/dist/*.js";
@import "./node_modules/preline/variants.css";

/* Preline 需要的基础样式 */
@plugin "@tailwindcss/forms";

/* ============================================ */
/* 主题 1: Neobrutalism (访客端 + 默认) */
/* ============================================ */

@layer base {
  :root {
    /* 色彩系统 */
    --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);
  }
  
  body {
    @apply bg-[var(--color-bg)] text-[var(--color-text)];
    font-family: system-ui, -apple-system, sans-serif;
  }
}

/* ============================================ */
/* 主题 2: Preline Admin (管理后台) */
/* ============================================ */

[data-theme="preline"] {
  /* Preline 默认配色 */
  --color-bg: #F8FAFC;
  --color-card: #FFFFFF;
  --color-primary: #10B981;
  --color-text: #0F172A;
  --color-text-secondary: #64748B;
  --color-border: #E2E8F0;
  --color-sidebar: #0F172A;
  --color-sidebar-active: #1E293B;
  
  /* 样式变量 */
  --border-width: 1px;
  --border-radius: 0.75rem;
  --shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
}

/* ============================================ */
/* Neobrutalism 组件样式 (保留) */
/* ============================================ */

@layer components {
  .btn-brutal {
    @apply inline-flex items-center justify-center px-4 py-2 
           border-2 border-black font-bold text-sm
           transition-all duration-150
           shadow-brutal hover:shadow-none
           hover:translate-x-[2px] hover:translate-y-[2px]
           active:translate-x-[4px] active:translate-y-[4px];
  }
  
  .card-brutal {
    @apply bg-white border-2 border-black shadow-brutal;
  }
  
  .input-brutal {
    @apply w-full px-3 py-2 border-2 border-black bg-white 
           focus:outline-none focus:ring-2 focus:ring-brutal-yellow
           placeholder:text-black/40;
  }
}

/* ============================================ */
/* Preline Admin 组件样式 (新增) */
/* ============================================ */

@layer components {
  /* Preline 风格按钮 */
  .btn-preline {
    @apply inline-flex items-center justify-center gap-2 
           px-4 py-2.5 rounded-lg font-medium text-sm
           bg-[var(--color-primary)] text-white
           hover:opacity-90 focus:outline-none focus:ring-2 
           focus:ring-[var(--color-primary)] focus:ring-offset-2
           transition-all duration-200;
  }
  
  .btn-preline-secondary {
    @apply inline-flex items-center justify-center gap-2 
           px-4 py-2.5 rounded-lg font-medium text-sm
           bg-white text-[var(--color-text)]
           border border-[var(--color-border)]
           hover:bg-gray-50 focus:outline-none focus:ring-2
           focus:ring-gray-200 transition-all duration-200;
  }
  
  /* Preline 风格卡片 */
  .card-preline {
    @apply bg-[var(--color-card)] rounded-xl 
           border border-[var(--color-border)]
           shadow-sm hover:shadow-md transition-shadow duration-200;
  }
  
  /* Preline 风格输入框 */
  .input-preline {
    @apply w-full px-4 py-2.5 rounded-lg 
           border border-[var(--color-border)] bg-white
           text-[var(--color-text)]
           focus:outline-none focus:ring-2 
           focus:ring-[var(--color-primary)]/20 
           focus:border-[var(--color-primary)]
           placeholder:text-gray-400
           transition-all duration-200;
  }
  
  /* Preline 侧边栏 */
  .sidebar-preline {
    @apply w-64 bg-[var(--color-sidebar)] min-h-screen
           fixed left-0 top-0 z-40;
  }
  
  .sidebar-nav-item {
    @apply flex items-center gap-3 px-4 py-2.5 rounded-lg
           text-gray-400 hover:bg-[var(--color-sidebar-active)]
           hover:text-white transition-colors duration-200;
  }
  
  .sidebar-nav-item.active {
    @apply bg-[var(--color-sidebar-active)] text-white font-medium;
  }
}

/* ============================================ */
/* 工具类扩展 */
/* ============================================ */

@layer utilities {
  .shadow-brutal {
    box-shadow: 4px 4px 0px 0px rgba(0,0,0,1);
  }
  
  .shadow-brutal-sm {
    box-shadow: 2px 2px 0px 0px rgba(0,0,0,1);
  }
}

/* ============================================ */
/* Neobrutalism 滚动条 (仅访客端) */
/* ============================================ */

:not([data-theme="preline"]) ::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}

:not([data-theme="preline"]) ::-webkit-scrollbar-track {
  background: #FEF9E7;
  border-left: 2px solid black;
}

:not([data-theme="preline"]) ::-webkit-scrollbar-thumb {
  background: #000;
  border: 2px solid #FEF9E7;
}

/* ============================================ */
/* Preline 滚动条 (管理后台) */
/* ============================================ */

[data-theme="preline"] ::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}

[data-theme="preline"] ::-webkit-scrollbar-track {
  background: transparent;
}

[data-theme="preline"] ::-webkit-scrollbar-thumb {
  background: #CBD5E1;
  border-radius: 4px;
}

[data-theme="preline"] ::-webkit-scrollbar-thumb:hover {
  background: #94A3B8;
}

步骤 2: 更新 tailwind.config.js

文件: tailwind.config.js

/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
    // Preline UI 支持
    "./node_modules/preline/dist/*.js",
  ],
  theme: {
    extend: {
      // 保留 Neobrutalism 颜色
      colors: {
        brutal: {
          cream: '#FEF9E7',
          yellow: '#FFDE59',
          pink: '#FF6B9D',
          cyan: '#00D9FF',
          lavender: '#C084FC',
          green: '#4ADE80',
        },
        // Preline 配色
        preline: {
          primary: '#10B981',
          'primary-hover': '#059669',
          'primary-light': '#D1FAE5',
          sidebar: '#0F172A',
          'sidebar-active': '#1E293B',
          bg: '#F8FAFC',
          card: '#FFFFFF',
          border: '#E2E8F0',
        }
      },
      boxShadow: {
        'brutal': '4px 4px 0px 0px rgba(0,0,0,1)',
        'brutal-sm': '2px 2px 0px 0px rgba(0,0,0,1)',
        // Preline 柔和阴影
        'card': '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)',
        'card-hover': '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
      },
      fontFamily: {
        display: ['system-ui', '-apple-system', 'sans-serif'],
        sans: ['Inter', 'system-ui', '-apple-system', 'sans-serif'],
      },
    },
  },
  plugins: [
    // Preline 需要
    require('@tailwindcss/forms'),
  ],
}

步骤 3: 添加 Preline JS

文件: src/main.jsx

import React from 'react'
import ReactDOM from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'
import App from './App.jsx'
import './index.css'

// Preline UI JavaScript
import 'preline'

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>,
)

3. 组件迁移计划

3.1 新建 Preline 组件目录

src/
├── components/           # 现有 Neobrutalism 组件
│   ├── Button.jsx
│   ├── Card.jsx
│   ├── Input.jsx
│   ├── Layout.jsx
│   └── Sidebar.jsx
├── components-preline/   # 新建 Preline 组件
│   ├── Button.jsx
│   ├── Card.jsx
│   ├── Input.jsx
│   ├── Layout.jsx        # Preline 风格后台布局
│   ├── Sidebar.jsx       # Preline 深色侧边栏
│   ├── StatsCard.jsx     # 统计卡片
│   ├── DataTable.jsx     # 数据表格
│   └── PageHeader.jsx    # 页面头部

3.2 核心组件对照表

功能 Neobrutalism Preline
按钮 btn-brutal hs-btn + Tailwind 类
卡片 card-brutal hs-card
输入框 input-brutal hs-input
侧边栏 奶油色 + 硬边框 深色 + 柔和圆角
表格 自定义 hs-table
模态框 自定义 hs-overlay
下拉菜单 自定义 hs-dropdown

4. 分阶段实施计划

Phase 1: 基础配置 (第 1 天)

目标: 让 Preline 跑起来,不影响现有功能

  • 更新 src/index.css 添加双主题支持
  • 更新 tailwind.config.js
  • 更新 main.jsx 引入 Preline JS
  • 创建 components-preline/ 目录结构
  • 测试:确认现有页面正常

验证点: 现有 Neobrutalism 风格页面不受影响


Phase 2: Settings 页面试点 (第 1-2 天)

目标: 用 Settings 页面验证迁移方案

为什么选 Settings?

  • 功能单一,改动风险小
  • 表单元素多,能验证 Preline 表单组件
  • 有保存/成功提示,能验证交互

具体改动:

  • 新建 components-preline/Layout.jsx (Preline 风格后台布局)
  • 新建 components-preline/Sidebar.jsx (深色侧边栏)
  • 新建 components-preline/Input.jsx (Preline 输入框)
  • 新建 components-preline/Button.jsx (Preline 按钮)
  • 改写 pages/admin/Settings.jsx
  • 添加主题切换开关

Settings 页面新结构:

// pages/admin/Settings.jsx
import { AdminLayout } from '../../components-preline/Layout'
import { Card } from '../../components-preline/Card'
import { Input } from '../../components-preline/Input'
import { Button } from '../../components-preline/Button'

export default function Settings() {
  return (
    <AdminLayout>
      <div className="p-6 max-w-4xl mx-auto">
        <h1 className="text-2xl font-semibold mb-6">博客设置</h1>
        
        <Card>
          <Card.Header>
            <h3 className="text-lg font-medium">基本信息</h3>
          </Card.Header>
          <Card.Body>
            {/* Preline 风格表单 */}
          </Card.Body>
        </Card>
      </div>
    </AdminLayout>
  )
}

验证点: Settings 页面显示正常,表单能正常提交


Phase 3: Dashboard 首页 (第 2 天)

目标: 后台首页改用 Preline 风格

改动内容:

  • 新建 components-preline/StatsCard.jsx (统计卡片)
  • 改写 pages/Dashboard.jsx
  • 添加图表支持 (可选,用 Recharts 或 Preline Charts)

Dashboard 新布局:

┌─────────────────────────────────────────────────────────┐
│  [Sidebar]  │  Header: Dashboard            [🔔][👤]    │
│  (dark)     ├───────────────────────────────────────────┤
│             │                                           │
│  Dashboard  │  ┌──────────┬──────────┬──────────┐      │
│  Posts      │  │ StatsCard│ StatsCard│ StatsCard│      │
│  Categories │  └──────────┴──────────┴──────────┘      │
│  Images     │                                           │
│  Settings   │  ┌───────────────────────────────┐       │
│             │  │   Recent Posts Table          │       │
│             │  └───────────────────────────────┘       │
│             │                                           │
└─────────────┴───────────────────────────────────────────┘

Phase 4: Posts 管理页面 (第 2-3 天)

目标: 文章列表改用 Preline 风格

改动内容:

  • 新建 components-preline/DataTable.jsx (数据表格)
  • 新建 components-preline/Badge.jsx (状态标签)
  • 新建 components-preline/Pagination.jsx (分页)
  • 改写 pages/Posts.jsx

Phase 5: PostEdit 编辑页面 (第 3 天)

目标: 文章编辑改用 Preline 风格

改动内容:

  • 新建 components-preline/Textarea.jsx (Markdown 编辑器容器)
  • 改写 pages/PostEdit.jsx

Phase 6: 剩余页面 (后续)

  • Login 页面
  • Categories 页面
  • Images 页面
  • CrawlEdit 页面

Phase 7: 主题切换功能 (可选)

目标: 支持在 Settings 切换后台主题

  • 后端 Setting 表添加 admin_theme 字段
  • 主题切换逻辑
  • 主题持久化

5. 文件清单

5.1 需要新建的组件

src/components-preline/
├── Layout.jsx          # 后台布局 (深色侧边栏 + 顶部栏)
├── Sidebar.jsx         # 侧边栏导航
├── Header.jsx          # 顶部栏
├── Button.jsx          # 按钮
├── Card.jsx            # 卡片
├── Input.jsx           # 输入框
├── Textarea.jsx        # 文本域
├── Select.jsx          # 下拉选择
├── Badge.jsx           # 标签
├── DataTable.jsx       # 数据表格
├── Pagination.jsx      # 分页
├── StatsCard.jsx       # 统计卡片
├── PageHeader.jsx      # 页面标题
├── Modal.jsx           # 模态框
├── Alert.jsx           # 提示消息
└── index.js            # 统一导出

5.2 需要改写的页面

src/pages/
├── Dashboard.jsx       # Phase 3
├── Posts.jsx           # Phase 4
├── PostEdit.jsx        # Phase 5
├── Login.jsx           # Phase 6
└── admin/
    ├── Settings.jsx    # Phase 2 (试点)
    ├── Categories.jsx  # Phase 6
    └── Images.jsx      # Phase 6

6. 风险与回滚方案

6.1 潜在风险

风险 概率 影响 应对
CSS 冲突 中 样式错乱 双主题 CSS 变量隔离
JS 兼容 低 Preline 组件失效 保留原有组件作为后备
构建失败 低 无法部署 每次改动后单独测试
功能回归 中 原有功能失效 逐个页面迁移,充分测试

6.2 回滚方案

如果某个页面迁移后出问题:

# 回滚单个页面
git checkout src/pages/Posts.jsx

# 或者使用原有组件
# 把 import { Button } from '../components-preline/Button'
# 改回 import { Button } from '../components/Button'

7. 验证清单

每个 Phase 完成后检查:

  • 页面能正常加载
  • 样式显示正确
  • 表单能正常提交
  • 响应式正常 (移动端/平板/桌面)
  • 访客端页面不受影响
  • 构建无警告/错误

8. 参考资源


9. 下一步行动

确认方案后,从 Phase 1 开始执行:

  1. ✅ 先更新配置文件 (CSS + Tailwind + main.jsx)
  2. ✅ 然后 Phase 2: Settings 页面试点
  3. ✅ 验证通过后继续后续 Phase

确认开始执行吗? 先确认一下理解:

采用双主题共存方案,访客端保持 Neobrutalism 奶油色粗边框风格,管理后台逐步迁移到 Preline 深色侧边栏现代风格,从 Settings 页面开始试点迁移。

确认后我开始写 Phase 1 的代码。