@qnroa/qtype 0.0.5 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,3 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/index-DgHvnMV9.js","assets/index-1XXyxiQO.js","assets/index-BLryk3W4.css"])))=>i.map(i=>d[i]);
2
- import{r as l,_ as h,u as g,j as f,C as p,M as m,T as y,a as w}from"./index-1XXyxiQO.js";let o=null,c=null;async function L(){return o||c||(c=h(()=>import("./index-DgHvnMV9.js"),__vite__mapDeps([0,1,2])).then(async e=>(o=await e.createHighlighter({themes:["github-dark","github-light"],langs:[]}),o)),c)}async function _(e,t){if(!e.getLoadedLanguages().includes(t))try{await e.loadLanguage(t)}catch{}}function x(e){const[t,n]=l.useState(o);return l.useEffect(()=>{if(!e)return;let r=!1;return(async()=>{const s=await L();await _(s,e),r||n(s)})(),()=>{r=!0}},[e]),t}const A=/```(\w+)/;function E(e){const t=e.toLowerCase();return t.includes("typescript")||t.endsWith(".ts")?"typescript":t.includes("python")||t.endsWith(".py")?"python":t.includes("cpp")||t.includes("c++")?"cpp":t.includes("java")&&!t.includes("script")?"java":t.includes("go")?"go":t.includes("rust")||t.endsWith(".rs")?"rust":t.includes("code-c")||t.endsWith(".c")?"c":"javascript"}function j(e,t){if(e){const n=e.match(A);if(n)return n[1]}return E(t)}function k(e,t,n,r){if(!r||!r.getLoadedLanguages().includes(t))return new Array(Array.from(e).length).fill(null);try{const s=r.codeToTokens(e,{lang:t,theme:n}),i=[];for(const u of s.tokens){for(const a of u)for(const d of a.content)i.push(a.color??null);i.push(null)}return!e.endsWith(`
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/index-BM7BgXjn.js","assets/index-C1KzsLUa.js","assets/index-BLryk3W4.css"])))=>i.map(i=>d[i]);
2
+ import{r as l,_ as h,u as g,j as f,C as p,M as m,T as y,a as w}from"./index-C1KzsLUa.js";let o=null,c=null;async function L(){return o||c||(c=h(()=>import("./index-BM7BgXjn.js"),__vite__mapDeps([0,1,2])).then(async e=>(o=await e.createHighlighter({themes:["github-dark","github-light"],langs:[]}),o)),c)}async function _(e,t){if(!e.getLoadedLanguages().includes(t))try{await e.loadLanguage(t)}catch{}}function x(e){const[t,n]=l.useState(o);return l.useEffect(()=>{if(!e)return;let r=!1;return(async()=>{const s=await L();await _(s,e),r||n(s)})(),()=>{r=!0}},[e]),t}const A=/```(\w+)/;function E(e){const t=e.toLowerCase();return t.includes("typescript")||t.endsWith(".ts")?"typescript":t.includes("python")||t.endsWith(".py")?"python":t.includes("cpp")||t.includes("c++")?"cpp":t.includes("java")&&!t.includes("script")?"java":t.includes("go")?"go":t.includes("rust")||t.endsWith(".rs")?"rust":t.includes("code-c")||t.endsWith(".c")?"c":"javascript"}function j(e,t){if(e){const n=e.match(A);if(n)return n[1]}return E(t)}function k(e,t,n,r){if(!r||!r.getLoadedLanguages().includes(t))return new Array(Array.from(e).length).fill(null);try{const s=r.codeToTokens(e,{lang:t,theme:n}),i=[];for(const u of s.tokens){for(const a of u)for(const d of a.content)i.push(a.color??null);i.push(null)}return!e.endsWith(`
3
3
  `)&&i.length>Array.from(e).length&&i.pop(),i}catch{return new Array(Array.from(e).length).fill(null)}}function v(e){var d;const{material:t,card:n}=e,[r]=g(),s=l.useMemo(()=>r?j(n.question,t.filePath):"",[n.question,t.filePath,r]),i=typeof document<"u"&&((d=document.documentElement.getAttribute("data-theme"))!=null&&d.includes("latte"))?"github-light":"github-dark",u=x(r?s:""),a=l.useMemo(()=>r?k(n.answer,s,i,u):void 0,[n.answer,s,i,u,r]);return f.jsx(p,{type:"code",variant:"flow",slots:[{role:"title",content:n.title},n.question?{role:"question",content:f.jsx(m,{source:n.question})}:{role:"question",content:null},{role:"arena",content:f.jsx(y,{...w(e),charColors:a},n.id)}]})}export{v as CodeCard};
@@ -13,7 +13,7 @@
13
13
  <meta name="referrer" content="no-referrer" />
14
14
  <link rel="icon" type="image/svg+xml" href="/qtype-mark.svg" />
15
15
  <title>qtype — 打字复习</title>
16
- <script type="module" crossorigin src="/assets/index-1XXyxiQO.js"></script>
16
+ <script type="module" crossorigin src="/assets/index-C1KzsLUa.js"></script>
17
17
  <link rel="stylesheet" crossorigin href="/assets/index-BLryk3W4.css">
18
18
  </head>
19
19
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qnroa/qtype",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "Turn Markdown notes into typing practice — CLI + review + static-site publisher",
5
5
  "keywords": [
6
6
  "typing",
@@ -41,7 +41,8 @@ The whole document is organized into four modules: **Concepts / Format / Operati
41
41
  ├── qtype.config.json
42
42
  ├── material/
43
43
  │ ├── .gitkeep
44
- │ ├── <slug>.md
44
+ │ ├── <slug>.md # flat placement — fine
45
+ │ ├── <category>/<slug>.md # nested placement — also fine
45
46
  │ └── assets/<material-slug>/
46
47
  └── raw/
47
48
  ├── .gitkeep
@@ -49,6 +50,8 @@ The whole document is organized into four modules: **Concepts / Format / Operati
49
50
  └── assets/<raw-slug>/
50
51
  ```
