Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@

### Fixed / Changed

**2026-08-20 · customConfig type 白名单对齐真实 GUI(修复 CI 长期红灯)**

- **`type: "color"` 不存在,取色器是 `type: "input"` + `"card": "color"`**:`scaffold_theme.py` 生成的 `config.json` 用了 `type: "color"`,被 `validate_syntax.py` 判为非法 —— 脚手架的产物通不过自己的校验器,CI 三个引擎自 2026-07-09 起全红。现改为 `input` + `card: "color"`,用户拿到的是真正的取色器而不是纯文本框;三个 starter 的 `primaryColor` 同步跟进。
- **校验白名单漏了 6 种 GUI 实际支持的类型**:逐条对照 `CustomSetting.vue` 的 v-if 分支核对后,`radio`、`switch`、`markdown`、`array`、`picture`、`image` 均可正常渲染,此前被误判为非法并给出错误的替代建议。白名单与 `theme-config-schema.md` 的类型表一并重写。
- **新增三条 config.json 校验**:`card` 只允许 `color` / `post`;`type: array` 缺 `arrayItems` 报错(否则面板渲染空卡片);`select` / `radio` 缺 `options` 报错(否则控件不渲染)。
- **文档补充数组配置写法**:`theme-config-schema.md` 增加 `arrayItems` 的完整示例。

**2026-07-08 · 基于 chatgpt 主题实战(真实引擎渲染)的修正与增强**

- **修正 `post.date` 类型描述(推翻上一轮"修正")**:Jinja2 / EJS 渲染上下文经 `json.Marshal` 构建,`post.date` / `updatedAt` / `createdAt` 是 **RFC3339 字符串**;仅 Go Templates 直接传 struct 才是 `time.Time`。Jinja2 中对这些字段用 `|date:` 会报错并使整页降级(实战中曾导致首页 + 全部文章页降级)。`template-variables.md` / `jinja2-guide.md`(差异 8 重写)/ `SKILL.md` 规则 6 三处对齐,并给出正确用法:`dateFormat` / `|relative` / 直接输出 / `|slice`。
Expand Down
1 change: 1 addition & 0 deletions assets/starters/ejs/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"group": "外观设置",
"value": "#2563eb",
"type": "input",
"card": "color",
"note": "主题主色调,用于链接和强调色"
},
{
Expand Down
1 change: 1 addition & 0 deletions assets/starters/go-templates/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"group": "外观设置",
"value": "#2563eb",
"type": "input",
"card": "color",
"note": "主题主色调,用于链接和强调色"
},
{
Expand Down
1 change: 1 addition & 0 deletions assets/starters/jinja2/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"group": "外观设置",
"value": "#2563eb",
"type": "input",
"card": "color",
"note": "主题主色调,用于链接和强调色"
},
{
Expand Down
43 changes: 34 additions & 9 deletions references/theme-config-schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,28 +80,53 @@ config.json 是主题与 Gridea Pro 之间的契约:

## 支持的配置类型

> ⚠️ **GUI 设置面板只渲染以下 5 种类型**(经真实 GUI 验证)。写其他类型不会报错,但设置面板中只显示标题、**控件空白,用户无法配置**。
> ⚠️ **只有下表中的 type 会被设置面板渲染**(逐条对照 `CustomSetting.vue` 的 v-if 分支核对)。写其他类型不会报错,但设置面板中只显示标题、**控件空白,用户无法配置**。

| type 值 | 渲染的 GUI 控件 | 值类型 | 额外字段 | 说明 |
|---------|-----------------|--------|----------|------|
| `input` | 单行文本输入框 | string | — | 短文本:标题、链接、颜色 HEX 值等 |
| `input` | 单行文本输入框 | string | `card` 可选 | 短文本:标题、链接等 |
| `input` + `"card": "color"` | **取色器** | string | — | 颜色首选写法,值为 HEX(如 `#2563eb`) |
| `input` + `"card": "post"` | 文章选择器 | string | — | 值为文章标识 |
| `textarea` | 多行文本域 | string | — | 长文本:自定义 CSS / JS、多行文案、注入代码 |
| `select` | 下拉选择框 | string | `options` 必需 | `options` 为 `[{"label":"显示名","value":"实际值"}]` 数组 |
| `toggle` | 开关(Switch) | boolean | — | 值为 `true` 或 `false` |
| `picture-upload` | 图片上传控件 | string | — | 值为图片路径字符串 |
| `select` | 下拉选择框 | string | `options` **必需** | `options` 为 `[{"label":"显示名","value":"实际值"}]` 数组 |
| `radio` | 单选按钮组 | string | `options` **必需** | 选项少(2–4 个)时比 `select` 直观 |
| `toggle` / `switch` | 开关 | boolean | — | 两者等价,值为 `true` 或 `false` |
| `markdown` | Markdown 编辑器 | string | — | 带编辑器的长文本 |
| `picture-upload` / `picture` / `image` | 图片上传控件 | string | — | 三者等价,值为图片路径字符串 |
| `array` | 可增删的卡片列表 | array | `arrayItems` **必需** | 见下方「数组配置」 |

`card` 只在 `type: input` 上生效,合法值仅 `color` 和 `post`。

### ❌ 无效类型与替代方案

以下类型**GUI 不支持**(历史文档曾错误地列为可用),请按对照表替换:
以下类型**GUI 不支持**,请按对照表替换:

| ❌ 无效 type | ✅ 替代方案 |
|-------------|------------|
| `boolean` | `toggle`(语义相同) |
| `image` | `picture-upload` |
| `color` | `input`(note 里注明 HEX 格式,如 `#10a37f`) |
| `color` | `input` 加 `"card": "color"`,渲染真正的取色器 |
| `code` | `textarea` |
| `number` | `select`(枚举常用值)或 `input`;**模板中比较前必须 `\|default:N\|to_int`**(GUI 保存的值是字符串) |
| `array` | 拆成多个 `input`(如 featured1Name / featured2Name…),或 `textarea` 每行一条 |

### 数组配置

`type: "array"` 渲染成一组可增删的卡片,每张卡片的字段由 `arrayItems` 定义(字段本身支持 `input` / `select` / `switch` / `picture-upload` 等):

```json
{
"name": "featured",
"label": "推荐位",
"group": "首页",
"type": "array",
"value": [],
"arrayItems": [
{ "name": "title", "label": "标题", "type": "input" },
{ "name": "cover", "label": "封面", "type": "picture-upload" }
]
}
```

漏写 `arrayItems` 会渲染出空白卡片,`validate_syntax.py` 会报错拦截。

### 数字配置的完整模式

Expand Down
5 changes: 3 additions & 2 deletions scripts/scaffold_theme.py
Original file line number Diff line number Diff line change
Expand Up @@ -1428,9 +1428,10 @@ def build_config(theme_name, engine, author):
"name": "primaryColor",
"label": "主色调",
"group": "样式",
"type": "color",
"type": "input",
"card": "color",
"value": "#2563eb",
"note": "主题的主要颜色"
"note": "主题的主要颜色(HEX,如 #2563eb)"
},
{
"name": "showFeatureImage",
Expand Down
37 changes: 31 additions & 6 deletions scripts/validate_syntax.py
Original file line number Diff line number Diff line change
Expand Up @@ -493,17 +493,42 @@ def _validate_cross_engine(theme_dir, engine):
f"config.json 中 engine 值无效: '{config['engine']}',应为 jinja2/go/ejs"
))

