# WikiPali 前端开发规范
> 版本:1.0 · 适用范围:`library/*` · `blog/*` 全站前端
---
## 1. 技术栈
| 层级 | 技术 |
|---|---|
| 后端框架 | Laravel 12 |
| 模板引擎 | Blade |
| CSS 框架 | Tabler CSS(基于 Bootstrap 5) |
| 构建工具 | Vite |
| 交互 | Vanilla JS + Tabler Offcanvas/Dropdown |
| 搜索引擎 | OpenSearch |
无 Livewire、无 Alpine.js、无额外前端框架。JS 保持轻量,仅在必要时引入模块。
---
## 2. 目录结构
```
resources/
├── css/
│ ├── library.css # library/* 入口(纯 @import)
│ ├── blog.css # blog/* 入口(纯 @import)
│ ├── reader.css # 全站阅读页入口(纯 @import)
│ ├── app.css # 过渡期保留,稳定后删除
│ │
│ ├── base/
│ │ ├── _variables.css # Tabler 变量覆盖 + 自定义 token
│ │ ├── _reset.css # normalize / reset
│ │ └── _typography.css # 字体、行高、标题
│ │
│ ├── layout/
│ │ ├── _grid.css # 断点定义 + 1/2/3 栏容器(全站唯一)
│ │ ├── _navbar.css # 顶部导航(desktop 展开 / mobile 汉堡)
│ │ ├── _drawer.css # 左右 Drawer(基于 Tabler Offcanvas)
│ │ ├── _hero.css # Hero 区域
│ │ ├── _footer.css
│ │ └── _toolbar.css # 页内工具条
│ │
│ ├── components/
│ │ ├── _search-input.css # 搜索框 + 提示下拉
│ │ ├── _search-results.css # 搜索结果页布局
│ │ ├── _card.css # 通用卡片(title + list)
│ │ ├── _card-book.css # 书籍卡片(封面 + 标题)
│ │ ├── _badge.css
│ │ └── _pagination.css
│ │
│ └── modules/ # 各栏目差异样式,仅覆盖变量或追加规则
│ ├── _wiki.css # wiki 专属(词条详情、质量徽章等)
│ ├── _tipitaka.css
│ ├── _anthology.css
│ ├── _blog.css
│ └── _reader.css # 阅读正文区(字号、行高、夜间模式)
│
├── js/
│ ├── app.js # 全局入口
│ ├── bootstrap.js
│ └── modules/
│ ├── term-tooltip.js # 术语提示(原 term-tooltip.js)
│ ├── toc.js # TOC 折叠 + 滚动高亮
│ ├── theme.js # 夜间模式切换
│ └── search-suggest.js # 搜索提示下拉
│
└── views/
├── layouts/ # 布局文件(全站仅 3 个)
│ ├── base.blade.php # HTML 骨架
│ ├── library.blade.php # library/* 含 navbar + footer
│ ├── blog.blade.php # blog/* 独立三栏,无 library 导航
│ └── reader.blade.php # 全站阅读页,沉浸式,无导航
│
├── components/
│ ├── ui/ # 纯 UI 组件,全站通用
│ │ ├── drawer.blade.php
│ │ ├── search-input.blade.php
│ │ ├── card.blade.php
│ │ ├── card-book.blade.php
│ │ ├── badge.blade.php
│ │ └── pagination.blade.php
│ │
│ └── library/ # library 布局专用
│ ├── navbar.blade.php
│ ├── nav-links.blade.php
│ ├── hero.blade.php
│ ├── toolbar.blade.php
│ ├── footer.blade.php
│ ├── toc.blade.php
│ ├── layout-1col.blade.php
│ ├── layout-2col.blade.php
│ └── layout-3col.blade.php
│
├── library/
│ ├── index.blade.php
│ ├── search.blade.php # 统一搜索结果页
│ ├── tipitaka/
│ │ ├── index.blade.php
│ │ ├── category.blade.php
│ │ ├── show.blade.php
│ │ └── read.blade.php
│ ├── anthology/
│ │ ├── index.blade.php
│ │ ├── show.blade.php
│ │ └── read.blade.php
│ └── wiki/
│ ├── home.blade.php
│ ├── index.blade.php
│ └── show.blade.php
│
└── blog/
├── index.blade.php
├── category.blade.php
└── show.blade.php
```
---
## 3. 路由与页面对应
```
/library → library/index.blade.php
/library/search?q=&type= → library/search.blade.php
/library/tipitaka → library/tipitaka/index.blade.php
/library/tipitaka/category/{id} → library/tipitaka/category.blade.php
/library/tipitaka/{id} → library/tipitaka/show.blade.php
/library/tipitaka/{id}/read → library/tipitaka/read.blade.php
/library/anthology → library/anthology/index.blade.php
/library/anthology/{id} → library/anthology/show.blade.php
/library/anthology/{id}/read/{art} → library/anthology/read.blade.php
/library/wiki → library/wiki/home.blade.php
/library/wiki/{lang} → library/wiki/index.blade.php
/library/wiki/{lang}/{word} → library/wiki/show.blade.php
/blog/{user} → blog/index.blade.php
/blog/{user}/{post} → blog/show.blade.php
/blog/{user}/category/... → blog/category.blade.php
```
---
## 4. 栏目划分
| 栏目 | 路由前缀 | 布局 | 说明 |
|---|---|---|---|
| Library 门户 | `/library` | `layouts/library` | 入口页,含 Hero |
| Tipitaka(巴利三藏) | `/library/tipitaka` | `layouts/library` | 含阅读页 |
| Anthology(文集) | `/library/anthology` | `layouts/library` | 含阅读页 |
| Wiki(词典) | `/library/wiki` | `layouts/library` | 词条详情为阅读页 |
| Search(搜索) | `/library/search` | `layouts/library` | 统一结果页,`?type=` 区分栏目 |
| Blog(博客) | `/blog` | `layouts/blog` | 独立三栏,与 library 完全隔离 |
**阅读页统一使用 `layouts/reader`**,包括:
- `library/tipitaka/read.blade.php`
- `library/anthology/read.blade.php`
- `library/wiki/show.blade.php`(词条详情本质为阅读)
- `blog/show.blade.php`(博文详情)
---
## 5. Blade 调用层级
```
layouts/base.blade.php
│ HTML 骨架,@vite,@stack('styles'),@stack('scripts')
│ 不含任何导航或布局
│
├── layouts/library.blade.php
│ @extends('layouts.base')
│ 包含:navbar + hero(可选) + toolbar(可选) + @yield('content') + footer
│ 页面通过 @section('content') 填充正文
│ 栏目模块 CSS 通过 @push('styles') 注入
│
├── layouts/blog.blade.php
│ @extends('layouts.base')
│ 独立三栏:左侧博主信息 + 中间内容 + 右侧过滤工具
│ 无 library navbar / footer
│
└── layouts/reader.blade.php
@extends('layouts.base')
沉浸式,无 navbar,无 footer
包含:TOC(desktop 常驻,mobile 左侧 Drawer)+ 正文区
```
**页面文件示例:**
```blade
{{-- library/wiki/show.blade.php --}}
@extends('layouts.reader')
@push('styles')
@vite('resources/css/modules/_wiki.css') {{-- wiki 专属样式 --}}
@endpush
@section('content')
...
@endsection
```
---
## 6. CSS 架构与复用
### 基准层
wiki 栏目的现有 CSS 作为全站基准,其他栏目默认继承,需要时通过 `modules/_xxx.css` 覆盖。
### 入口文件职责
入口文件(`library.css` / `blog.css` / `reader.css`)**只做 `@import`,不写任何样式规则**。
```css
/* library.css */
@import './base/_variables.css';
@import './base/_reset.css';
@import './base/_typography.css';
@import './layout/_grid.css';
@import './layout/_navbar.css';
@import './layout/_drawer.css';
@import './layout/_hero.css';
@import './layout/_footer.css';
@import './layout/_toolbar.css';
@import './components/_search-input.css';
@import './components/_card.css';
@import './components/_card-book.css';
@import './components/_badge.css';
@import './components/_pagination.css';
/* modules 不在此引入,由各页面按需 @push */
```
### 变量覆盖机制
`_variables.css` 覆盖 Tabler 的 CSS custom properties,各栏目 module 文件**只重定义变量,不重写规则**:
```css
/* modules/_wiki.css */
:root {
--color-primary: #5c6bc0;
}
/* 仅追加 wiki 专属规则 */
```
### Vite 入口配置
```js
// vite.config.js
laravel({
input: [
'resources/css/library.css',
'resources/css/blog.css',
'resources/css/reader.css',
'resources/js/app.js',
],
refresh: true,
})
```
---
## 7. 页面布局(从上到下)
### library/* 页面
```
┌────────────────────────────────────┐
│ Navbar │ 所有 library 页面
│ 左:面包屑 右:导航按钮 │
├────────────────────────────────────┤
│ Hero(可选) │ 首页、栏目首页
├────────────────────────────────────┤
│ Toolbar(可选) │ 列表页、详情页
├──────────┬────────────┬────────────┤
│ 左边栏 │ 主内容 │ 右边栏 │ 3 栏(wiki 词条等)
│(可选) │ │(可选) │ 2 栏(tipitaka 等)
│ │ │ │ 1 栏(首页、搜索)
└──────────┴────────────┴────────────┘
│ Footer │
└────────────────────────────────────┘
```
### blog/* 页面
```
┌──────────┬────────────┬────────────┐
│ 左边栏 │ 文章列表 │ 右边栏 │
│ │ │ │
│ 头像 │ 卡片列表 │ 搜索框 │
│ 徽章 │ 分页 │ 标签云 │
│ 栏目导航│ │ 过滤器 │
└──────────┴────────────┴────────────┘
```
### 阅读页(reader)
```
┌──────────┬────────────────────────┐
│ TOC │ 正文 │
│ 常驻 │ 无 navbar │
│ │ 无 footer │
└──────────┴────────────────────────┘
```
---
## 8. 响应式规范
断点统一定义在 `layout/_grid.css`,全站唯一,不在各栏目重复定义。
| 区域 | Desktop (>1024px) | Tablet (768–1024px) | Mobile (<768px) |
|---|---|---|---|
| 顶部导航 | 完整展开 | 完整展开 | 汉堡按钮 → 右侧 Drawer |
| 左边栏 | 常驻 | 常驻 | 左侧 Drawer,默认收起 |
| 右边栏 | 常驻 | 隐藏 | 隐藏 |
| 阅读页 TOC | 左侧常驻 | 左侧 Drawer | 左侧 Drawer + 悬浮触发按钮 |
| Blog 左边栏 | 常驻 | 左侧 Drawer | 左侧 Drawer |
| Blog 右边栏 | 常驻 | 隐藏 | 隐藏 |
### Drawer 组件
基于 Tabler Offcanvas,左右方向通过 `side` prop 控制:
```blade
{{-- 导航 Drawer(右侧) --}}
{{-- TOC Drawer(左侧) --}}
```
---
## 9. 可复用组件清单
| 组件 | 路径 | Props | 用途 |
|---|---|---|---|
| `` | `components/ui/drawer` | `id` `side=start\|end` `title` | 左/右抽屉 |
| `` | `components/ui/search-input` | `name` `action` `placeholder` `suggest-url` | 搜索框 + 提示 |
| `` | `components/ui/card` | `title` `items` `href` | 通用卡片 |
| `` | `components/ui/card-book` | `title` `cover` `href` `layout=vertical\|horizontal` | 书籍卡片 |
| `` | `components/ui/badge` | `type` `label` | 徽章 |
| `` | `components/ui/pagination` | `paginator` | 分页 |
| `` | `components/library/navbar` | — | 含汉堡触发 |
| `` | `components/library/toc` | `items` | TOC,自适应 Drawer |
| `` | `components/library/hero` | `title` `subtitle` | Hero 区域 |
| `` | `components/library/toolbar` | slot | 页内工具条 |
| `` | `components/library/layout-1col` | slot | 单栏容器 |
| `` | `components/library/layout-2col` | slot `main` `aside` | 双栏容器 |
| `` | `components/library/layout-3col` | slot `left` `main` `right` | 三栏容器 |
---
## 10. 搜索规范
搜索底层统一使用 OpenSearch,结果页统一为 `library/search.blade.php`。
| 参数 | 说明 | 示例 |
|---|---|---|
| `q` | 搜索关键词 | `?q=dukkha` |
| `type` | 栏目过滤 | `?type=wiki` `?type=tipitaka` |
| `lang` | 语言过滤 | `?lang=zh` |
各栏目的搜索入口(如 wiki 首页的搜索框)跳转至统一搜索页,并预填 `type` 参数。搜索提示下拉由 `search-suggest.js` 处理,调用各自的 suggest API。
---
## 11. 迁移策略
重构为**增量迁移**,不一次性切换,降低风险。
1. **以 wiki 为基准**:wiki 现有 CSS 和组件作为公共层的起点
2. **提取公共层**:将 wiki 中可复用的部分移至 `layouts/`、`components/ui/`、`base/`
3. **wiki 改为引用公共层**:行为不变,验证通过后继续
4. **逐栏目迁移顺序**:wiki → anthology → tipitaka → blog(从简单到复杂)
5. **旧文件保留至迁移完成**:`app.css`、各栏目旧 `layouts/app.blade.php` 在对应栏目迁移完成后再删除
---
*本文档随重构进展持续更新*