51
52
 
53
+ **Flat and nested placements are both supported.** All `.md` under `material/` are discovered recursively. Choose whichever fits the repo — small repos are usually flat, larger ones group by category folder.
54
+
52
55
  ---
53
56
 
54
57
  ## Format
@@ -68,13 +71,58 @@ updated: YYYY-MM-DD
68
71
  ```
69
72
 
70
73
  - `title`: human-readable
71
- - `type`: **required**. Decides how every card is parsed and rendered
72
- - `tags`: array or space-separated
74
+ - `type`: **default** for every card in the file. Individual cards can
75
+ override via card-level frontmatter (see below).
76
+ - `tags`: default tag set for every card. Card-level tags are unioned
77
+ with these (deduped).
73
78
  - `created` / `updated`: dates. Bump `updated` on any content change
74
79
 
75
- **One material, one type. All cards in a file share the same shape.**
80
+ **Material-level fields set defaults; cards can override.** A single
81
+ file can mix qa / code / article / etc. by giving each card its own
82
+ `type` in card-level frontmatter.
83
+
84
+ ### Card-level frontmatter (optional)
85
+
86
+ Immediately after an H1, you may open a second YAML block. It uses the
87
+ same `---\n...\n---` syntax as the file-level frontmatter:
88
+
89
+ ```md
90
+ ---
91
+ title: 704 Binary search
92
+ type: qa
93
+ tags: [algo]
94
+ ---
76
95
 
