Back to skills
SKILL.md
Teaching Handbook
ASecurity將 Word (.docx)、Markdown (.md) 或 PowerPoint (.pptx) 教學講義轉成「側邊欄導航風格」的高畫質 HTML 網頁。使用時機:使用者說「上架教材」「上架講義」「教材轉網頁」「講義轉網頁」「轉成側邊欄導航風格」「轉成側邊欄網頁」「把這份 .docx/.md/.pptx 轉 HTML」,或提供 .docx/.md/.pptx 檔案並要求產出教學網頁時。產出包含固定側邊欄目錄、Scroll Spy、字體縮放、程式碼複製按鈕、自動保留 Word 文字顏色等互動功能。若使用者指名 codelab / Codelabs 風格,改用 codelab-handout skill;本 skill 走忠實機械轉檔路線、不做視覺重設計。
- 2 stars
- 0 votes
- 0 copies
- 2 views
- Added October 4, 2026
Security analysis
100/100Pro scans all 7 files and shows the line behind each finding
npx -y skills add unbias38/my-claude-skills --skill teaching-handbook --agent claude-codeAre you the author of Teaching Handbook?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/unbias38-teaching-handbook)---
name: teaching-handbook
description: 將 Word (.docx)、Markdown (.md) 或 PowerPoint (.pptx) 教學講義轉成「側邊欄導航風格」的高畫質 HTML 網頁。使用時機:使用者說「上架教材」「上架講義」「教材轉網頁」「講義轉網頁」「轉成側邊欄導航風格」「轉成側邊欄網頁」「把這份 .docx/.md/.pptx 轉 HTML」,或提供 .docx/.md/.pptx 檔案並要求產出教學網頁時。產出包含固定側邊欄目錄、Scroll Spy、字體縮放、程式碼複製按鈕、自動保留 Word 文字顏色等互動功能。若使用者指名 codelab / Codelabs 風格,改用 codelab-handout skill;本 skill 走忠實機械轉檔路線、不做視覺重設計。
---
# teaching-handbook
> `<SKILL_DIR>` 代表本 SKILL.md 所在資料夾。
把 `.docx` / `.md` / `.pptx` 教學講義轉成側邊欄風格的教學網頁。
## 範圍邊界(重要)
本 skill **只負責機械轉檔**(Stage 1):把原檔的文字、圖、結構**忠實搬到** HTML,不改寫、不美化、不重組。
**內容理解 / 改寫 / 美化(Stage 2)不在本 skill 範圍**。原因:每份簡報的領域、讀者、風格差異太大,強行寫死自動規則只會把大部分簡報搞砸。Stage 2 由使用者**在跑完轉檔後**另起對話、依當份簡報的具體需求請 Claude 處理。
未來的維護者:**不要把美化規則寫進這個 skill**——本 skill 定位是忠實機械轉檔,美化屬於下游另一層。
若使用者指名 **codelab / Codelabs 風格**,本 skill 不處理,改用 `codelab-handout`(強意見視覺設計路線)。
## 硬規則(不可違反)
1. **必須使用原始檔**(`.docx` / `.md` / `.pptx`),不接受先轉過的 `.htm` / `.html`(否則圖片會糊)。
2. **不要改寫 `scripts/` 下的 Python 邏輯**,直接呼叫即可。
3. **輸出檔名以輸入檔名為基底**(例如 `我的講義.docx` → `我的講義.html`),不要預設 `index.html`,避免覆蓋專案主頁。
4. 若目標輸出檔已存在,先向使用者確認再覆蓋。
## 依套件
依賴由各腳本的 inline metadata(PEP 723)宣告,`uv run` 會自動安裝,無需手動裝套件。
## 執行 SOP
### 步驟 1:確認輸入檔
- 使用者提供 `.docx` → 走 `docx_converter.py`
- 使用者提供 `.md` → 走 `md_converter.py`
- 使用者提供 `.pptx` → 走 `pptx_converter.py`
- 其他副檔名 → 停下來問使用者
### 步驟 2:確認參數(都有預設值,可略)
- `--title`:瀏覽器分頁標題(預設 `教學手冊`,md 預設 `Document`)
- `--sidebar-title`:側邊欄標題(docx 預設 `教學手冊導航`;pptx 預設 `投影片目錄`)
- `--no-notes`(僅 pptx):不納入講者備註。**預設納入**。
- 輸出檔名:省略則自動用輸入檔名 + `.html`
使用者若沒主動提,**直接用預設值**,不要反覆追問。
### 步驟 3:執行轉換
DOCX:
```bash
uv run <SKILL_DIR>/scripts/docx_converter.py "<input.docx>" --title "<標題>" --sidebar-title "<側邊欄標題>"
```
Markdown:
```bash
uv run <SKILL_DIR>/scripts/md_converter.py "<input.md>" --title "<標題>"
```
PPTX:
```bash
uv run <SKILL_DIR>/scripts/pptx_converter.py "<input.pptx>" --title "<標題>" --sidebar-title "<側邊欄標題>"
```
### 步驟 4:回報結果
告訴使用者輸出檔路徑,讓他可以打開檢查。不用自行開啟瀏覽器。
## 產出的網頁功能
- 左側 280px 固定側邊欄,自動從 `h1/h2/h3` 生成目錄(Scroll Spy 高亮目前章節)
- `<<` 收折按鈕:側邊欄縮成 60px,主區域擴展到 1400px
- `A- / 100% / A+` 字體縮放(預設 1.15x)
- 程式碼區塊(單格表格或 `<pre>`)自動加「複製」按鈕
- 圖片響應式(`max-width: 100%`),保留 Word 原始高畫質
## 檔案結構
```
<SKILL_DIR>/
├── SKILL.md ← 本文件
└── scripts/
├── docx_converter.py ← .docx 入口
├── md_converter.py ← .md 入口
├── pptx_converter.py ← .pptx 入口
├── style_injector.py ← 核心樣式 + 導航 + 複製按鈕引擎(上游、不動)
└── _polish.py ← 共用 helper:sidebar 搜尋框 + 圖片 lazy load
```
`style_injector.py` 自成一體,三個 converter 皆透過 `import style_injector` 呼叫它。
`_polish.py` 是 converter-side 的共用增強,與 `style_injector.py` 無關(後者保持原樣)。
## 三個 converter 共享的功能(透過 `_polish.py`)
下列功能無論 docx / md / pptx 都會生效:
- **圖片 `loading="lazy"`**:所有 `<img>` 自動帶 lazy 屬性,大檔載入快
- **Sidebar 重建**:清空 `style_injector.py` 生成的 nav,**用文件中所有 H1/H2/H3 重建**(按文件順序)。修復「`1. 章節`」「純中文標題」等不符合上游 regex 的 heading 被 sidebar 漏掉的問題
- **Sidebar 即時搜尋**:在重建後的 `#sidebar-nav` 上方注入 `<input id="th-search">`,輸入即時過濾目錄項
執行時機:converter 在 body 末端塞 `<script>`,於 `window.load` 後執行(此時 `style_injector.py` 已跑完,nav 已被它的 regex 邏輯填好)。
**為什麼放在 `_polish.py` 而非 `style_injector.py`**:硬規則 #2 不動上游 `style_injector.py`。converter-side 增強統一抽到 `_polish.py`。
### 為什麼是「清空重建」而非「補登」
上游 `style_injector.py` sidebar JS 用 regex `^(\d+(\.\d+)?)(\s|$) || ^[A-Z](\s|$)` 過濾 H2/H3。對下列常見情境**全部會誤殺**:
- markdown 標題「`1. 章節`」(digit + dot + space,regex 在 dot 後 require digit,失敗)
- 純中文 H2 / H3(既無數字也無大寫字母前綴)
- docx heading 用中文起頭
如果只「補登被漏的」,當 H1(永遠通過)和 H2(中文,被漏)交錯時,**順序會錯**(既有 H1 在前,後補的 H2 全部塞最後)。所以必須**清空 nav 整個重建**,按 `querySelectorAll('h1, h2, h3')` 的 document order 全列。
**ID 兼容性**:`style_injector.py` 給通過 regex 的 heading assign `id="section-N"`,scroll-spy IntersectionObserver 用這些 ID 對應 nav-link。重建邏輯**重用既有 id**(若 heading 已有 id 則保留),新加的 heading assign `th-section-N`。Observer 端比對 `href === '#' + id`,新舊 ID 都對得上 → scroll-spy 正常。
**順序保證**:document order 由 `querySelectorAll` 保證,重建後 sidebar 順序 = 文件順序,與單純 append 在 H1/H2/H3 交錯文件的順序錯亂問題隔絕。
**驗證**(2026-04-25):
- `LSpe2.md`(1 H1 + 15 H2 + 7 H3 共 23 個 heading):之前 sidebar 1 條,現在 23 條 ✅
- `防災宣導_SROI.docx`(10 H1):10 條 → 10 條,無 regression ✅
- `金融大數據_v0.pptx`(10 H2 「01 - 標題」):10 條 → 10 條,無 regression ✅
**不要這樣修**:~~改 `style_injector.py` 的 regex 一勞永逸~~ — 違反硬規則 #2。`_polish.py` 的清空重建是正確的繞道方式。
## pptx 轉換原則
- **每張投影片 = 一個 `<h2>` 章節**(側邊欄自動列出)
- **章節分隔投影片 → `<h1>`**(無內容、無 bullets、≤1 圖、或 layout 名稱含 `section header`/`title slide`/`chapter`)
- 投影片標題空白 → 用 `Slide N` 標示
- 投影片內文 → `<ul>`(短)或 `<p>`(長)
- 投影片內嵌圖片 → 以 base64 data URI 內嵌、`loading="lazy"`、80×80 縮圖橫排
- 講者備註 → **預設納入**(教學型 pptx 常把真正內容放在備註);用 `--no-notes` 可關閉
- Sidebar 自動加搜尋框(輸入即時過濾目錄項)
- 不做投影片轉圖、不還原版面 —— 這是重排器,不是螢幕截圖器
- 動畫、轉場、嵌入影片會丟失(pptx → HTML 的必然代價)
## pptx 採坑紀錄(2026-04-25 實測 12 頁簡報)
下面是「為什麼 `pptx_converter.py` 看起來怪怪的」的解答。**未來除錯前先讀完,避免把對的東西改壞。**
### 1. 標題會被強制加 `01 - ` 前綴 — 這是故意的
**現象**:`pptx_converter.py` 的 `_render_slide_html` 會把 `投影片標題` 改成 `01 - 投影片標題` 才送進 HTML。
**原因**:上游 `style_injector.py` 第 430 行 sidebar nav 生成 JS 用 regex 過濾 h2/h3 標題:
```js
const match = text.match(/^(\d+(\.\d+)?)(\s|$)/) || text.match(/^[A-Z](\s|$)/);
if (match || header.tagName === 'H1') { /* add to sidebar */ }
```
只接受「數字 + 空白開頭」(如 `1 章` `1.1 節`)或「單一大寫字母 + 空白開頭」(如 `A 概論`)。**純中文標題全部被略過 → sidebar 變空白**。
**對策**:converter 端強制前綴 `f"{i:02d} - {title}"`(不動上游腳本,符合硬規則 #2)。
**不要這樣修**:~~改 `style_injector.py` 把 regex 放寬~~ — 違反硬規則 #2,且會影響 docx/md 流程。
### 2. 圖片預設縮成 80×80 縮圖橫排 — 這也是故意的
**現象**:投影片裡的圖片不是大圖內嵌,是 `<div class="pptx-thumbs">` 裡的 80×80 小方塊橫排。
**原因**:PowerPoint 教學簡報通常每張投影片埋 5–10 張 256×256 的**裝飾圖示**(流程箭頭、燈泡、章節標誌等)—— 不是「正文圖」。如果當大圖內嵌,每張佔約 300px 垂直空間,累積就一片空白海。實測 12 頁簡報共 32 張圖、所有都是 256×256,幾乎全是裝飾。
**對策**:用 flex + 80×80 縮圖排在標題下方,視覺上是一行 icons。
**不要這樣修**:~~改回每張一行的大圖呈現~~ — 會讓所有教學型 pptx 變成空白海。如果未來真遇到「圖才是主角」的 pptx(例如設計作品集),應該另開新 skill(如 `pptx-gallery`),別改這個。
### 3. 過濾純數字/單字母的短 bullet
**現象**:`_collect_body_paragraphs` 會跳過長度 ≤ 2 且為純數字或純字母的文字。
**原因**:PowerPoint 投影片底部常有頁碼("2"、"3")或裝飾編號,會被 python-pptx 當成一般文字框讀進來,污染 bullet 清單。
**不要這樣修**:~~移掉這個過濾~~ — 除非使用者明確表示需要保留頁碼。
### 4. 上游 style_injector 的兩處來源專案特定 hack — 保留原樣
上游 `style_injector.py` 含兩處來源專案特定 hack(emoji 狀態色替換、「執行步驟」表格的 copy-btn 排除),對一般文件無害、幾乎不觸發;依硬規則 #2 保留原樣,不要清理。
---
### 教訓(給未來的我)
「LLM 按按鈕」型 skill 並非「加個檔就完事」。下游 `style_injector.py` 有**隱性假設**(標題要數字開頭、image 要適合大圖呈現),新加的 converter 必須學會這些假設才能對接。設計上的拗口都是有原因的,不要看到就想「優化」掉。
## pptx 大檔擴張(2026-04-25 加,因應 200+ 頁簡報)
為了讓大檔(50+ 頁)也好用,`pptx_converter.py` 內建章節偵測:
### 章節偵測 → `<h1>`
`_is_chapter_slide()` 判斷規則:
- 投影片 layout 名稱含 `section header` / `section divider` / `title slide` / `chapter` → 是章節
- 或 投影片無 bullets、無 long paragraphs、且 ≤1 張圖 → 是章節
章節投影片用 `<h1>`(不加 `01 -` 前綴,因 H1 不需 regex 匹配)。`style_injector.py` 自動把 H1 列為 sidebar 頂層(level-1,含上方分隔線)—— **這是上游已經支援的功能,我們只是讓 pptx 能觸發它**。
**不要這樣修**:~~改用 H3 區分章節~~ — H3 受 regex 限制,且 sidebar 顯示太小看不出階層。
lazy load 與 sidebar 搜尋已移至三 converter 共享的 `_polish.py`,見上節「三個 converter 共享的功能」。
Files in this skill
- README.md
- SKILL.md
- scripts/_polish.py
- scripts/docx_converter.py
- scripts/md_converter.py
- scripts/pptx_converter.py
- scripts/style_injector.py
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.