mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-12 02:37:45 +08:00
Add output preview phase and callout types specifications
- Implemented Phase 4: Output & Preview for text formatter, including saving formatted content, generating statistics, and providing HTML preview. - Created callout types documentation with detection patterns and conversion rules for BBCode and HTML. - Added element mapping specifications detailing detection patterns and conversion matrices for various Markdown elements. - Established format conversion rules for BBCode and Markdown, emphasizing pixel-based sizing and supported tags. - Developed BBCode template with structured document and callout templates for consistent formatting.
This commit is contained in:
185
.claude/skills/text-formatter/SKILL.md
Normal file
185
.claude/skills/text-formatter/SKILL.md
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
---
|
||||||
|
name: text-formatter
|
||||||
|
description: Transform and optimize text content with intelligent formatting. Output BBCode + Markdown hybrid format optimized for forums. Triggers on "format text", "text formatter", "排版", "格式化文本", "BBCode".
|
||||||
|
allowed-tools: Task, AskUserQuestion, Read, Write, Bash, Glob
|
||||||
|
---
|
||||||
|
|
||||||
|
# Text Formatter
|
||||||
|
|
||||||
|
Transform and optimize text content with intelligent structure analysis. Output format: **BBCode + Markdown hybrid** optimized for forum publishing.
|
||||||
|
|
||||||
|
## Architecture Overview
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ Text Formatter Architecture (BBCode + MD Mode) │
|
||||||
|
├─────────────────────────────────────────────────────────────────┤
|
||||||
|
│ │
|
||||||
|
│ Phase 1: Input Collection → 接收文本/文件 │
|
||||||
|
│ ↓ │
|
||||||
|
│ Phase 2: Content Analysis → 分析结构、识别 Callout/Admonition │
|
||||||
|
│ ↓ │
|
||||||
|
│ Phase 3: Format Transform → 转换为 BBCode+MD 格式 │
|
||||||
|
│ ↓ │
|
||||||
|
│ Phase 4: Output & Preview → 保存文件 + 预览 │
|
||||||
|
│ │
|
||||||
|
└─────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## Key Design Principles
|
||||||
|
|
||||||
|
1. **Single Format Output**: BBCode + Markdown hybrid (forum optimized)
|
||||||
|
2. **Pixel-Based Sizing**: size=150/120/100/80 (not 1-7 levels)
|
||||||
|
3. **Forum Compatibility**: Only use widely-supported BBCode tags
|
||||||
|
4. **Markdown Separators**: Use `---` for horizontal rules (not `[hr]`)
|
||||||
|
5. **No Alignment Tags**: `[align]` not supported, avoid usage
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Format Specification
|
||||||
|
|
||||||
|
### Supported BBCode Tags
|
||||||
|
|
||||||
|
| Tag | Usage | Example |
|
||||||
|
|-----|-------|---------|
|
||||||
|
| `[size=N]` | Font size (pixels) | `[size=120]Title[/size]` |
|
||||||
|
| `[color=X]` | Text color | `[color=#2196F3]Blue[/color]` |
|
||||||
|
| `[b]` | Bold | `[b]Bold text[/b]` |
|
||||||
|
| `[i]` | Italic | `[i]Italic[/i]` |
|
||||||
|
| `[quote]` | Quote block | `[quote]Content[/quote]` |
|
||||||
|
| `[code]` | Code block | `[code]code[/code]` |
|
||||||
|
| `[img]` | Image | `[img]url[/img]` |
|
||||||
|
| `[url]` | Link | `[url=link]text[/url]` |
|
||||||
|
| `[list]` | List container | `[list][*]item[/list]` |
|
||||||
|
|
||||||
|
### Unsupported Tags (Avoid!)
|
||||||
|
|
||||||
|
| Tag | Reason | Alternative |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `[align]` | Not rendered | Remove or use default left |
|
||||||
|
| `[hr]` | Shows as text | Use Markdown `---` |
|
||||||
|
| `<div>` | HTML not supported | Use BBCode only |
|
||||||
|
| `[table]` | Limited support | Use list or code block |
|
||||||
|
|
||||||
|
### Size Hierarchy (Pixels)
|
||||||
|
|
||||||
|
| Element | Size | Color | Usage |
|
||||||
|
|---------|------|-------|-------|
|
||||||
|
| **Main Title** | 150 | #2196F3 | Document title |
|
||||||
|
| **Section Title** | 120 | #2196F3 | Major sections (## H2) |
|
||||||
|
| **Subsection** | 100 | #333 | Sub-sections (### H3) |
|
||||||
|
| **Normal Text** | (default) | - | Body content |
|
||||||
|
| **Notes/Gray** | 80 | gray | Footnotes, metadata |
|
||||||
|
|
||||||
|
### Color Palette
|
||||||
|
|
||||||
|
| Color | Hex | Semantic Usage |
|
||||||
|
|-------|-----|----------------|
|
||||||
|
| **Blue** | #2196F3 | Titles, links, info |
|
||||||
|
| **Green** | #4CAF50 | Success, tips, features |
|
||||||
|
| **Orange** | #FF9800 | Warnings, caution |
|
||||||
|
| **Red** | #F44336 | Errors, danger, important |
|
||||||
|
| **Purple** | #9C27B0 | Examples, code |
|
||||||
|
| **Gray** | gray | Notes, metadata |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Mandatory Prerequisites
|
||||||
|
|
||||||
|
> Read before execution:
|
||||||
|
|
||||||
|
| Document | Purpose | Priority |
|
||||||
|
|----------|---------|----------|
|
||||||
|
| [specs/format-rules.md](specs/format-rules.md) | Format conversion rules | **P0** |
|
||||||
|
| [specs/element-mapping.md](specs/element-mapping.md) | Element type mappings | P1 |
|
||||||
|
| [specs/callout-types.md](specs/callout-types.md) | Callout/Admonition types | P1 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Execution Flow
|
||||||
|
|
||||||
|
```
|
||||||
|
┌────────────────────────────────────────────────────────────────┐
|
||||||
|
│ Phase 1: Input Collection │
|
||||||
|
│ - Ask: paste text OR file path │
|
||||||
|
│ - Output: input-config.json │
|
||||||
|
├────────────────────────────────────────────────────────────────┤
|
||||||
|
│ Phase 2: Content Analysis │
|
||||||
|
│ - Detect structure: headings, lists, code blocks, tables │
|
||||||
|
│ - Identify Callouts/Admonitions (>[!type]) │
|
||||||
|
│ - Output: analysis.json │
|
||||||
|
├────────────────────────────────────────────────────────────────┤
|
||||||
|
│ Phase 3: Format Transform │
|
||||||
|
│ - Apply BBCode + MD rules from specs/format-rules.md │
|
||||||
|
│ - Convert elements with pixel-based sizes │
|
||||||
|
│ - Use Markdown --- for separators │
|
||||||
|
│ - Output: formatted content │
|
||||||
|
├────────────────────────────────────────────────────────────────┤
|
||||||
|
│ Phase 4: Output & Preview │
|
||||||
|
│ - Save to .bbcode.txt file │
|
||||||
|
│ - Display preview │
|
||||||
|
│ - Output: final file │
|
||||||
|
└────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## Callout/Admonition Support
|
||||||
|
|
||||||
|
支持 Obsidian 风格的 Callout 语法,转换为 BBCode quote:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
> [!NOTE]
|
||||||
|
> 这是一个提示信息
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> 这是一个警告信息
|
||||||
|
```
|
||||||
|
|
||||||
|
转换结果:
|
||||||
|
|
||||||
|
```bbcode
|
||||||
|
[quote]
|
||||||
|
[size=100][color=#2196F3][b]📝 注意[/b][/color][/size]
|
||||||
|
|
||||||
|
这是一个提示信息
|
||||||
|
[/quote]
|
||||||
|
```
|
||||||
|
|
||||||
|
| Type | Color | Icon |
|
||||||
|
|------|-------|------|
|
||||||
|
| NOTE/INFO | #2196F3 | 📝 |
|
||||||
|
| TIP/HINT | #4CAF50 | 💡 |
|
||||||
|
| SUCCESS | #4CAF50 | ✅ |
|
||||||
|
| WARNING/CAUTION | #FF9800 | ⚠️ |
|
||||||
|
| DANGER/ERROR | #F44336 | ❌ |
|
||||||
|
| EXAMPLE | #9C27B0 | 📋 |
|
||||||
|
|
||||||
|
## Directory Setup
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const timestamp = new Date().toISOString().slice(0,10).replace(/-/g, '');
|
||||||
|
const workDir = `.workflow/.scratchpad/text-formatter-${timestamp}`;
|
||||||
|
|
||||||
|
Bash(`mkdir -p "${workDir}"`);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Output Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
.workflow/.scratchpad/text-formatter-{date}/
|
||||||
|
├── input-config.json # 输入配置
|
||||||
|
├── analysis.json # 内容分析结果
|
||||||
|
└── output.bbcode.txt # BBCode+MD 输出
|
||||||
|
```
|
||||||
|
|
||||||
|
## Reference Documents
|
||||||
|
|
||||||
|
| Document | Purpose |
|
||||||
|
|----------|---------|
|
||||||
|
| [phases/01-input-collection.md](phases/01-input-collection.md) | 收集输入内容 |
|
||||||
|
| [phases/02-content-analysis.md](phases/02-content-analysis.md) | 分析内容结构 |
|
||||||
|
| [phases/03-format-transform.md](phases/03-format-transform.md) | 格式转换 |
|
||||||
|
| [phases/04-output-preview.md](phases/04-output-preview.md) | 输出和预览 |
|
||||||
|
| [specs/format-rules.md](specs/format-rules.md) | 格式转换规则 |
|
||||||
|
| [specs/element-mapping.md](specs/element-mapping.md) | 元素映射表 |
|
||||||
|
| [specs/callout-types.md](specs/callout-types.md) | Callout 类型定义 |
|
||||||
|
| [templates/bbcode-template.md](templates/bbcode-template.md) | BBCode 模板 |
|
||||||
111
.claude/skills/text-formatter/phases/01-input-collection.md
Normal file
111
.claude/skills/text-formatter/phases/01-input-collection.md
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
# Phase 1: Input Collection
|
||||||
|
|
||||||
|
收集用户输入的文本内容。
|
||||||
|
|
||||||
|
## Objective
|
||||||
|
|
||||||
|
- 获取用户输入内容(直接粘贴或文件路径)
|
||||||
|
- 生成输入配置文件
|
||||||
|
|
||||||
|
**注意**: 输出格式固定为 BBCode + Markdown 混合格式(论坛优化),无需选择。
|
||||||
|
|
||||||
|
## Input
|
||||||
|
|
||||||
|
- 来源: 用户交互
|
||||||
|
- 配置: 无前置依赖
|
||||||
|
|
||||||
|
## Execution Steps
|
||||||
|
|
||||||
|
### Step 1: 询问输入方式
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const inputMethod = await AskUserQuestion({
|
||||||
|
questions: [
|
||||||
|
{
|
||||||
|
question: "请选择输入方式",
|
||||||
|
header: "输入方式",
|
||||||
|
multiSelect: false,
|
||||||
|
options: [
|
||||||
|
{ label: "直接粘贴文本", description: "在对话中粘贴要格式化的内容" },
|
||||||
|
{ label: "指定文件路径", description: "读取指定文件的内容" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: 获取内容
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
let content = '';
|
||||||
|
|
||||||
|
if (inputMethod["输入方式"] === "直接粘贴文本") {
|
||||||
|
// 提示用户粘贴内容
|
||||||
|
const textInput = await AskUserQuestion({
|
||||||
|
questions: [
|
||||||
|
{
|
||||||
|
question: "请粘贴要格式化的文本内容(粘贴后选择确认)",
|
||||||
|
header: "文本内容",
|
||||||
|
multiSelect: false,
|
||||||
|
options: [
|
||||||
|
{ label: "已粘贴完成", description: "确认已在上方粘贴内容" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
// 从用户消息中提取文本内容
|
||||||
|
content = extractUserText();
|
||||||
|
} else {
|
||||||
|
// 询问文件路径
|
||||||
|
const filePath = await AskUserQuestion({
|
||||||
|
questions: [
|
||||||
|
{
|
||||||
|
question: "请输入文件路径",
|
||||||
|
header: "文件路径",
|
||||||
|
multiSelect: false,
|
||||||
|
options: [
|
||||||
|
{ label: "已输入路径", description: "确认路径已在上方输入" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
content = Read(extractedFilePath);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: 保存配置
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const config = {
|
||||||
|
input_method: inputMethod["输入方式"],
|
||||||
|
target_format: "BBCode+MD", // 固定格式
|
||||||
|
original_content: content,
|
||||||
|
timestamp: new Date().toISOString()
|
||||||
|
};
|
||||||
|
|
||||||
|
Write(`${workDir}/input-config.json`, JSON.stringify(config, null, 2));
|
||||||
|
```
|
||||||
|
|
||||||
|
## Output
|
||||||
|
|
||||||
|
- **File**: `input-config.json`
|
||||||
|
- **Format**: JSON
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"input_method": "直接粘贴文本",
|
||||||
|
"target_format": "BBCode+MD",
|
||||||
|
"original_content": "...",
|
||||||
|
"timestamp": "2026-01-13T..."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quality Checklist
|
||||||
|
|
||||||
|
- [ ] 成功获取用户输入内容
|
||||||
|
- [ ] 内容非空且有效
|
||||||
|
- [ ] 配置文件已保存
|
||||||
|
|
||||||
|
## Next Phase
|
||||||
|
|
||||||
|
→ [Phase 2: Content Analysis](02-content-analysis.md)
|
||||||
248
.claude/skills/text-formatter/phases/02-content-analysis.md
Normal file
248
.claude/skills/text-formatter/phases/02-content-analysis.md
Normal file
@@ -0,0 +1,248 @@
|
|||||||
|
# Phase 2: Content Analysis
|
||||||
|
|
||||||
|
分析输入内容的结构和语义元素。
|
||||||
|
|
||||||
|
## Objective
|
||||||
|
|
||||||
|
- 识别内容结构(标题、段落、列表等)
|
||||||
|
- 检测特殊元素(代码块、表格、链接等)
|
||||||
|
- 生成结构化分析结果
|
||||||
|
|
||||||
|
## Input
|
||||||
|
|
||||||
|
- 依赖: `input-config.json`
|
||||||
|
- 配置: `{workDir}/input-config.json`
|
||||||
|
|
||||||
|
## Execution Steps
|
||||||
|
|
||||||
|
### Step 1: 加载输入
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const config = JSON.parse(Read(`${workDir}/input-config.json`));
|
||||||
|
const content = config.original_content;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: 结构分析
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
function analyzeStructure(text) {
|
||||||
|
const analysis = {
|
||||||
|
elements: [],
|
||||||
|
stats: {
|
||||||
|
headings: 0,
|
||||||
|
paragraphs: 0,
|
||||||
|
lists: 0,
|
||||||
|
code_blocks: 0,
|
||||||
|
tables: 0,
|
||||||
|
links: 0,
|
||||||
|
images: 0,
|
||||||
|
quotes: 0,
|
||||||
|
callouts: 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Callout 检测正则 (Obsidian 风格)
|
||||||
|
const CALLOUT_PATTERN = /^>\s*\[!(\w+)\](?:\s+(.+))?$/;
|
||||||
|
|
||||||
|
const lines = text.split('\n');
|
||||||
|
let currentElement = null;
|
||||||
|
let inCodeBlock = false;
|
||||||
|
let inList = false;
|
||||||
|
|
||||||
|
for (let i = 0; i < lines.length; i++) {
|
||||||
|
const line = lines[i];
|
||||||
|
|
||||||
|
// 检测代码块
|
||||||
|
if (line.match(/^```/)) {
|
||||||
|
inCodeBlock = !inCodeBlock;
|
||||||
|
if (inCodeBlock) {
|
||||||
|
analysis.elements.push({
|
||||||
|
type: 'code_block',
|
||||||
|
start: i,
|
||||||
|
language: line.replace(/^```/, '').trim()
|
||||||
|
});
|
||||||
|
analysis.stats.code_blocks++;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inCodeBlock) continue;
|
||||||
|
|
||||||
|
// 检测标题 (Markdown 或纯文本模式)
|
||||||
|
if (line.match(/^#{1,6}\s/)) {
|
||||||
|
const level = line.match(/^(#+)/)[1].length;
|
||||||
|
analysis.elements.push({
|
||||||
|
type: 'heading',
|
||||||
|
level: level,
|
||||||
|
content: line.replace(/^#+\s*/, ''),
|
||||||
|
line: i
|
||||||
|
});
|
||||||
|
analysis.stats.headings++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测列表
|
||||||
|
if (line.match(/^[\s]*[-*+]\s/) || line.match(/^[\s]*\d+\.\s/)) {
|
||||||
|
if (!inList) {
|
||||||
|
analysis.elements.push({
|
||||||
|
type: 'list',
|
||||||
|
start: i,
|
||||||
|
ordered: line.match(/^\d+\./) !== null
|
||||||
|
});
|
||||||
|
analysis.stats.lists++;
|
||||||
|
inList = true;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
inList = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测 Callout (Obsidian 风格) - 优先于普通引用
|
||||||
|
const calloutMatch = line.match(CALLOUT_PATTERN);
|
||||||
|
if (calloutMatch) {
|
||||||
|
const calloutType = calloutMatch[1].toLowerCase();
|
||||||
|
const calloutTitle = calloutMatch[2] || null;
|
||||||
|
// 收集 Callout 内容行
|
||||||
|
const calloutContent = [];
|
||||||
|
let j = i + 1;
|
||||||
|
while (j < lines.length && lines[j].startsWith('>')) {
|
||||||
|
calloutContent.push(lines[j].replace(/^>\s*/, ''));
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
analysis.elements.push({
|
||||||
|
type: 'callout',
|
||||||
|
calloutType: calloutType,
|
||||||
|
title: calloutTitle,
|
||||||
|
content: calloutContent.join('\n'),
|
||||||
|
start: i,
|
||||||
|
end: j - 1
|
||||||
|
});
|
||||||
|
analysis.stats.callouts++;
|
||||||
|
i = j - 1; // 跳过已处理的行
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测普通引用
|
||||||
|
if (line.match(/^>\s/)) {
|
||||||
|
analysis.elements.push({
|
||||||
|
type: 'quote',
|
||||||
|
content: line.replace(/^>\s*/, ''),
|
||||||
|
line: i
|
||||||
|
});
|
||||||
|
analysis.stats.quotes++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测表格
|
||||||
|
if (line.match(/^\|.*\|$/)) {
|
||||||
|
analysis.elements.push({
|
||||||
|
type: 'table_row',
|
||||||
|
line: i
|
||||||
|
});
|
||||||
|
if (!analysis.elements.find(e => e.type === 'table')) {
|
||||||
|
analysis.stats.tables++;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测链接
|
||||||
|
const links = line.match(/\[([^\]]+)\]\(([^)]+)\)/g);
|
||||||
|
if (links) {
|
||||||
|
analysis.stats.links += links.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测图片
|
||||||
|
const images = line.match(/!\[([^\]]*)\]\(([^)]+)\)/g);
|
||||||
|
if (images) {
|
||||||
|
analysis.stats.images += images.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 普通段落
|
||||||
|
if (line.trim() && !line.match(/^[-=]{3,}$/)) {
|
||||||
|
analysis.elements.push({
|
||||||
|
type: 'paragraph',
|
||||||
|
line: i,
|
||||||
|
preview: line.substring(0, 50)
|
||||||
|
});
|
||||||
|
analysis.stats.paragraphs++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return analysis;
|
||||||
|
}
|
||||||
|
|
||||||
|
const analysis = analyzeStructure(content);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: 语义增强
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 识别特殊语义
|
||||||
|
function enhanceSemantics(text, analysis) {
|
||||||
|
const enhanced = { ...analysis };
|
||||||
|
|
||||||
|
// 检测关键词强调
|
||||||
|
const boldPatterns = text.match(/\*\*[^*]+\*\*/g) || [];
|
||||||
|
const italicPatterns = text.match(/\*[^*]+\*/g) || [];
|
||||||
|
|
||||||
|
enhanced.semantics = {
|
||||||
|
emphasis: {
|
||||||
|
bold: boldPatterns.length,
|
||||||
|
italic: italicPatterns.length
|
||||||
|
},
|
||||||
|
estimated_reading_time: Math.ceil(text.split(/\s+/).length / 200) // 200 words/min
|
||||||
|
};
|
||||||
|
|
||||||
|
return enhanced;
|
||||||
|
}
|
||||||
|
|
||||||
|
const enhancedAnalysis = enhanceSemantics(content, analysis);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: 保存分析结果
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
Write(`${workDir}/analysis.json`, JSON.stringify(enhancedAnalysis, null, 2));
|
||||||
|
```
|
||||||
|
|
||||||
|
## Output
|
||||||
|
|
||||||
|
- **File**: `analysis.json`
|
||||||
|
- **Format**: JSON
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"elements": [
|
||||||
|
{ "type": "heading", "level": 1, "content": "Title", "line": 0 },
|
||||||
|
{ "type": "paragraph", "line": 2, "preview": "..." },
|
||||||
|
{ "type": "callout", "calloutType": "warning", "title": "注意事项", "content": "...", "start": 4, "end": 6 },
|
||||||
|
{ "type": "code_block", "start": 8, "language": "javascript" }
|
||||||
|
],
|
||||||
|
"stats": {
|
||||||
|
"headings": 3,
|
||||||
|
"paragraphs": 10,
|
||||||
|
"lists": 2,
|
||||||
|
"code_blocks": 1,
|
||||||
|
"tables": 0,
|
||||||
|
"links": 5,
|
||||||
|
"images": 0,
|
||||||
|
"quotes": 1,
|
||||||
|
"callouts": 2
|
||||||
|
},
|
||||||
|
"semantics": {
|
||||||
|
"emphasis": { "bold": 5, "italic": 3 },
|
||||||
|
"estimated_reading_time": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quality Checklist
|
||||||
|
|
||||||
|
- [ ] 所有结构元素已识别
|
||||||
|
- [ ] 统计信息准确
|
||||||
|
- [ ] 语义增强完成
|
||||||
|
- [ ] 分析文件已保存
|
||||||
|
|
||||||
|
## Next Phase
|
||||||
|
|
||||||
|
→ [Phase 3: Format Transform](03-format-transform.md)
|
||||||
237
.claude/skills/text-formatter/phases/03-format-transform.md
Normal file
237
.claude/skills/text-formatter/phases/03-format-transform.md
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
# Phase 3: Format Transform
|
||||||
|
|
||||||
|
将内容转换为 BBCode + Markdown 混合格式(论坛优化)。
|
||||||
|
|
||||||
|
## Objective
|
||||||
|
|
||||||
|
- 根据分析结果转换内容
|
||||||
|
- 应用像素级字号规则
|
||||||
|
- 处理 Callout/标注语法
|
||||||
|
- 生成论坛兼容的输出
|
||||||
|
|
||||||
|
## Input
|
||||||
|
|
||||||
|
- 依赖: `input-config.json`, `analysis.json`
|
||||||
|
- 规范: `specs/format-rules.md`, `specs/element-mapping.md`
|
||||||
|
|
||||||
|
## Format Specification
|
||||||
|
|
||||||
|
### Size Hierarchy (Pixels)
|
||||||
|
|
||||||
|
| Element | Size | Color | Usage |
|
||||||
|
|---------|------|-------|-------|
|
||||||
|
| **H1** | 150 | #2196F3 | 文档主标题 |
|
||||||
|
| **H2** | 120 | #2196F3 | 章节标题 |
|
||||||
|
| **H3** | 100 | #333 | 子标题 |
|
||||||
|
| **H4+** | (默认) | - | 仅加粗 |
|
||||||
|
| **Notes** | 80 | gray | 备注/元数据 |
|
||||||
|
|
||||||
|
### Unsupported Tags (禁止使用)
|
||||||
|
|
||||||
|
| Tag | Reason | Alternative |
|
||||||
|
|-----|--------|-------------|
|
||||||
|
| `[align]` | 不渲染 | 删除,使用默认左对齐 |
|
||||||
|
| `[hr]` | 显示为文本 | 使用 Markdown `---` |
|
||||||
|
| `[table]` | 支持有限 | 转为列表或代码块 |
|
||||||
|
| HTML tags | 不支持 | 仅使用 BBCode |
|
||||||
|
|
||||||
|
## Execution Steps
|
||||||
|
|
||||||
|
### Step 1: 加载配置和分析
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const config = JSON.parse(Read(`${workDir}/input-config.json`));
|
||||||
|
const analysis = JSON.parse(Read(`${workDir}/analysis.json`));
|
||||||
|
const content = config.original_content;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: Callout 配置
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Callout 类型映射(像素级字号)
|
||||||
|
const CALLOUT_CONFIG = {
|
||||||
|
// 信息类
|
||||||
|
note: { icon: '📝', color: '#2196F3', label: '注意' },
|
||||||
|
info: { icon: 'ℹ️', color: '#2196F3', label: '信息' },
|
||||||
|
abstract: { icon: '📄', color: '#2196F3', label: '摘要' },
|
||||||
|
summary: { icon: '📄', color: '#2196F3', label: '摘要' },
|
||||||
|
tldr: { icon: '📄', color: '#2196F3', label: '摘要' },
|
||||||
|
|
||||||
|
// 成功/提示类
|
||||||
|
tip: { icon: '💡', color: '#4CAF50', label: '提示' },
|
||||||
|
hint: { icon: '💡', color: '#4CAF50', label: '提示' },
|
||||||
|
success: { icon: '✅', color: '#4CAF50', label: '成功' },
|
||||||
|
check: { icon: '✅', color: '#4CAF50', label: '完成' },
|
||||||
|
done: { icon: '✅', color: '#4CAF50', label: '完成' },
|
||||||
|
|
||||||
|
// 警告类
|
||||||
|
warning: { icon: '⚠️', color: '#FF9800', label: '警告' },
|
||||||
|
caution: { icon: '⚠️', color: '#FF9800', label: '注意' },
|
||||||
|
attention: { icon: '⚠️', color: '#FF9800', label: '注意' },
|
||||||
|
question: { icon: '❓', color: '#FF9800', label: '问题' },
|
||||||
|
help: { icon: '❓', color: '#FF9800', label: '帮助' },
|
||||||
|
faq: { icon: '❓', color: '#FF9800', label: 'FAQ' },
|
||||||
|
todo: { icon: '📋', color: '#FF9800', label: '待办' },
|
||||||
|
|
||||||
|
// 错误/危险类
|
||||||
|
danger: { icon: '❌', color: '#F44336', label: '危险' },
|
||||||
|
error: { icon: '❌', color: '#F44336', label: '错误' },
|
||||||
|
bug: { icon: '🐛', color: '#F44336', label: 'Bug' },
|
||||||
|
important: { icon: '⭐', color: '#F44336', label: '重要' },
|
||||||
|
|
||||||
|
// 其他
|
||||||
|
example: { icon: '📋', color: '#9C27B0', label: '示例' },
|
||||||
|
quote: { icon: '💬', color: 'gray', label: '引用' },
|
||||||
|
cite: { icon: '💬', color: 'gray', label: '引用' }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Callout 检测正则 (支持 +/- 折叠标记)
|
||||||
|
const CALLOUT_PATTERN = /^>\s*\[!(\w+)\][+-]?(?:\s+(.+))?$/;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: Callout 解析器
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
function parseCallouts(text) {
|
||||||
|
const lines = text.split('\n');
|
||||||
|
const result = [];
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
while (i < lines.length) {
|
||||||
|
const match = lines[i].match(CALLOUT_PATTERN);
|
||||||
|
if (match) {
|
||||||
|
const type = match[1].toLowerCase();
|
||||||
|
const title = match[2] || null;
|
||||||
|
const content = [];
|
||||||
|
i++;
|
||||||
|
|
||||||
|
// 收集 Callout 内容行
|
||||||
|
while (i < lines.length && lines[i].startsWith('>')) {
|
||||||
|
content.push(lines[i].replace(/^>\s*/, ''));
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push({
|
||||||
|
isCallout: true,
|
||||||
|
type,
|
||||||
|
title,
|
||||||
|
content: content.join('\n')
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
result.push({ isCallout: false, line: lines[i] });
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: BBCode+MD 转换器
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
function formatBBCodeMD(text) {
|
||||||
|
let result = text;
|
||||||
|
|
||||||
|
// ===== 标题转换 (像素级字号) =====
|
||||||
|
result = result.replace(/^######\s*(.+)$/gm, '[b]$1[/b]');
|
||||||
|
result = result.replace(/^#####\s*(.+)$/gm, '[b]$1[/b]');
|
||||||
|
result = result.replace(/^####\s*(.+)$/gm, '[b]$1[/b]');
|
||||||
|
result = result.replace(/^###\s*(.+)$/gm, '[size=100][color=#333][b]$1[/b][/color][/size]');
|
||||||
|
result = result.replace(/^##\s*(.+)$/gm, '[size=120][color=#2196F3][b]$1[/b][/color][/size]');
|
||||||
|
result = result.replace(/^#\s*(.+)$/gm, '[size=150][color=#2196F3][b]$1[/b][/color][/size]');
|
||||||
|
|
||||||
|
// ===== 文本样式 =====
|
||||||
|
result = result.replace(/\*\*\*(.+?)\*\*\*/g, '[b][i]$1[/i][/b]');
|
||||||
|
result = result.replace(/\*\*(.+?)\*\*/g, '[b]$1[/b]');
|
||||||
|
result = result.replace(/\*(.+?)\*/g, '[i]$1[/i]');
|
||||||
|
result = result.replace(/~~(.+?)~~/g, '[s]$1[/s]');
|
||||||
|
result = result.replace(/==(.+?)==/g, '[color=yellow]$1[/color]');
|
||||||
|
|
||||||
|
// ===== 代码 =====
|
||||||
|
result = result.replace(/```(\w*)\n([\s\S]*?)```/g, '[code]$2[/code]');
|
||||||
|
// 行内代码保持原样 (部分论坛不支持 font=monospace)
|
||||||
|
|
||||||
|
// ===== 链接和图片 =====
|
||||||
|
result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '[url=$2]$1[/url]');
|
||||||
|
result = result.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '[img]$2[/img]');
|
||||||
|
|
||||||
|
// ===== 引用 (非 Callout) =====
|
||||||
|
result = result.replace(/^>\s+(.+)$/gm, '[quote]$1[/quote]');
|
||||||
|
|
||||||
|
// ===== 列表 (使用 • 符号) =====
|
||||||
|
result = result.replace(/^[-*+]\s+(.+)$/gm, '• $1');
|
||||||
|
|
||||||
|
// ===== 分隔线 (保持 Markdown 语法) =====
|
||||||
|
// `---` 在混合格式中通常可用,不转换为 [hr]
|
||||||
|
|
||||||
|
return result.trim();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 5: Callout 转换
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
function convertCallouts(text) {
|
||||||
|
const parsed = parseCallouts(text);
|
||||||
|
|
||||||
|
return parsed.map(item => {
|
||||||
|
if (item.isCallout) {
|
||||||
|
const cfg = CALLOUT_CONFIG[item.type] || CALLOUT_CONFIG.note;
|
||||||
|
const displayTitle = item.title || cfg.label;
|
||||||
|
|
||||||
|
// 使用 [quote] 包裹,标题使用 size=100
|
||||||
|
return `[quote]
|
||||||
|
[size=100][color=${cfg.color}][b]${cfg.icon} ${displayTitle}[/b][/color][/size]
|
||||||
|
|
||||||
|
${item.content}
|
||||||
|
[/quote]`;
|
||||||
|
}
|
||||||
|
return item.line;
|
||||||
|
}).join('\n');
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 6: 执行转换
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 1. 先处理 Callouts
|
||||||
|
let formattedContent = convertCallouts(content);
|
||||||
|
|
||||||
|
// 2. 再进行通用 BBCode+MD 转换
|
||||||
|
formattedContent = formatBBCodeMD(formattedContent);
|
||||||
|
|
||||||
|
// 3. 清理多余空行
|
||||||
|
formattedContent = formattedContent.replace(/\n{3,}/g, '\n\n');
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 7: 保存转换结果
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const outputFile = 'output.bbcode.txt';
|
||||||
|
Write(`${workDir}/${outputFile}`, formattedContent);
|
||||||
|
|
||||||
|
// 更新配置
|
||||||
|
config.output_file = outputFile;
|
||||||
|
config.formatted_content = formattedContent;
|
||||||
|
Write(`${workDir}/input-config.json`, JSON.stringify(config, null, 2));
|
||||||
|
```
|
||||||
|
|
||||||
|
## Output
|
||||||
|
|
||||||
|
- **File**: `output.bbcode.txt`
|
||||||
|
- **Format**: BBCode + Markdown 混合格式
|
||||||
|
|
||||||
|
## Quality Checklist
|
||||||
|
|
||||||
|
- [ ] 标题使用像素值 (150/120/100)
|
||||||
|
- [ ] 未使用 `[align]` 标签
|
||||||
|
- [ ] 未使用 `[hr]` 标签
|
||||||
|
- [ ] 分隔线使用 `---`
|
||||||
|
- [ ] Callout 正确转换为 [quote]
|
||||||
|
- [ ] 颜色值使用 hex 格式
|
||||||
|
- [ ] 内容完整无丢失
|
||||||
|
|
||||||
|
## Next Phase
|
||||||
|
|
||||||
|
→ [Phase 4: Output & Preview](04-output-preview.md)
|
||||||
183
.claude/skills/text-formatter/phases/04-output-preview.md
Normal file
183
.claude/skills/text-formatter/phases/04-output-preview.md
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
# Phase 4: Output & Preview
|
||||||
|
|
||||||
|
输出最终结果并提供预览。
|
||||||
|
|
||||||
|
## Objective
|
||||||
|
|
||||||
|
- 保存格式化后的内容到文件
|
||||||
|
- 提供预览功能
|
||||||
|
- 显示转换统计信息
|
||||||
|
|
||||||
|
## Input
|
||||||
|
|
||||||
|
- 依赖: `input-config.json`, `output.*`
|
||||||
|
- 配置: `{workDir}/input-config.json`
|
||||||
|
|
||||||
|
## Execution Steps
|
||||||
|
|
||||||
|
### Step 1: 加载结果
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const config = JSON.parse(Read(`${workDir}/input-config.json`));
|
||||||
|
const analysis = JSON.parse(Read(`${workDir}/analysis.json`));
|
||||||
|
const outputFile = `${workDir}/${config.output_file}`;
|
||||||
|
const formattedContent = Read(outputFile);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: 生成统计摘要
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const summary = {
|
||||||
|
input: {
|
||||||
|
method: config.input_method,
|
||||||
|
original_length: config.original_content.length,
|
||||||
|
word_count: config.original_content.split(/\s+/).length
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
format: config.target_format,
|
||||||
|
file: outputFile,
|
||||||
|
length: formattedContent.length
|
||||||
|
},
|
||||||
|
elements: analysis.stats,
|
||||||
|
reading_time: analysis.semantics?.estimated_reading_time || 1
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log(`
|
||||||
|
╔════════════════════════════════════════════════════════════════╗
|
||||||
|
║ Text Formatter Summary ║
|
||||||
|
╠════════════════════════════════════════════════════════════════╣
|
||||||
|
║ Input: ${summary.input.word_count} words (${summary.input.original_length} chars)
|
||||||
|
║ Output: ${summary.output.format} → ${summary.output.file}
|
||||||
|
║ Elements Converted:
|
||||||
|
║ • Headings: ${summary.elements.headings}
|
||||||
|
║ • Paragraphs: ${summary.elements.paragraphs}
|
||||||
|
║ • Lists: ${summary.elements.lists}
|
||||||
|
║ • Code Blocks: ${summary.elements.code_blocks}
|
||||||
|
║ • Links: ${summary.elements.links}
|
||||||
|
║ Estimated Reading Time: ${summary.reading_time} min
|
||||||
|
╚════════════════════════════════════════════════════════════════╝
|
||||||
|
`);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: HTML 预览(如适用)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
if (config.target_format === 'HTML') {
|
||||||
|
// 生成完整 HTML 文件用于预览
|
||||||
|
const previewHtml = `<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Text Formatter Preview</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 2rem;
|
||||||
|
background: #f5f5f5;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
background: white;
|
||||||
|
padding: 2rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
h1, h2, h3, h4, h5, h6 { color: #333; margin-top: 1.5em; }
|
||||||
|
code { background: #f0f0f0; padding: 2px 6px; border-radius: 3px; }
|
||||||
|
pre { background: #282c34; color: #abb2bf; padding: 1rem; border-radius: 6px; overflow-x: auto; }
|
||||||
|
pre code { background: none; padding: 0; }
|
||||||
|
blockquote { border-left: 4px solid #ddd; margin: 0; padding-left: 1rem; color: #666; }
|
||||||
|
a { color: #0066cc; }
|
||||||
|
img { max-width: 100%; }
|
||||||
|
hr { border: none; border-top: 1px solid #ddd; margin: 2rem 0; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="content">
|
||||||
|
${formattedContent}
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>`;
|
||||||
|
|
||||||
|
Write(`${workDir}/preview.html`, previewHtml);
|
||||||
|
|
||||||
|
// 可选:在浏览器中打开预览
|
||||||
|
// Bash(`start "${workDir}/preview.html"`); // Windows
|
||||||
|
// Bash(`open "${workDir}/preview.html"`); // macOS
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: 显示输出内容
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 显示格式化后的内容
|
||||||
|
console.log('\n=== Formatted Content ===\n');
|
||||||
|
console.log(formattedContent);
|
||||||
|
console.log('\n=========================\n');
|
||||||
|
|
||||||
|
// 提示用户
|
||||||
|
console.log(`
|
||||||
|
📁 Output saved to: ${outputFile}
|
||||||
|
${config.target_format === 'HTML' ? '🌐 Preview available: ' + workDir + '/preview.html' : ''}
|
||||||
|
|
||||||
|
💡 Tips:
|
||||||
|
- Copy the content above for immediate use
|
||||||
|
- Or access the saved file at the path shown
|
||||||
|
`);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 5: 询问后续操作
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const nextAction = await AskUserQuestion({
|
||||||
|
questions: [
|
||||||
|
{
|
||||||
|
question: "需要执行什么操作?",
|
||||||
|
header: "后续操作",
|
||||||
|
multiSelect: false,
|
||||||
|
options: [
|
||||||
|
{ label: "完成", description: "结束格式化流程" },
|
||||||
|
{ label: "转换为其他格式", description: "选择另一种输出格式" },
|
||||||
|
{ label: "重新编辑", description: "修改原始内容后重新格式化" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
if (nextAction["后续操作"] === "转换为其他格式") {
|
||||||
|
// 返回 Phase 1 选择新格式
|
||||||
|
console.log('请重新运行 /text-formatter 选择其他格式');
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Output
|
||||||
|
|
||||||
|
- **File**: `output.{ext}` (最终输出)
|
||||||
|
- **File**: `preview.html` (HTML 预览,仅 HTML 格式)
|
||||||
|
- **Console**: 统计摘要和格式化内容
|
||||||
|
|
||||||
|
## Final Output Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
{workDir}/
|
||||||
|
├── input-config.json # 配置信息
|
||||||
|
├── analysis.json # 分析结果
|
||||||
|
├── output.md # Markdown 输出(如选择)
|
||||||
|
├── output.bbcode.txt # BBCode 输出(如选择)
|
||||||
|
├── output.html # HTML 输出(如选择)
|
||||||
|
└── preview.html # HTML 预览页面
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quality Checklist
|
||||||
|
|
||||||
|
- [ ] 输出文件已保存
|
||||||
|
- [ ] 统计信息正确显示
|
||||||
|
- [ ] 预览功能可用(HTML)
|
||||||
|
- [ ] 用户可访问输出内容
|
||||||
|
|
||||||
|
## Completion
|
||||||
|
|
||||||
|
此为最终阶段,格式化流程完成。
|
||||||
293
.claude/skills/text-formatter/specs/callout-types.md
Normal file
293
.claude/skills/text-formatter/specs/callout-types.md
Normal file
@@ -0,0 +1,293 @@
|
|||||||
|
# Callout Types
|
||||||
|
|
||||||
|
Obsidian 风格的 Callout/Admonition 类型定义和转换规则。
|
||||||
|
|
||||||
|
## When to Use
|
||||||
|
|
||||||
|
| Phase | Usage | Section |
|
||||||
|
|-------|-------|---------|
|
||||||
|
| Phase 2 | 检测 Callout | Detection patterns |
|
||||||
|
| Phase 3 | 格式转换 | Conversion rules |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Callout 语法
|
||||||
|
|
||||||
|
### Obsidian 原生语法
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
> [!TYPE] 可选标题
|
||||||
|
> 内容行1
|
||||||
|
> 内容行2
|
||||||
|
```
|
||||||
|
|
||||||
|
### 支持的类型
|
||||||
|
|
||||||
|
| Type | Alias | Icon | Color | 用途 |
|
||||||
|
|------|-------|------|-------|------|
|
||||||
|
| `note` | - | 📝 | blue | 普通提示 |
|
||||||
|
| `info` | - | ℹ️ | blue | 信息说明 |
|
||||||
|
| `tip` | `hint` | 💡 | green | 技巧提示 |
|
||||||
|
| `success` | `check`, `done` | ✅ | green | 成功状态 |
|
||||||
|
| `warning` | `caution`, `attention` | ⚠️ | orange | 警告信息 |
|
||||||
|
| `danger` | `error` | ❌ | red | 危险/错误 |
|
||||||
|
| `bug` | - | 🐛 | red | Bug 说明 |
|
||||||
|
| `example` | - | 📋 | purple | 示例内容 |
|
||||||
|
| `quote` | `cite` | 💬 | gray | 引用内容 |
|
||||||
|
| `abstract` | `summary`, `tldr` | 📄 | cyan | 摘要 |
|
||||||
|
| `question` | `help`, `faq` | ❓ | yellow | 问题/FAQ |
|
||||||
|
| `todo` | - | 📌 | orange | 待办事项 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 检测 Pattern
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Callout 检测正则
|
||||||
|
const CALLOUT_PATTERN = /^>\s*\[!(\w+)\](?:\s+(.+))?$/;
|
||||||
|
|
||||||
|
// 检测函数
|
||||||
|
function detectCallout(line) {
|
||||||
|
const match = line.match(CALLOUT_PATTERN);
|
||||||
|
if (match) {
|
||||||
|
return {
|
||||||
|
type: match[1].toLowerCase(),
|
||||||
|
title: match[2] || null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析完整 Callout 块
|
||||||
|
function parseCalloutBlock(lines, startIndex) {
|
||||||
|
const firstLine = lines[startIndex];
|
||||||
|
const calloutInfo = detectCallout(firstLine);
|
||||||
|
|
||||||
|
if (!calloutInfo) return null;
|
||||||
|
|
||||||
|
const content = [];
|
||||||
|
let i = startIndex + 1;
|
||||||
|
|
||||||
|
while (i < lines.length && lines[i].startsWith('>')) {
|
||||||
|
content.push(lines[i].replace(/^>\s*/, ''));
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...calloutInfo,
|
||||||
|
content: content.join('\n'),
|
||||||
|
endIndex: i - 1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 转换规则
|
||||||
|
|
||||||
|
### BBCode 转换
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const CALLOUT_BBCODE = {
|
||||||
|
note: {
|
||||||
|
icon: '📝',
|
||||||
|
color: '#2196F3',
|
||||||
|
label: '注意'
|
||||||
|
},
|
||||||
|
info: {
|
||||||
|
icon: 'ℹ️',
|
||||||
|
color: '#2196F3',
|
||||||
|
label: '信息'
|
||||||
|
},
|
||||||
|
tip: {
|
||||||
|
icon: '💡',
|
||||||
|
color: '#4CAF50',
|
||||||
|
label: '提示'
|
||||||
|
},
|
||||||
|
success: {
|
||||||
|
icon: '✅',
|
||||||
|
color: '#4CAF50',
|
||||||
|
label: '成功'
|
||||||
|
},
|
||||||
|
warning: {
|
||||||
|
icon: '⚠️',
|
||||||
|
color: '#FF9800',
|
||||||
|
label: '警告'
|
||||||
|
},
|
||||||
|
danger: {
|
||||||
|
icon: '❌',
|
||||||
|
color: '#F44336',
|
||||||
|
label: '危险'
|
||||||
|
},
|
||||||
|
bug: {
|
||||||
|
icon: '🐛',
|
||||||
|
color: '#F44336',
|
||||||
|
label: 'Bug'
|
||||||
|
},
|
||||||
|
example: {
|
||||||
|
icon: '📋',
|
||||||
|
color: '#9C27B0',
|
||||||
|
label: '示例'
|
||||||
|
},
|
||||||
|
quote: {
|
||||||
|
icon: '💬',
|
||||||
|
color: '#9E9E9E',
|
||||||
|
label: '引用'
|
||||||
|
},
|
||||||
|
question: {
|
||||||
|
icon: '❓',
|
||||||
|
color: '#FFEB3B',
|
||||||
|
label: '问题'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function calloutToBBCode(type, title, content, style = 'forum') {
|
||||||
|
const config = CALLOUT_BBCODE[type] || CALLOUT_BBCODE.note;
|
||||||
|
const displayTitle = title || config.label;
|
||||||
|
|
||||||
|
if (style === 'compact') {
|
||||||
|
return `[quote][b]${config.icon} ${displayTitle}[/b]
|
||||||
|
${content}[/quote]`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forum style - more visual
|
||||||
|
return `[quote]
|
||||||
|
[color=${config.color}][size=4][b]${config.icon} ${displayTitle}[/b][/size][/color]
|
||||||
|
|
||||||
|
${content}
|
||||||
|
[/quote]`;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### HTML 转换
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
function calloutToHTML(type, title, content) {
|
||||||
|
const config = CALLOUT_BBCODE[type] || CALLOUT_BBCODE.note;
|
||||||
|
const displayTitle = title || config.label;
|
||||||
|
|
||||||
|
return `<div class="callout callout-${type}">
|
||||||
|
<div class="callout-title">
|
||||||
|
<span class="callout-icon">${config.icon}</span>
|
||||||
|
<span class="callout-title-text">${displayTitle}</span>
|
||||||
|
</div>
|
||||||
|
<div class="callout-content">
|
||||||
|
${content}
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Hybrid 转换
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
function calloutToHybrid(type, title, content) {
|
||||||
|
const config = CALLOUT_BBCODE[type] || CALLOUT_BBCODE.note;
|
||||||
|
const displayTitle = title || config.label;
|
||||||
|
|
||||||
|
// HTML container + BBCode styling + MD content
|
||||||
|
return `<div class="callout ${type}">
|
||||||
|
|
||||||
|
[color=${config.color}][b]${config.icon} ${displayTitle}[/b][/color]
|
||||||
|
|
||||||
|
${content}
|
||||||
|
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Callout CSS 样式
|
||||||
|
|
||||||
|
```css
|
||||||
|
/* Base callout styles */
|
||||||
|
.callout {
|
||||||
|
padding: 1rem;
|
||||||
|
margin: 1rem 0;
|
||||||
|
border-left: 4px solid;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #f8f9fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.callout-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.callout-icon {
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Type-specific colors */
|
||||||
|
.callout-note, .callout-info {
|
||||||
|
border-color: #2196F3;
|
||||||
|
background: #E3F2FD;
|
||||||
|
}
|
||||||
|
|
||||||
|
.callout-tip, .callout-success {
|
||||||
|
border-color: #4CAF50;
|
||||||
|
background: #E8F5E9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.callout-warning {
|
||||||
|
border-color: #FF9800;
|
||||||
|
background: #FFF3E0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.callout-danger, .callout-bug {
|
||||||
|
border-color: #F44336;
|
||||||
|
background: #FFEBEE;
|
||||||
|
}
|
||||||
|
|
||||||
|
.callout-example {
|
||||||
|
border-color: #9C27B0;
|
||||||
|
background: #F3E5F5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.callout-quote {
|
||||||
|
border-color: #9E9E9E;
|
||||||
|
background: #FAFAFA;
|
||||||
|
}
|
||||||
|
|
||||||
|
.callout-question {
|
||||||
|
border-color: #FFC107;
|
||||||
|
background: #FFFDE7;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 折叠 Callout
|
||||||
|
|
||||||
|
支持可折叠的 Callout 语法:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
> [!NOTE]+ 默认展开
|
||||||
|
> 内容
|
||||||
|
|
||||||
|
> [!NOTE]- 默认折叠
|
||||||
|
> 内容
|
||||||
|
```
|
||||||
|
|
||||||
|
### BBCode 折叠
|
||||||
|
|
||||||
|
```bbcode
|
||||||
|
[collapse=📝 注意]
|
||||||
|
内容
|
||||||
|
[/collapse]
|
||||||
|
```
|
||||||
|
|
||||||
|
### HTML 折叠
|
||||||
|
|
||||||
|
```html
|
||||||
|
<details class="callout callout-note">
|
||||||
|
<summary>📝 注意</summary>
|
||||||
|
<div class="callout-content">
|
||||||
|
内容
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
```
|
||||||
209
.claude/skills/text-formatter/specs/element-mapping.md
Normal file
209
.claude/skills/text-formatter/specs/element-mapping.md
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
# Element Mapping
|
||||||
|
|
||||||
|
内容元素到 BBCode + Markdown 混合格式的映射表。
|
||||||
|
|
||||||
|
## When to Use
|
||||||
|
|
||||||
|
| Phase | Usage | Section |
|
||||||
|
|-------|-------|---------|
|
||||||
|
| Phase 2 | 元素识别 | Detection patterns |
|
||||||
|
| Phase 3 | 格式转换 | Conversion rules |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Element Detection Patterns
|
||||||
|
|
||||||
|
### 标题检测
|
||||||
|
|
||||||
|
| 类型 | Pattern | 示例 |
|
||||||
|
|------|---------|------|
|
||||||
|
| ATX 标题 | `/^#{1,6}\s+(.+)$/` | `# Title`, `## Subtitle` |
|
||||||
|
| Setext H1 | `/^(.+)\n={3,}$/` | `Title\n====` |
|
||||||
|
| Setext H2 | `/^(.+)\n-{3,}$/` | `Subtitle\n----` |
|
||||||
|
|
||||||
|
### 列表检测
|
||||||
|
|
||||||
|
| 类型 | Pattern | 示例 |
|
||||||
|
|------|---------|------|
|
||||||
|
| 无序列表 | `/^[\s]*[-*+]\s+(.+)$/` | `- item`, `* item` |
|
||||||
|
| 有序列表 | `/^[\s]*\d+\.\s+(.+)$/` | `1. item`, `2. item` |
|
||||||
|
| 任务列表 | `/^[\s]*[-*]\s+\[([ x])\]\s+(.+)$/` | `- [ ] todo`, `- [x] done` |
|
||||||
|
|
||||||
|
### Callout 检测
|
||||||
|
|
||||||
|
| 类型 | Pattern | 示例 |
|
||||||
|
|------|---------|------|
|
||||||
|
| Callout 开始 | `/^>\s*\[!(\w+)\](?:\s+(.+))?$/` | `> [!NOTE] 标题` |
|
||||||
|
| Callout 内容 | `/^>\s*(.*)$/` | `> 内容行` |
|
||||||
|
| 可折叠展开 | `/^>\s*\[!(\w+)\]\+/` | `> [!NOTE]+` |
|
||||||
|
| 可折叠收起 | `/^>\s*\[!(\w+)\]-/` | `> [!NOTE]-` |
|
||||||
|
|
||||||
|
### 代码检测
|
||||||
|
|
||||||
|
| 类型 | Pattern | 示例 |
|
||||||
|
|------|---------|------|
|
||||||
|
| 代码块开始 | `/^```(\w*)$/` | ` ```js ` |
|
||||||
|
| 代码块结束 | `/^```$/` | ` ``` ` |
|
||||||
|
| 行内代码 | `/`([^`]+)`/` | `` `code` `` |
|
||||||
|
|
||||||
|
### 其他元素
|
||||||
|
|
||||||
|
| 类型 | Pattern | 示例 |
|
||||||
|
|------|---------|------|
|
||||||
|
| 链接 | `/\[([^\]]+)\]\(([^)]+)\)/` | `[text](url)` |
|
||||||
|
| 图片 | `/!\[([^\]]*)\]\(([^)]+)\)/` | `` |
|
||||||
|
| 普通引用 | `/^>\s+(.+)$/` | `> quote` |
|
||||||
|
| 分隔线 | `/^[-*_]{3,}$/` | `---`, `***` |
|
||||||
|
| 高亮 | `/==(.+?)==/` | `==highlight==` |
|
||||||
|
| 粗体 | `/\*\*(.+?)\*\*/` | `**bold**` |
|
||||||
|
| 斜体 | `/\*(.+?)\*/` | `*italic*` |
|
||||||
|
| 删除线 | `/~~(.+?)~~/` | `~~strike~~` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Element Conversion Matrix
|
||||||
|
|
||||||
|
### 标题映射 (Pixel-Based)
|
||||||
|
|
||||||
|
| Element | Markdown | BBCode Output |
|
||||||
|
|---------|----------|---------------|
|
||||||
|
| **H1** | `# text` | `[size=150][color=#2196F3][b]text[/b][/color][/size]` |
|
||||||
|
| **H2** | `## text` | `[size=120][color=#2196F3][b]text[/b][/color][/size]` |
|
||||||
|
| **H3** | `### text` | `[size=100][color=#333][b]text[/b][/color][/size]` |
|
||||||
|
| **H4** | `#### text` | `[b]text[/b]` |
|
||||||
|
| **H5** | `##### text` | `[b]text[/b]` |
|
||||||
|
| **H6** | `###### text` | `[b]text[/b]` |
|
||||||
|
|
||||||
|
### 文本样式映射
|
||||||
|
|
||||||
|
| Element | Markdown | BBCode |
|
||||||
|
|---------|----------|--------|
|
||||||
|
| **Bold** | `**text**` | `[b]text[/b]` |
|
||||||
|
| **Italic** | `*text*` | `[i]text[/i]` |
|
||||||
|
| **Bold+Italic** | `***text***` | `[b][i]text[/i][/b]` |
|
||||||
|
| **Strike** | `~~text~~` | `[s]text[/s]` |
|
||||||
|
| **Highlight** | `==text==` | `[color=yellow]text[/color]` |
|
||||||
|
| **Code (inline)** | `` `text` `` | 保持原样 |
|
||||||
|
|
||||||
|
### 块级元素映射
|
||||||
|
|
||||||
|
| Element | Markdown | BBCode |
|
||||||
|
|---------|----------|--------|
|
||||||
|
| **Code Block** | ` ```lang\ncode\n``` ` | `[code]code[/code]` |
|
||||||
|
| **Quote** | `> text` | `[quote]text[/quote]` |
|
||||||
|
| **HR** | `---` | `---` (保持 Markdown) |
|
||||||
|
| **List Item** | `- text` | `• text` |
|
||||||
|
| **Paragraph** | `text\n\ntext` | `text\n\ntext` |
|
||||||
|
|
||||||
|
### 链接和媒体映射
|
||||||
|
|
||||||
|
| Element | Markdown | BBCode |
|
||||||
|
|---------|----------|--------|
|
||||||
|
| **Link** | `[text](url)` | `[url=url]text[/url]` |
|
||||||
|
| **Image** | `` | `[img]url[/img]` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Callout Mapping
|
||||||
|
|
||||||
|
### 类型到样式映射
|
||||||
|
|
||||||
|
| Callout Type | Color | Icon | Label |
|
||||||
|
|--------------|-------|------|-------|
|
||||||
|
| note | #2196F3 | 📝 | 注意 |
|
||||||
|
| info | #2196F3 | ℹ️ | 信息 |
|
||||||
|
| tip | #4CAF50 | 💡 | 提示 |
|
||||||
|
| hint | #4CAF50 | 💡 | 提示 |
|
||||||
|
| success | #4CAF50 | ✅ | 成功 |
|
||||||
|
| check | #4CAF50 | ✅ | 完成 |
|
||||||
|
| done | #4CAF50 | ✅ | 完成 |
|
||||||
|
| warning | #FF9800 | ⚠️ | 警告 |
|
||||||
|
| caution | #FF9800 | ⚠️ | 注意 |
|
||||||
|
| attention | #FF9800 | ⚠️ | 注意 |
|
||||||
|
| danger | #F44336 | ❌ | 危险 |
|
||||||
|
| error | #F44336 | ❌ | 错误 |
|
||||||
|
| bug | #F44336 | 🐛 | Bug |
|
||||||
|
| example | #9C27B0 | 📋 | 示例 |
|
||||||
|
| question | #FF9800 | ❓ | 问题 |
|
||||||
|
| help | #FF9800 | ❓ | 帮助 |
|
||||||
|
| faq | #FF9800 | ❓ | FAQ |
|
||||||
|
| quote | gray | 💬 | 引用 |
|
||||||
|
| cite | gray | 💬 | 引用 |
|
||||||
|
| abstract | #2196F3 | 📄 | 摘要 |
|
||||||
|
| summary | #2196F3 | 📄 | 摘要 |
|
||||||
|
| tldr | #2196F3 | 📄 | 摘要 |
|
||||||
|
| todo | #FF9800 | 📋 | 待办 |
|
||||||
|
| important | #F44336 | ⭐ | 重要 |
|
||||||
|
|
||||||
|
### Callout 输出模板
|
||||||
|
|
||||||
|
```bbcode
|
||||||
|
[quote]
|
||||||
|
[size=100][color={color}][b]{icon} {title}[/b][/color][/size]
|
||||||
|
|
||||||
|
{content}
|
||||||
|
[/quote]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Unsupported Elements
|
||||||
|
|
||||||
|
### 不支持转换的元素
|
||||||
|
|
||||||
|
| 元素 | 原因 | 降级方案 |
|
||||||
|
|------|------|----------|
|
||||||
|
| 表格 | BBCode 表格支持有限 | 转为代码块或列表 |
|
||||||
|
| 脚注 | 不支持 | 转为括号注释 `(注: ...)` |
|
||||||
|
| 数学公式 | 不支持 | 保留原始文本 |
|
||||||
|
| 嵌入内容 | 不支持 | 转为链接 |
|
||||||
|
| 任务列表 | 复选框不支持 | 转为普通列表 `☐`/`☑` |
|
||||||
|
|
||||||
|
### 降级示例
|
||||||
|
|
||||||
|
**表格**:
|
||||||
|
```
|
||||||
|
| A | B |
|
||||||
|
|---|---|
|
||||||
|
| 1 | 2 |
|
||||||
|
|
||||||
|
→ 降级为:
|
||||||
|
|
||||||
|
A: 1
|
||||||
|
B: 2
|
||||||
|
```
|
||||||
|
|
||||||
|
**脚注**:
|
||||||
|
```
|
||||||
|
文本[^1]
|
||||||
|
|
||||||
|
[^1]: 脚注内容
|
||||||
|
|
||||||
|
→ 降级为:
|
||||||
|
|
||||||
|
文本 (注: 脚注内容)
|
||||||
|
```
|
||||||
|
|
||||||
|
**任务列表**:
|
||||||
|
```
|
||||||
|
- [ ] 待办
|
||||||
|
- [x] 已完成
|
||||||
|
|
||||||
|
→ 降级为:
|
||||||
|
|
||||||
|
☐ 待办
|
||||||
|
☑ 已完成
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Validation Rules
|
||||||
|
|
||||||
|
### 转换验证
|
||||||
|
|
||||||
|
- [ ] 所有 H1-H3 使用像素值 size (150/120/100)
|
||||||
|
- [ ] 未使用 `[align]` 标签
|
||||||
|
- [ ] 未使用 `[hr]` 标签
|
||||||
|
- [ ] 分隔线保持 `---`
|
||||||
|
- [ ] Callout 正确识别并转换
|
||||||
|
- [ ] 颜色值使用 hex 格式
|
||||||
260
.claude/skills/text-formatter/specs/format-rules.md
Normal file
260
.claude/skills/text-formatter/specs/format-rules.md
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
# Format Conversion Rules
|
||||||
|
|
||||||
|
BBCode + Markdown 混合格式转换规则(论坛优化)。
|
||||||
|
|
||||||
|
## When to Use
|
||||||
|
|
||||||
|
| Phase | Usage | Section |
|
||||||
|
|-------|-------|---------|
|
||||||
|
| Phase 3 | 格式转换 | All sections |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Core Principles
|
||||||
|
|
||||||
|
### 1. Pixel-Based Sizing
|
||||||
|
|
||||||
|
**重要**: 使用像素值而非 1-7 级别
|
||||||
|
|
||||||
|
| 元素 | Size (px) | 说明 |
|
||||||
|
|------|-----------|------|
|
||||||
|
| 主标题 (H1) | 150 | 文档标题 |
|
||||||
|
| 章节标题 (H2) | 120 | 主要章节 |
|
||||||
|
| 子标题 (H3) | 100 | 子章节 |
|
||||||
|
| 正文 | (默认) | 不指定 size |
|
||||||
|
| 备注/灰色 | 80 | 脚注、元数据 |
|
||||||
|
|
||||||
|
### 2. Supported Tags Only
|
||||||
|
|
||||||
|
**支持的 BBCode 标签**:
|
||||||
|
- `[size=N]` - 字号(像素值)
|
||||||
|
- `[color=X]` - 颜色(hex 或名称)
|
||||||
|
- `[b]`, `[i]`, `[s]` - 粗体、斜体、删除线
|
||||||
|
- `[quote]` - 引用块
|
||||||
|
- `[code]` - 代码块
|
||||||
|
- `[url]`, `[img]` - 链接、图片
|
||||||
|
- `[list]`, `[*]` - 列表
|
||||||
|
|
||||||
|
**禁止使用的标签**:
|
||||||
|
- `[align]` - 不渲染,显示为文本
|
||||||
|
- `[hr]` - 不渲染,使用 Markdown `---`
|
||||||
|
- `[table]` - 支持有限,避免使用
|
||||||
|
- HTML 标签 (`<div>`, `<span>`) - 不支持
|
||||||
|
|
||||||
|
### 3. Markdown as Separator
|
||||||
|
|
||||||
|
分隔线使用 Markdown 语法:`---`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Element Conversion Rules
|
||||||
|
|
||||||
|
### 标题转换
|
||||||
|
|
||||||
|
| Markdown | BBCode Output |
|
||||||
|
|----------|---------------|
|
||||||
|
| `# H1` | `[size=150][color=#2196F3][b]H1[/b][/color][/size]` |
|
||||||
|
| `## H2` | `[size=120][color=#2196F3][b]H2[/b][/color][/size]` |
|
||||||
|
| `### H3` | `[size=100][color=#333][b]H3[/b][/color][/size]` |
|
||||||
|
| `#### H4+` | `[b]H4[/b]` (不加 size) |
|
||||||
|
|
||||||
|
### 文本样式
|
||||||
|
|
||||||
|
| Markdown | BBCode |
|
||||||
|
|----------|--------|
|
||||||
|
| `**bold**` | `[b]bold[/b]` |
|
||||||
|
| `*italic*` | `[i]italic[/i]` |
|
||||||
|
| `***both***` | `[b][i]both[/i][/b]` |
|
||||||
|
| `~~strike~~` | `[s]strike[/s]` |
|
||||||
|
| `==highlight==` | `[color=yellow]highlight[/color]` |
|
||||||
|
|
||||||
|
### 代码
|
||||||
|
|
||||||
|
| Markdown | BBCode |
|
||||||
|
|----------|--------|
|
||||||
|
| `` `inline` `` | 保持原样或 `[color=#9C27B0]inline[/color]` |
|
||||||
|
| ` ```code``` ` | `[code]code[/code]` |
|
||||||
|
|
||||||
|
### 链接和图片
|
||||||
|
|
||||||
|
| Markdown | BBCode |
|
||||||
|
|----------|--------|
|
||||||
|
| `[text](url)` | `[url=url]text[/url]` |
|
||||||
|
| `` | `[img]url[/img]` |
|
||||||
|
|
||||||
|
### 列表
|
||||||
|
|
||||||
|
```
|
||||||
|
Markdown:
|
||||||
|
- item 1
|
||||||
|
- item 2
|
||||||
|
- nested
|
||||||
|
|
||||||
|
BBCode:
|
||||||
|
• item 1
|
||||||
|
• item 2
|
||||||
|
• nested
|
||||||
|
```
|
||||||
|
|
||||||
|
注意:使用 `•` 符号而非 `[list][*]`,因为部分论坛渲染有问题。
|
||||||
|
|
||||||
|
### 引用
|
||||||
|
|
||||||
|
```
|
||||||
|
Markdown:
|
||||||
|
> quote text
|
||||||
|
|
||||||
|
BBCode:
|
||||||
|
[quote]
|
||||||
|
quote text
|
||||||
|
[/quote]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Callout (标注) 转换
|
||||||
|
|
||||||
|
### Obsidian Callout 语法
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
> [!TYPE] 可选标题
|
||||||
|
> 内容行 1
|
||||||
|
> 内容行 2
|
||||||
|
```
|
||||||
|
|
||||||
|
### 支持的 Callout 类型
|
||||||
|
|
||||||
|
| Type | Color | Icon | 中文标签 |
|
||||||
|
|------|-------|------|----------|
|
||||||
|
| note, info | #2196F3 | 📝 | 注意 / 信息 |
|
||||||
|
| tip, hint | #4CAF50 | 💡 | 提示 |
|
||||||
|
| success, check, done | #4CAF50 | ✅ | 成功 |
|
||||||
|
| warning, caution, attention | #FF9800 | ⚠️ | 警告 |
|
||||||
|
| danger, error, bug | #F44336 | ❌ | 危险 / 错误 |
|
||||||
|
| example | #9C27B0 | 📋 | 示例 |
|
||||||
|
| question, help, faq | #FF9800 | ❓ | 问题 |
|
||||||
|
| quote, cite | gray | 💬 | 引用 |
|
||||||
|
| abstract, summary, tldr | #2196F3 | 📄 | 摘要 |
|
||||||
|
|
||||||
|
### Callout 转换模板
|
||||||
|
|
||||||
|
```bbcode
|
||||||
|
[quote]
|
||||||
|
[size=100][color={color}][b]{icon} {title}[/b][/color][/size]
|
||||||
|
|
||||||
|
{content}
|
||||||
|
[/quote]
|
||||||
|
```
|
||||||
|
|
||||||
|
**示例**:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
> [!WARNING] 注意事项
|
||||||
|
> 这是警告内容
|
||||||
|
```
|
||||||
|
|
||||||
|
转换为:
|
||||||
|
|
||||||
|
```bbcode
|
||||||
|
[quote]
|
||||||
|
[size=100][color=#FF9800][b]⚠️ 注意事项[/b][/color][/size]
|
||||||
|
|
||||||
|
这是警告内容
|
||||||
|
[/quote]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 可折叠 Callout
|
||||||
|
|
||||||
|
Obsidian 支持 `> [!NOTE]+` (展开) 和 `> [!NOTE]-` (折叠)。
|
||||||
|
|
||||||
|
由于 BBCode 不支持折叠,统一转换为普通 quote。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Color Palette
|
||||||
|
|
||||||
|
### 语义颜色
|
||||||
|
|
||||||
|
| 语义 | Hex | 使用场景 |
|
||||||
|
|------|-----|----------|
|
||||||
|
| Primary | #2196F3 | 标题、链接、信息 |
|
||||||
|
| Success | #4CAF50 | 成功、提示、特性 |
|
||||||
|
| Warning | #FF9800 | 警告、注意 |
|
||||||
|
| Error | #F44336 | 错误、危险 |
|
||||||
|
| Purple | #9C27B0 | 示例、代码 |
|
||||||
|
| Gray | gray | 备注、元数据 |
|
||||||
|
| Dark | #333 | 子标题 |
|
||||||
|
|
||||||
|
### 颜色使用规则
|
||||||
|
|
||||||
|
1. **标题颜色**: H1/H2 使用 #2196F3,H3 使用 #333
|
||||||
|
2. **Callout 颜色**: 根据类型使用语义颜色
|
||||||
|
3. **备注颜色**: 使用 gray
|
||||||
|
4. **强调颜色**: 根据语义选择(成功用绿色,警告用橙色)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Spacing Rules
|
||||||
|
|
||||||
|
### 空行控制
|
||||||
|
|
||||||
|
| 元素 | 前空行 | 后空行 |
|
||||||
|
|------|--------|--------|
|
||||||
|
| 标题 | 1 | 1 |
|
||||||
|
| 段落 | 0 | 1 |
|
||||||
|
| 列表 | 0 | 1 |
|
||||||
|
| 代码块 | 1 | 1 |
|
||||||
|
| Callout | 1 | 1 |
|
||||||
|
| 分隔线 `---` | 1 | 1 |
|
||||||
|
|
||||||
|
### 示例输出结构
|
||||||
|
|
||||||
|
```bbcode
|
||||||
|
[size=150][color=#2196F3][b]文档标题[/b][/color][/size]
|
||||||
|
|
||||||
|
[size=80][color=gray]作者 | 日期[/color][/size]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[size=120][color=#2196F3][b]第一章节[/b][/color][/size]
|
||||||
|
|
||||||
|
正文内容...
|
||||||
|
|
||||||
|
[quote]
|
||||||
|
[size=100][color=#4CAF50][b]💡 提示[/b][/color][/size]
|
||||||
|
|
||||||
|
提示内容
|
||||||
|
[/quote]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[size=120][color=#2196F3][b]第二章节[/b][/color][/size]
|
||||||
|
|
||||||
|
更多内容...
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[size=80][color=gray]— 全文完 —[/color][/size]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quality Checklist
|
||||||
|
|
||||||
|
### 转换完整性
|
||||||
|
|
||||||
|
- [ ] 所有标题使用像素值 size
|
||||||
|
- [ ] 未使用 `[align]` 或 `[hr]`
|
||||||
|
- [ ] 分隔线使用 `---`
|
||||||
|
- [ ] Callout 正确转换为 quote
|
||||||
|
- [ ] 颜色符合语义规范
|
||||||
|
- [ ] 空行控制正确
|
||||||
|
|
||||||
|
### 常见错误
|
||||||
|
|
||||||
|
| 错误 | 正确做法 |
|
||||||
|
|------|----------|
|
||||||
|
| `[size=5]` | `[size=120]` |
|
||||||
|
| `[align=center]` | 删除,默认左对齐 |
|
||||||
|
| `[hr]` | 使用 `---` |
|
||||||
|
| `<div class="...">` | 删除 HTML 标签 |
|
||||||
350
.claude/skills/text-formatter/templates/bbcode-template.md
Normal file
350
.claude/skills/text-formatter/templates/bbcode-template.md
Normal file
@@ -0,0 +1,350 @@
|
|||||||
|
# BBCode Template
|
||||||
|
|
||||||
|
论坛优化的 BBCode + Markdown 混合模板(像素级字号)。
|
||||||
|
|
||||||
|
## 核心规则
|
||||||
|
|
||||||
|
### 字号体系 (Pixels)
|
||||||
|
|
||||||
|
| 元素 | Size | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| 主标题 | 150 | 文档标题 |
|
||||||
|
| 章节标题 | 120 | H2 级别 |
|
||||||
|
| 子标题 | 100 | H3 级别 |
|
||||||
|
| 正文 | (默认) | 不指定 |
|
||||||
|
| 备注 | 80 | 灰色小字 |
|
||||||
|
|
||||||
|
### 禁止使用
|
||||||
|
|
||||||
|
- `[align]` - 不渲染
|
||||||
|
- `[hr]` - 不渲染,用 `---`
|
||||||
|
- `[table]` - 支持有限
|
||||||
|
- HTML 标签
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 文档模板
|
||||||
|
|
||||||
|
### 基础文档结构
|
||||||
|
|
||||||
|
```bbcode
|
||||||
|
[size=150][color=#2196F3][b]{{title}}[/b][/color][/size]
|
||||||
|
|
||||||
|
[size=80][color=gray]{{metadata}}[/color][/size]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
{{introduction}}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[size=120][color=#2196F3][b]{{section1_title}}[/b][/color][/size]
|
||||||
|
|
||||||
|
{{section1_content}}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[size=120][color=#2196F3][b]{{section2_title}}[/b][/color][/size]
|
||||||
|
|
||||||
|
{{section2_content}}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[size=80][color=gray]— 全文完 —[/color][/size]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 带目录的文档
|
||||||
|
|
||||||
|
```bbcode
|
||||||
|
[size=150][color=#2196F3][b]{{title}}[/b][/color][/size]
|
||||||
|
|
||||||
|
[size=80][color=gray]{{author}} | {{date}}[/color][/size]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[size=100][b]📋 目录[/b][/size]
|
||||||
|
|
||||||
|
• {{section1_title}}
|
||||||
|
• {{section2_title}}
|
||||||
|
• {{section3_title}}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[size=120][color=#2196F3][b]{{section1_title}}[/b][/color][/size]
|
||||||
|
|
||||||
|
{{section1_content}}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[size=120][color=#2196F3][b]{{section2_title}}[/b][/color][/size]
|
||||||
|
|
||||||
|
{{section2_content}}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[size=120][color=#2196F3][b]{{section3_title}}[/b][/color][/size]
|
||||||
|
|
||||||
|
{{section3_content}}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[size=80][color=gray]— 全文完 —[/color][/size]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Callout 模板
|
||||||
|
|
||||||
|
### 提示 (Note/Info)
|
||||||
|
|
||||||
|
```bbcode
|
||||||
|
[quote]
|
||||||
|
[size=100][color=#2196F3][b]📝 {{title}}[/b][/color][/size]
|
||||||
|
|
||||||
|
{{content}}
|
||||||
|
[/quote]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 技巧 (Tip/Hint)
|
||||||
|
|
||||||
|
```bbcode
|
||||||
|
[quote]
|
||||||
|
[size=100][color=#4CAF50][b]💡 {{title}}[/b][/color][/size]
|
||||||
|
|
||||||
|
{{content}}
|
||||||
|
[/quote]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 成功 (Success)
|
||||||
|
|
||||||
|
```bbcode
|
||||||
|
[quote]
|
||||||
|
[size=100][color=#4CAF50][b]✅ {{title}}[/b][/color][/size]
|
||||||
|
|
||||||
|
{{content}}
|
||||||
|
[/quote]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 警告 (Warning/Caution)
|
||||||
|
|
||||||
|
```bbcode
|
||||||
|
[quote]
|
||||||
|
[size=100][color=#FF9800][b]⚠️ {{title}}[/b][/color][/size]
|
||||||
|
|
||||||
|
{{content}}
|
||||||
|
[/quote]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 危险/错误 (Danger/Error)
|
||||||
|
|
||||||
|
```bbcode
|
||||||
|
[quote]
|
||||||
|
[size=100][color=#F44336][b]❌ {{title}}[/b][/color][/size]
|
||||||
|
|
||||||
|
{{content}}
|
||||||
|
[/quote]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 示例 (Example)
|
||||||
|
|
||||||
|
```bbcode
|
||||||
|
[quote]
|
||||||
|
[size=100][color=#9C27B0][b]📋 {{title}}[/b][/color][/size]
|
||||||
|
|
||||||
|
{{content}}
|
||||||
|
[/quote]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 问题 (Question/FAQ)
|
||||||
|
|
||||||
|
```bbcode
|
||||||
|
[quote]
|
||||||
|
[size=100][color=#FF9800][b]❓ {{title}}[/b][/color][/size]
|
||||||
|
|
||||||
|
{{content}}
|
||||||
|
[/quote]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 重要 (Important)
|
||||||
|
|
||||||
|
```bbcode
|
||||||
|
[quote]
|
||||||
|
[size=100][color=#F44336][b]⭐ {{title}}[/b][/color][/size]
|
||||||
|
|
||||||
|
{{content}}
|
||||||
|
[/quote]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 代码展示模板
|
||||||
|
|
||||||
|
### 单代码块
|
||||||
|
|
||||||
|
```bbcode
|
||||||
|
[size=100][color=#9C27B0][b]代码示例[/b][/color][/size]
|
||||||
|
|
||||||
|
[code]
|
||||||
|
{{code}}
|
||||||
|
[/code]
|
||||||
|
|
||||||
|
[size=80][color=gray]说明: {{description}}[/color][/size]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 带标题的代码
|
||||||
|
|
||||||
|
```bbcode
|
||||||
|
[size=100][b]{{code_title}}[/b][/size]
|
||||||
|
|
||||||
|
[code]
|
||||||
|
{{code}}
|
||||||
|
[/code]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 特性展示模板
|
||||||
|
|
||||||
|
### 特性列表
|
||||||
|
|
||||||
|
```bbcode
|
||||||
|
[size=120][color=#2196F3][b]功能特性[/b][/color][/size]
|
||||||
|
|
||||||
|
• [color=#4CAF50][b]✨ {{feature1}}[/b][/color] — {{desc1}}
|
||||||
|
• [color=#2196F3][b]🚀 {{feature2}}[/b][/color] — {{desc2}}
|
||||||
|
• [color=#FF9800][b]⚡ {{feature3}}[/b][/color] — {{desc3}}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 详细特性卡片
|
||||||
|
|
||||||
|
```bbcode
|
||||||
|
[size=120][color=#2196F3][b]功能特性[/b][/color][/size]
|
||||||
|
|
||||||
|
[quote]
|
||||||
|
[size=100][color=#4CAF50][b]✨ {{feature1_title}}[/b][/color][/size]
|
||||||
|
|
||||||
|
{{feature1_description}}
|
||||||
|
|
||||||
|
[size=80][color=gray]适用场景: {{feature1_use_case}}[/color][/size]
|
||||||
|
[/quote]
|
||||||
|
|
||||||
|
[quote]
|
||||||
|
[size=100][color=#2196F3][b]🚀 {{feature2_title}}[/b][/color][/size]
|
||||||
|
|
||||||
|
{{feature2_description}}
|
||||||
|
|
||||||
|
[size=80][color=gray]适用场景: {{feature2_use_case}}[/color][/size]
|
||||||
|
[/quote]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 步骤指南模板
|
||||||
|
|
||||||
|
```bbcode
|
||||||
|
[size=120][color=#2196F3][b]操作步骤[/b][/color][/size]
|
||||||
|
|
||||||
|
[size=100][color=#2196F3][b]步骤 1: {{step1_title}}[/b][/color][/size]
|
||||||
|
|
||||||
|
{{step1_content}}
|
||||||
|
|
||||||
|
[quote]
|
||||||
|
[size=100][color=#FF9800][b]💡 提示[/b][/color][/size]
|
||||||
|
|
||||||
|
{{step1_tip}}
|
||||||
|
[/quote]
|
||||||
|
|
||||||
|
[size=100][color=#2196F3][b]步骤 2: {{step2_title}}[/b][/color][/size]
|
||||||
|
|
||||||
|
{{step2_content}}
|
||||||
|
|
||||||
|
[size=100][color=#2196F3][b]步骤 3: {{step3_title}}[/b][/color][/size]
|
||||||
|
|
||||||
|
{{step3_content}}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[color=#4CAF50][b]✅ 完成![/b][/color] {{completion_message}}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 版本更新模板
|
||||||
|
|
||||||
|
```bbcode
|
||||||
|
[size=150][color=#673AB7][b]🎉 版本 {{version}} 更新日志[/b][/color][/size]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[size=120][color=#4CAF50][b]✨ 新功能[/b][/color][/size]
|
||||||
|
|
||||||
|
• [b]{{new_feature1}}[/b]: {{new_feature1_desc}}
|
||||||
|
• [b]{{new_feature2}}[/b]: {{new_feature2_desc}}
|
||||||
|
|
||||||
|
[size=120][color=#2196F3][b]🔧 改进[/b][/color][/size]
|
||||||
|
|
||||||
|
• {{improvement1}}
|
||||||
|
• {{improvement2}}
|
||||||
|
|
||||||
|
[size=120][color=#F44336][b]🐛 修复[/b][/color][/size]
|
||||||
|
|
||||||
|
• {{bugfix1}}
|
||||||
|
• {{bugfix2}}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[url={{download_url}}][b]📥 立即下载[/b][/url]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## FAQ 模板
|
||||||
|
|
||||||
|
```bbcode
|
||||||
|
[size=120][color=#2196F3][b]❓ 常见问题[/b][/color][/size]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[size=100][color=#333][b]Q: {{question1}}[/b][/color][/size]
|
||||||
|
|
||||||
|
[b]A:[/b] {{answer1}}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[size=100][color=#333][b]Q: {{question2}}[/b][/color][/size]
|
||||||
|
|
||||||
|
[b]A:[/b] {{answer2}}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[size=100][color=#333][b]Q: {{question3}}[/b][/color][/size]
|
||||||
|
|
||||||
|
[b]A:[/b] {{answer3}}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 转换检查清单
|
||||||
|
|
||||||
|
### 必须检查
|
||||||
|
|
||||||
|
- [ ] 标题使用像素值 (150/120/100)
|
||||||
|
- [ ] 分隔线使用 `---`
|
||||||
|
- [ ] 未使用 `[align]`
|
||||||
|
- [ ] 未使用 `[hr]`
|
||||||
|
- [ ] 未使用 HTML 标签
|
||||||
|
- [ ] Callout 标题 size=100
|
||||||
|
- [ ] 灰色备注 size=80
|
||||||
|
|
||||||
|
### 颜色规范
|
||||||
|
|
||||||
|
| 用途 | 颜色 |
|
||||||
|
|------|------|
|
||||||
|
| 主标题 | #2196F3 |
|
||||||
|
| 章节标题 | #2196F3 |
|
||||||
|
| 子标题 | #333 |
|
||||||
|
| 成功/提示 | #4CAF50 |
|
||||||
|
| 警告 | #FF9800 |
|
||||||
|
| 错误/危险 | #F44336 |
|
||||||
|
| 示例 | #9C27B0 |
|
||||||
|
| 备注 | gray |
|
||||||
Reference in New Issue
Block a user