77
- There is **no card-level frontmatter**. All per-card info lives in markdown structure.
96
+ # Principle
97
+ ---
98
+ type: qa
99
+ tags: [L1]
100
+ ---
101
+
102
+ ## Q
103
+ Which invariant do I keep for the closed interval version?
104
+
105
+ ## A
106
+ Loop while lo <= hi; update `lo = mid+1` / `hi = mid-1`.
107
+
108
+ # C++ implementation
109
+ ---
110
+ type: code
111
+ tags: [cpp, L1]
112
+ ---
113
+
114
+ ## Q
115
+ Write the closed-interval binary search in C++.
116
+
117
+ ## A
118
+ ​```cpp
119
+ int search(vector<int>& nums, int target) { ... }
120
+ ​```
121
+ ```
122
+
123
+ - `type` (if present) overrides the material default for this one card.
124
+ - `tags` (if present) are unioned with material tags and deduped.
125
+ - Omit the block entirely and the card inherits both fields as-is.
78
126
 
79
127
  ### Card structure
80
128
 
@@ -231,11 +279,21 @@ sqrt(pi)
231
279
 
232
280
  ### Naming
233
281
 
234
- Material files: `material/<slug>.md`
235
- - kebab-case, ASCII lowercase + hyphens, ≤ 60 chars
282
+ Material files: `material/<slug>.md` — or `material/<category>/<slug>.md` if grouping by folder.
283
+
284
+ - Each path segment (`<slug>`, `<category>`) uses the same rules: kebab-case, ASCII lowercase + hyphens, ≤ 60 chars
236
285
  - Chinese topics: use English translation or pinyin
237
286
  - Collision: append `-2` / `-3`
238
287
 
288
+ ### Grouping by folder (optional)
289
+
290
+ `material/` may contain category subfolders. Two things to know when you use them:
291
+
292
+ - **Discovery is recursive.** All `.md` files under `material/` are picked up regardless of depth. Nested folders don't hide their contents.
293
+ - **The first path segment is a fallback `type`.** When a material's frontmatter omits `type`, the first folder name is used instead — e.g. a file at `material/code/hello.md` with no `type:` line is treated as `type: code`. This is a shortcut for repos organized by type folder; explicit `type:` in frontmatter always wins.
294
+
295
+ Group by folder when the repo has many materials of clearly different subjects (e.g. `skills/`, `experience/`, `projects/`, `code/`). Stay flat when there are only a handful of files — extra folders add friction without payoff.
296
+
239
297
  ### Links
240
298
 
241
299
  - **Markdown link syntax only**, no Wikilinks
@@ -256,7 +314,9 @@ Ingest, Update, Quiz-gen, Cascade, Check, Level-up — semantics as before. Key
256
314
  - Concept questions, interviews → **qa**
257
315
  - Coding problems, snippets → **code**
258
316
 
259
- **One material, one type.** Mixed content multiple materials.
317
+ **Material-level `type` is the default for its cards.** Cards can
318
+ override with card-level frontmatter, so one file can mix shapes
319
+ (e.g. one qa "principle" card + four code cards for cpp/py/go/java).
260
320
 
261
321
  ---
262
322
 
@@ -272,7 +332,7 @@ Ingest, Update, Quiz-gen, Cascade, Check, Level-up — semantics as before. Key
272
332
  6. **No Wikilinks**
273
333
  7. **No absolute paths**
274
334
  8. **Never `git commit` / `push`** — the user commits
275
- 9. **No unspec'd directories** — flat `material/` + `assets/` only
335
+ 9. **No unspec'd directories** — only `material/` (may contain category subfolders, see "Grouping by folder"), `material/assets/`, and `raw/` are allowed at the repo root
276
336
  10. **Never fabricate IPA / gloss / translation** — leave blank, report in log
277
- 11. **One `type` per material** — no mixing
278
- 12. **No card-level frontmatter** per-card info lives in markdown structure
337
+ 11. **Material-level `type` is a default** — cards can override via
338
+ card-level frontmatter (see "Card-level frontmatter (optional)")
@@ -43,8 +43,9 @@ qtype 是一个以 Markdown 为源、以 OS 键盘(含中文 IME)为输入
43
43
  ├── qtype.config.json # 用户可调设置
44
44
  ├── material/ # 你写的素材
45
45
  │ ├── .gitkeep
46
- │ ├── <slug>.md # 一个素材一个文件
47
- └── assets/ # 素材引用的图片
46
+ │ ├── <slug>.md # 平铺放法 —— 可以
47
+ ├── <category>/<slug>.md # 按分类嵌套 —— 也可以
48
+ │ └── assets/ # 素材引用的图片
48
49
  │ └── <material-slug>/
49
50
  └── raw/ # (可选)用户扔进来的原始材料
50
51
  ├── .gitkeep
@@ -52,6 +53,8 @@ qtype 是一个以 Markdown 为源、以 OS 键盘(含中文 IME)为输入
52
53
  └── assets/
53
54
  ```
54
55
 
56
+ **平铺和嵌套都支持**:`material/` 下所有 `.md` 会被递归发现,深几层都能扫到。文件少时平铺就够了,文件多时按分类开子目录更清爽。
57
+
55
58
  ---
56
59
 
57
60
  ## 格式
@@ -73,12 +76,55 @@ updated: YYYY-MM-DD
73
76
  **规则**:
74
77
 
75
78
  - `title`:素材标题,人看的
76
- - `type`:**必填**,决定所有卡片的解析规则和渲染样式
77
- - `tags`:数组或空格分隔,至少一个
79
+ - `type`:**默认值**,决定每张卡的解析规则和渲染样式。单卡可通过
80
+ card-level frontmatter 覆盖(见下)。
81
+ - `tags`:素材级 tag 集,和 card-level tag 合并去重
78
82
  - `created` / `updated`:日期。内容变化时 bump `updated`
79
- - **一个 material 只有一个 type**,一个文件的所有卡片形态一致
80
83
 
