Skip to content

Commit

Permalink
docs: how to develop a theme
Browse files Browse the repository at this point in the history
  • Loading branch information
wibus-wee committed Jan 31, 2023
1 parent d07593a commit 6caac63
Show file tree
Hide file tree
Showing 2 changed files with 276 additions and 4 deletions.
8 changes: 4 additions & 4 deletions src/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,6 @@ export default defineConfigWithTheme<Config>({
{
text: '主要功能',
link: '/guide/features',
},
{
text: '跟其他的博客系统进行对比',
link: '/guide/compare',
}
],
},
Expand Down Expand Up @@ -184,6 +180,10 @@ export default defineConfigWithTheme<Config>({
text: '拓展新的服务模块',
link: '/developer/extend-service',
},
{
text: "开发新的主题",
link: '/developer/theme',
}
],
}
]
Expand Down
272 changes: 272 additions & 0 deletions src/developer/theme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
# 开发新的主题


## 主题开发

::: warning 注意
创建主题时,需要在 `package.json` 中指定 `name` 字段、在 `config.yml` 中指定 `id` 字段和 `language` 字段,否则合法性检查会失败。

示例主题可以在此处找到:[mogland-dev/mog-theme-tiny-ejs](https://github.com/mogland-dev/mog-theme-tiny-ejs)
:::

1. 按照[主题目录结构](#主题目录结构)创建主题目录。
2. 开始开发主题,其中需要有 EJS 的基础语法知识,主题渲染中提供了一些变量,可以在 EJS 中使用,具体变量见 [变量](#变量)
3.`config.yml` 中指定主题的配置,具体配置见 [主题配置](#主题配置)
4. 开发完成后,将主题上传至 GitHub,然后标注 `mog-theme` 标签,等待 [awesome-mog](https://github.com/mogland/awesome-mog) 更新完毕即可在主题市场中搜索到。

> 正常情况下最多在 3 小时后,你的项目将能出现在 Awesome List 和 Mog 主题市场中


## 主题目录结构

- **packages.json**: 主题的配置文件,类似于 npm 的 `packages.json`,用于描述主题的基本信息,如:主题名字、版本、作者、描述等
- **config.yaml**: 主题的配置文件,用于描述主题的配置项,如:头像源、评论系统等
- ~~**i18n.yaml**: 主题的国际化文件,用于描述主题的国际化信息 <Badge text="尚未实现" color="gray" small/>~~
- **assets**: 主题的静态资源文件,如:css、js、图片等
- ~~**plugins**: 主题的插件文件,用于注入方法到主题中,如:moment.js 等方法类库 <Badge text="尚未实现" color="gray" small/>~~
- **index.ejs**: 主页
- **post.ejs**: 文章页
- **page.ejs**: 页面页
- **archives.ejs**: 归档页,分类 & 标签页
- **friends.ejs**: 友链页
- **404.ejs**: 404页
- **page-\*.ejs**: 自定义页面,如:关于页 等, `*` 为自定义的页面路径
- **preview.png**: 主题预览图

## 主题配置

我们考虑使用 YAML 定义主题配置

```yaml
id: "theme.tiny.wibus-wee"
language: zh # 语言, 要与 i18n.yaml 中设置的语言一致
# name: Tiny # name 使用 package.json 中的值
configs:
- name: "头像源"
key: "avatar_source"
# key is optional, if not set, it will be the same as name
# But I recommend you to set it if your name contains special characters or use Chinese
type: "select"
data:
- name: "Gravatar"
# key: "Gravatar"
value: "https://cn.gravatar.com/avatar/"
- name: "国内源"
key: "China"
value: "https://cdn.v2ex.com/gravatar/"
value: "Gravatar"
```
- **name**: 配置展示名
- **key**: 配置储存名(取值的时候使用此名)
key 是可选的,如果不去设置就与 name 是一样的。但是当 name 中涉及到一些特殊符号或者涉及中文字符的时候,强制需要填入 key
- **type**: 配置组件
- **data**: 传入配置组件的值(内部的定义与上方相似)
- **value**: 默认值,会传入配置组件,可选
## 配置组件
所有的 key 一般情况下除特殊要求,皆为可选字段,如果不设置 key 就与 name 一样。但是当 name 中涉及到一些特殊符号或者涉及中文字符的时候,**强制需要填入 key。**
- **input**: 输入框
```yaml
type: "input"
value: "https://cn.gravatar.com/avatar/"
```
传入的 data 为一个对象,对象中包含 value 一个必须的字段,key 为可选字段,如果不设置 key 就与 name 一样。
- **switch**: 开关
```yaml
type: "switch"
value: true
```
传入的 data 为一个对象,对象中包含 value 一个必须的字段,要求 value 为布尔值。
- **color**: 颜色选择器
```yaml
type: "color"
value: "#000000"
```
传入的 data 为一个对象,对象中包含 value 一个必须的字段,要求 value 为颜色值。
- **slider**: 滑块
```yaml
type: "slider"
value: 50
```
传入的 data 为一个对象,对象中包含 value 一个必须的字段,要求 value 为数字。
- **radio**: 单选框
```yaml
type: "radio"
data:
- name: "Gravatar"
value: "https://cn.gravatar.com/avatar/"
- name: "国内源"
key: "China"
value: "https://cdn.v2ex.com/gravatar/"
value: "Gravatar"
```
传入的 data 为一个数组,数组中的每一项都是一个对象,对象中包含 name, value 两个必须的字段。key 为可选字段,如果不设置 key 就与 name 一样。
value 为传入的值,value 会传入配置组件,需要与 data 中的 key 对应。
- **checkbox**: 多选框
```yaml
type: "checkbox"
data:
- name: "Gravatar"
value: "https://cn.gravatar.com/avatar/"
- name: "国内源"
key: "China"
value: "https://cdn.v2ex.com/gravatar/"
value: "Gravatar"
```
传入的 data 为一个数组,数组中的每一项都是一个对象,对象中包含 name, value 两个必须的字段。key 为可选字段,如果不设置 key 就与 name 一样。
value 为传入的值,value 会传入配置组件,需要与 data 中的 key 对应。
- **textarea**: 多行文本框
```yaml
type: "textarea"
value: "https://cn.gravatar.com/avatar/"
```
传入的 data 为一个对象,对象中包含 value 一个必须的字段,key 为可选字段,如果不设置 key 就与 name 一样。
- **select**: 下拉选择框
```yaml
type: "select"
data:
- name: "Gravatar"
value: "https://cn.gravatar.com/avatar/"
- name: "国内源"
key: "China"
value: "https://cdn.v2ex.com/gravatar/"
value: "Gravatar"
```
传入的 data 为一个数组,数组中的每一项都是一个对象,对象中包含 name, value 两个必须的字段。key 为可选字段,如果不设置 key 就与 name 一样。
value 为传入的值,value 会传入配置组件,需要与 data 中的 key 对应。
## 变量
### 全局变量
```ts
{
site: any, // 见 「网站变量」
page: any, // 见 「页面变量」
config: ConfigInterface, // 见 「ConfigInterface」- https://github.com/mogland/core/blob/main/libs/config/src/config.interface.ts#L14-L30
theme: any, // 主题配置文件
path: string, // 当前页面的路径(不含根路径)
url: any, // 见 「URL变量」
}
```

### 网站变量

```ts
{
posts: PostModel[], // 文章列表
pages: PageModel[], // 分页列表
categories: CategoryModel[], // 分类列表
tags: { // 标签列表
count: number, // 标签数量
name: string, // 标签名
}[],
}
```

### 页面变量

**页面(`page`**: [`PageModel`](https://github.com/mogland/core/blob/main/apps/page-service/src/model/page.model.ts) - 不会输出 `password` 等隐私字段

**文章 (`post`)**: [`PostModel`](https://github.com/mogland/core/blob/main/apps/page-service/src/model/post.model.ts) - 不会输出 `password` 等隐私字段

**首页(`index`**

```ts
{
docs: PostModel[], // 文章列表
totalDocs: number, // 文章总数
limit: number, // 每页文章数
totalPages: number, // 总页数
page: number, // 当前页
hasPrevPage: boolean, // 是否有上一页
hasNextPage: boolean, // 是否有下一页
prevPage: number | null, // 上一页页码
nextPage: number | null, // 下一页页码
}
```

**分类 (`category`)**[`CategoryModel`](https://github.com/mogland/core/blob/main/apps/page-service/src/model/category.model.ts)

```ts
data: {
[key in keyof CategoryModel]: CategoryModel[key]; // 继承自 CategoryModel 的字段
children: PostModel[], // 文章列表
},
isTag: false, // 是否是标签页
isCategory: true, // 是否是分类或者标签页
```

**标签 (`tag`)**

```ts
data: {
name: string, // 标签名
children: PostModel[], // 文章列表
},
isTag: true, // 是否是标签页
isCategory: true, // 是否是分类或者标签页
```

**归档 (`archives`)**

```ts
data: {
children: PostModel[], // 文章列表
},
isCategory: false, // 是否是分类或者标签页
```

**友链 (`friends`)**`FriendsModel`

### URL变量

```ts
{
url: string, // 完整的链接
path: string, // 路径
query: object, // 查询参数
params: object, // 路径参数
origin: string, // 域名: protocol + host
host: string, // 域名: host
protocol: string, // 协议
}
```

## i18n 方案 <Badge text="尚未实现" color="gray" small/>

## 主题模板扩展 <Badge text="尚未实现" color="gray" small/>

0 comments on commit 6caac63

Please sign in to comment.