# --- customConfig type 白名单(GUI 只渲染这 5 种,其他类型控件空白无法配置) ---
VALID_CONFIG_TYPES = {"input", "textarea", "select", "toggle", "picture-upload"}
# --- customConfig type 白名单 ---
# 与设置面板 CustomSetting.vue 的 v-if 分支一一对应;不在表内的 type 只渲染标题、控件空白。
# config.json 经 domain.Theme.CustomConfig([]interface{})原样透传到前端,
# 故 card / options / arrayItems 等附加字段不会在后端被裁掉。
VALID_CONFIG_TYPES = {
"input", "textarea", "select", "radio", "switch", "toggle",
"markdown", "array", "picture-upload", "picture", "image",
}
TYPE_SUGGESTIONS = {
"boolean": "toggle", "image": "picture-upload", "color": "input(note 注明 HEX)",
"code": "textarea", "number": "select 或 input(模板中 |default:N|to_int)",
"array": "多个 input 或 textarea 每行一条", "switch": "toggle", "radio": "select",
"boolean": "toggle",
"color": 'input 并加 "card": "color"(渲染取色器)',
"code": "textarea",
"number": "select 或 input(模板中 |default:N|to_int)",
}
VALID_CARDS = {"color", "post"}
for item in config.get("customConfig", []) or []:
item_type = item.get("type", "")
card = item.get("card", "")
if card and card not in VALID_CARDS:
issues.append(Issue(
ERROR, "config.json", None,
f"customConfig '{item.get('name', '?')}' 的 card '{card}' GUI 不支持,"
f"仅支持 {'/'.join(sorted(VALID_CARDS))}(且只对 type: input 生效)"
))
if item_type == "array" and not item.get("arrayItems"):
issues.append(Issue(
ERROR, "config.json", None,
f"customConfig '{item.get('name', '?')}' 的 type 'array' 缺少 arrayItems,面板将渲染空卡片"
))
if item_type in ("select", "radio") and not item.get("options"):
issues.append(Issue(
ERROR, "config.json", None,
f"customConfig '{item.get('name', '?')}' 的 type '{item_type}' 缺少 options,控件不会渲染"
))
if item_type and item_type not in VALID_CONFIG_TYPES:
hint = TYPE_SUGGESTIONS.get(item_type, "input/textarea/select/toggle/picture-upload 之一")
hint = TYPE_SUGGESTIONS.get(item_type, "/".join(sorted(VALID_CONFIG_TYPES)) + " 之一")
issues.append(Issue(
ERROR, "config.json", None,
f"customConfig '{item.get('name', '?')}' 的 type '{item_type}' GUI 不支持(面板控件空白),请改用 {hint}"
Expand Down