81
- **没有 card-level frontmatter**。所有卡片信息都由 markdown 结构表达。
84
+ **素材级 type 是默认值,卡片可以 override。** 一个文件里可以混合
85
+ qa / code / article 等多种卡型 —— 只需要给对应的卡加卡级 frontmatter。
86
+
87
+ ### 卡级 frontmatter(可选)
88
+
89
+ H1 之后可以再写一段 YAML,和文件顶部一样用 `---\n...\n---` 包起来:
90
+
91
+ ```md
92
+ ---
93
+ title: 704 二分查找
94
+ type: qa
95
+ tags: [algo]
96
+ ---
97
+
98
+ # 原理
99
+ ---
100
+ type: qa
101
+ tags: [L1]
102
+ ---
103
+
104
+ ## Q
105
+ 左闭右闭需要保持什么循环不变量?
106
+
107
+ ## A
108
+ while lo <= hi;更新 `lo = mid+1` 或 `hi = mid-1`。
109
+
110
+ # C++ 实现
111
+ ---
112
+ type: code
113
+ tags: [cpp, L1]
114
+ ---
115
+
116
+ ## Q
117
+ 用 C++ 写左闭右闭版本。
118
+
119
+ ## A
120
+ ​```cpp
121
+ int search(vector<int>& nums, int target) { ... }
122
+ ​```
123
+ ```
124
+
125
+ - 卡级 `type` 存在则覆盖素材默认
126
+ - 卡级 `tags` 存在则和素材 tags 并集(去重)
127
+ - 卡级 frontmatter 完全省略则继承素材默认
82
128
 
83
129
  ### Card 结构
84
130
 
@@ -259,12 +305,21 @@ sqrt(pi)
259
305
 
260
306
  ### 命名
261
307
 
262
- **素材文件名**:`material/<slug>.md`
308
+ **素材文件名**:`material/<slug>.md` —— 或者按分类嵌套时 `material/<category>/<slug>.md`。
263
309
 
264
- - `<slug>`:主题的 kebab-case,小写,英文字母和短横线,最长 60 字符
310
+ - 每一段路径(`<slug>`、`<category>`)都用同一套规则:kebab-case,小写,英文字母和短横线,最长 60 字符
265
311
  - 中文主题用英译或拼音
266
312
  - 同名冲突:末尾追加 `-2` / `-3`
267
313
 
314
+ ### 按分类分子目录(可选)
315
+
316
+ `material/` 下可以开分类子目录。启用时需要知道两件事:
317
+
318
+ - **发现是递归的**。`material/` 下所有 `.md` 文件不论深度都会被扫到,嵌套目录不会被跳过
319
+ - **首段路径充当 `type` 的 fallback**。如果一个 material 的 frontmatter 没有写 `type`,第一段目录名会被当作 type —— 比如 `material/code/hello.md` 不写 `type:` 会被视为 `type: code`。这是给"按 type 分目录"的仓库的捷径;只要 frontmatter 里显式写了 `type`,永远以 frontmatter 为准。
320
+
321
+ 素材数量多、主题差异明显时(比如 `skills/` / `experience/` / `projects/` / `code/`)用子目录归类;素材只有几个时保持平铺就好,多开一层目录只会增摩擦不增收益。
322
+
268
323
  ### 链接
269
324
 
270
325
  - **只用 Markdown link**,不用 Wikilink
@@ -314,7 +369,8 @@ updated: YYYY-MM-DD
314
369
  - 问答、面试题、概念解释 → **qa**
315
370
  - 代码题、算法题、片段 → **code**
316
371
 
317
- **一个 material 只有一个 type**。混合内容拆成多个 material。
372
+ **素材级 `type` 是默认值。** 一个文件里可以混合多种卡型 —— 靠卡级
373
+ frontmatter 覆盖(比如 1 张 qa 原理卡 + 4 张不同语言的 code 实现卡)。
318
374
 
319
375
  ---
320
376
 
@@ -330,7 +386,7 @@ updated: YYYY-MM-DD
330
386
  6. **不用 Wikilink**
331
387
  7. **不绝对路径**
332
388
  8. **不主动 git commit / push**
333
- 9. **不建规则外的目录**
389
+ 9. **不建规则外的目录**:仓库根下只允许 `material/`(内部可按分类开子目录,见"按分类分子目录")、`material/assets/`、`raw/`
334
390
  10. **不凭空造 IPA / 释义 / 翻译**:不确定的宁可空着
335
- 11. **一个 material 只有一个 type**:不能混
336
- 12. **没有 card-level frontmatter**:所有 per-card 信息都用 markdown 结构表达
391
+ 11. **素材级 `type` 是默认值**:卡片可以通过卡级 frontmatter 覆盖
392
+ (见"卡级 frontmatter(可选)"章节)