@kolkrabbi/kol-workshop 0.3.3 → 0.3.4

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kolkrabbi/kol-workshop",
3
- "version": "0.3.3",
3
+ "version": "0.3.4",
4
4
  "private": false,
5
5
  "description": "KOL workshop/docs system — a handrolled markdown engine, search, tag system (incl. a d3 tag graph), docs viewer, and docs shell. Sits above @kolkrabbi/kol-{theme,icons,component,framework}; content is consumer-injected (the package never globs docs).",
6
6
  "license": "MIT",
@@ -14,9 +14,9 @@
14
14
  "dependencies": {
15
15
  "d3": "^7.9.0",
16
16
  "@kolkrabbi/kol-brand": "^0.1.2",
17
+ "@kolkrabbi/kol-icons": "0.8.11",
17
18
  "@kolkrabbi/kol-component": "0.14.1",
18
- "@kolkrabbi/kol-icons": "0.8.10",
19
- "@kolkrabbi/kol-framework": "0.7.0",
19
+ "@kolkrabbi/kol-framework": "0.8.0",
20
20
  "@kolkrabbi/kol-theme": "0.13.2"
21
21
  },
22
22
  "peerDependencies": {
@@ -1,7 +1,13 @@
1
1
  const join = (...classes) => classes.filter(Boolean).join(' ')
2
2
 
3
+ /* NOT .kol-prose (wave-4 retype, 2026-07-30 — user law: one layout = one style
4
+ * system; prose is the blog/CMS voice, never docs surfaces). Every element the
5
+ * reader renders is typed explicitly through the kol-doc-* roles, mirroring
6
+ * showcase/src/lib/mdx-components.jsx — the SAME dialect MDX pages speak.
7
+ * Vertical rhythm comes from the flex gap (the MdxDoc content idiom), not
8
+ * prose margins. */
3
9
  const DocsArticle = ({ children, className }) => (
4
- <article className={join('docs-article kol-prose', className)}>{children}</article>
10
+ <article className={join('docs-article flex w-full min-w-0 flex-col gap-6', className)}>{children}</article>
5
11
  )
6
12
 
7
13
  export default DocsArticle
@@ -1,9 +1,13 @@
1
1
  const join = (...classes) => classes.filter(Boolean).join(' ')
2
2
 
3
+ /* Doc voice (wave-4 retype, 2026-07-30): title/subtitle ride the DocHeader
4
+ * contract roles (kol-doc-heading / kol-doc-lede) instead of the old
5
+ * kol-sans-heading-02 + kol-mono-14 pair — one header voice across the
6
+ * reader, MDX pages and the Doc* kit. */
3
7
  const DocsHeader = ({ title, subtitle, meta = [], className }) => (
4
- <header className={join('docs-header', className)}>
5
- {title ? <h1 className="kol-sans-heading-02 text-strong">{title}</h1> : null}
6
- {subtitle ? <p className="kol-mono-14 text-meta">{subtitle}</p> : null}
8
+ <header className={join('docs-header flex flex-col gap-3', className)}>
9
+ {title ? <h1 className="kol-doc-heading">{title}</h1> : null}
10
+ {subtitle ? <p className="kol-doc-lede">{subtitle}</p> : null}
7
11
  {Array.isArray(meta) && meta.length > 0 ? (
8
12
  <div className="docs-meta kol-helper-10 text-body">
9
13
  {meta.map(({ label, value }) => (
@@ -1,12 +1,13 @@
1
1
  import { useContext, useEffect, useMemo, useState } from 'react'
2
2
  import { useParams, Link, useNavigate } from 'react-router-dom'
3
- import { CodeBlock, Divider, DocsToc, Icon, Tag } from '@kolkrabbi/kol-component'
3
+ import { CodeBlock, Divider, DocsToc, Icon, Table, Tag } from '@kolkrabbi/kol-component'
4
4
  import { ShellTocContext } from '../shell'
5
5
  import { useTagMode } from '../tags'
6
6
  import { parseDocsMarkdown, isIndexFile, getTagColor } from '../engine'
7
7
  import DocsHeader from './DocsHeader.jsx'
8
8
  import DocsArticle from './DocsArticle.jsx'
9
9
  import DocsFrontmatter from './DocsFrontmatter.jsx'
10
+ import { DocSection } from './DocKit.jsx'
10
11
  import { renderInlineTokens } from './render-tokens.jsx'
11
12
 
12
13
  const SidebarSection = ({ sectionKey, label, collapsedSections, toggleSection, children }) => (
@@ -166,6 +167,82 @@ const DocumentationReader = ({
166
167
  const renderTokens = (tokens, tokenKey) =>
167
168
  renderInlineTokens(tokens, tokenKey, resolveDocLink, tagHref)
168
169
 
170
+ /* ONE block renderer for intro + section content (wave-4 retype, 2026-07-30
171
+ * — the two switches had already drifted). Every element is typed through
172
+ * the kol-doc-* dialect of showcase mdx-components.jsx: doc-body running
173
+ * text (self-caps at the measure), heading-05 h3/h4 (h4 = weight 400, the
174
+ * prose-h4 precedent), panel-capped furniture (width law: tables/code cap
175
+ * at --kol-content-panel), markdown tables through THE kol-component Table
176
+ * as a dynamic-column DocTable sibling (no parallel table markup). */
177
+ const renderBlock = (block, blockKey) => {
178
+ switch (block.type) {
179
+ case 'paragraph':
180
+ return (
181
+ <p key={blockKey} className="kol-doc-body">
182
+ {block.tokens ? renderTokens(block.tokens, blockKey) : block.content}
183
+ </p>
184
+ )
185
+ case 'heading3':
186
+ return (
187
+ <h3 key={blockKey} id={block.id} className="kol-sans-heading-05 text-emphasis scroll-mt-20 mt-2">
188
+ {block.content}
189
+ </h3>
190
+ )
191
+ case 'heading4':
192
+ return (
193
+ <h4 key={blockKey} id={block.id} className="kol-sans-heading-05 font-normal text-emphasis scroll-mt-20">
194
+ {block.content}
195
+ </h4>
196
+ )
197
+ case 'list': {
198
+ const ListComponent = block.ordered ? 'ol' : 'ul'
199
+ const listClass = `flex ${block.ordered ? 'list-decimal' : 'list-disc'} flex-col gap-2 pl-5 kol-doc-body`
200
+ return block.items ? (
201
+ <ListComponent key={blockKey} className={listClass}>
202
+ {block.items.map((item, itemIndex) => (
203
+ <li key={itemIndex}>
204
+ {item.tokens ? renderTokens(item.tokens, `${blockKey}-item-${itemIndex}`) : item.content || item}
205
+ </li>
206
+ ))}
207
+ </ListComponent>
208
+ ) : null
209
+ }
210
+ case 'blockquote':
211
+ return (
212
+ <blockquote key={blockKey} className="docs-callout kol-doc-body">
213
+ {block.tokens ? renderTokens(block.tokens, blockKey) : block.content}
214
+ </blockquote>
215
+ )
216
+ case 'divider':
217
+ return <Divider key={blockKey} className="docs-divider" opacity="12" />
218
+ case 'code':
219
+ return (
220
+ <div key={blockKey} className="max-w-[var(--kol-content-panel)]">
221
+ <CodeBlock code={block.lines.join('\n')} language={block.lang} />
222
+ </div>
223
+ )
224
+ case 'table':
225
+ return (
226
+ <div key={blockKey} className="max-w-[var(--kol-content-panel)]">
227
+ <Table
228
+ variant="simple"
229
+ columns={block.headers.map((header, i) => ({ accessor: `c${i}`, header }))}
230
+ rows={block.rows.map((row, rowIndex) => ({
231
+ id: rowIndex,
232
+ ...Object.fromEntries(row.map((cell, cellIndex) => [
233
+ `c${cellIndex}`,
234
+ cell.tokens ? renderTokens(cell.tokens, `${blockKey}-row-${rowIndex}-cell-${cellIndex}`) : cell.content,
235
+ ])),
236
+ }))}
237
+ className="kol-doc-table"
238
+ />
239
+ </div>
240
+ )
241
+ default:
242
+ return null
243
+ }
244
+ }
245
+
169
246
  const doc = useMemo(() => {
170
247
  return inventory.find((d) => d.id === docId)
171
248
  }, [inventory, docId])
@@ -254,172 +331,19 @@ const DocumentationReader = ({
254
331
  <DocsArticle>
255
332
  <DocsFrontmatter metadata={doc.metadata} docId={docId} />
256
333
  {docTitle && (
257
- <h1>{docTitle}</h1>
334
+ <h1 className="kol-doc-heading">{docTitle}</h1>
258
335
  )}
259
336
  {/* Render intro blocks (excluding H1 which is docTitle) */}
260
- {introBlocks.filter(b => b.type !== 'heading1').map((block, index) => {
261
- const blockKey = `intro-${block.type}-${index}`
262
- switch (block.type) {
263
- case 'paragraph':
264
- return (
265
- <p key={blockKey}>
266
- {block.tokens ? renderTokens(block.tokens, blockKey) : block.content}
267
- </p>
268
- )
269
- case 'heading3':
270
- return (
271
- <h3 key={blockKey} id={block.id}>
272
- {block.content}
273
- </h3>
274
- )
275
- case 'heading4':
276
- return (
277
- <h4 key={blockKey} id={block.id}>
278
- {block.content}
279
- </h4>
280
- )
281
- case 'list':
282
- return block.items ? (
283
- <ul key={blockKey} className="docs-list tight">
284
- {block.items.map((item, i) => (
285
- <li key={i}>
286
- {item.tokens ? renderTokens(item.tokens, `${blockKey}-item-${i}`) : item.content}
287
- </li>
288
- ))}
289
- </ul>
290
- ) : null
291
- case 'blockquote':
292
- return (
293
- <blockquote key={blockKey} className="docs-callout">
294
- {block.tokens ? renderTokens(block.tokens, blockKey) : block.content}
295
- </blockquote>
296
- )
297
- case 'divider':
298
- return <Divider key={blockKey} className="docs-divider" opacity="12" />
299
- case 'code':
300
- return (
301
- <CodeBlock
302
- key={blockKey}
303
- code={block.lines.join('\n')}
304
- language={block.lang}
305
- />
306
- )
307
- case 'table':
308
- return (
309
- <div key={blockKey} className="kol-table-wrapper kol-table--simple">
310
- <table className="kol-table">
311
- <thead className="kol-table-thead">
312
- <tr>
313
- {block.headers.map((header, headerIndex) => (
314
- <th key={headerIndex} className="kol-table-cell-title">{header}</th>
315
- ))}
316
- </tr>
317
- </thead>
318
- <tbody>
319
- {block.rows.map((row, rowIndex) => (
320
- <tr key={rowIndex} className="kol-table-row">
321
- {row.map((cell, cellIndex) => (
322
- <td key={cellIndex} className="kol-table-cell-text">
323
- {cell.tokens ? renderTokens(cell.tokens, `${blockKey}-row-${rowIndex}-cell-${cellIndex}`) : cell.content}
324
- </td>
325
- ))}
326
- </tr>
327
- ))}
328
- </tbody>
329
- </table>
330
- </div>
331
- )
332
- default:
333
- return null
334
- }
335
- })}
337
+ {introBlocks.filter(b => b.type !== 'heading1').map((block, index) =>
338
+ renderBlock(block, `intro-${block.type}-${index}`)
339
+ )}
336
340
 
341
+ {/* Sections through the packaged DocSection — the same anchored
342
+ * rule + h2 contract MDX pages compose with. */}
337
343
  {sections.map(({ heading, id, blocks }) => (
338
- <section key={id} id={id} className="space-y-6 scroll-mt-32">
339
- <h2>{heading}</h2>
340
- {blocks.map((block, index) => {
341
- const blockKey = `${id}-${block.type}-${index}`
342
-
343
- switch (block.type) {
344
- case 'heading3':
345
- return (
346
- <h3 key={blockKey} id={block.id}>
347
- {block.content}
348
- </h3>
349
- )
350
- case 'heading4':
351
- return (
352
- <h4 key={blockKey} id={block.id}>
353
- {block.content}
354
- </h4>
355
- )
356
- case 'paragraph':
357
- return (
358
- <p key={blockKey}>
359
- {block.tokens ? renderTokens(block.tokens, blockKey) : block.content}
360
- </p>
361
- )
362
- case 'list': {
363
- const listClass = block.ordered
364
- ? 'docs-list docs-list--ordered tight'
365
- : 'docs-list tight'
366
- const ListComponent = block.ordered ? 'ol' : 'ul'
367
- return (
368
- <ListComponent key={blockKey} className={listClass}>
369
- {block.items.map((item, itemIndex) => (
370
- <li key={itemIndex}>
371
- {item.tokens ? renderTokens(item.tokens, `${blockKey}-item-${itemIndex}`) : item.content || item}
372
- </li>
373
- ))}
374
- </ListComponent>
375
- )
376
- }
377
- case 'code':
378
- return (
379
- <CodeBlock
380
- key={blockKey}
381
- code={block.lines.join('\n')}
382
- language={block.lang}
383
- />
384
- )
385
- case 'blockquote':
386
- return (
387
- <blockquote key={blockKey} className="docs-callout">
388
- {block.tokens ? renderTokens(block.tokens, blockKey) : block.content}
389
- </blockquote>
390
- )
391
- case 'divider':
392
- return <Divider key={blockKey} className="docs-divider" opacity="12" />
393
- case 'table':
394
- return (
395
- <div key={blockKey} className="kol-table-wrapper kol-table--simple">
396
- <table className="kol-table">
397
- <thead className="kol-table-thead">
398
- <tr>
399
- {block.headers.map((header, headerIndex) => (
400
- <th key={headerIndex} className="kol-table-cell-title">{header}</th>
401
- ))}
402
- </tr>
403
- </thead>
404
- <tbody>
405
- {block.rows.map((row, rowIndex) => (
406
- <tr key={rowIndex} className="kol-table-row">
407
- {row.map((cell, cellIndex) => (
408
- <td key={cellIndex} className="kol-table-cell-text">
409
- {cell.tokens ? renderTokens(cell.tokens, `${blockKey}-row-${rowIndex}-cell-${cellIndex}`) : cell.content}
410
- </td>
411
- ))}
412
- </tr>
413
- ))}
414
- </tbody>
415
- </table>
416
- </div>
417
- )
418
- default:
419
- return null
420
- }
421
- })}
422
- </section>
344
+ <DocSection key={id} id={id} title={heading}>
345
+ {blocks.map((block, index) => renderBlock(block, `${id}-${block.type}-${index}`))}
346
+ </DocSection>
423
347
  ))}
424
348
  </DocsArticle>
425
349
  )
@@ -37,15 +37,19 @@ export const renderInlineTokens = (
37
37
  return <em key={tokenKey}>{token.content}</em>
38
38
 
39
39
  case 'code':
40
- return <code key={tokenKey}>{token.content}</code>
40
+ return <code key={tokenKey} className="kol-doc-code-inline">{token.content}</code>
41
41
 
42
42
  case 'link': {
43
+ /* One link idiom across doc surfaces (wave-4 retype): the anchor
44
+ * treatment from showcase mdx-components.jsx — colorless per the
45
+ * link law, emphasis + quiet underline. */
46
+ const linkCls = 'text-emphasis underline decoration-fg-16 underline-offset-2 hover:decoration-current'
43
47
  // For .md links, try to resolve to an app route
44
48
  if (resolveDocLink && token.url.includes('.md')) {
45
49
  const route = resolveDocLink(token.url)
46
50
  if (route) {
47
51
  return (
48
- <Link key={tokenKey} to={route} className="docs-link">
52
+ <Link key={tokenKey} to={route} className={linkCls}>
49
53
  {token.text}
50
54
  </Link>
51
55
  )
@@ -54,7 +58,7 @@ export const renderInlineTokens = (
54
58
  return token.text
55
59
  }
56
60
  return (
57
- <a key={tokenKey} href={token.url} className="docs-link">
61
+ <a key={tokenKey} href={token.url} className={linkCls}>
58
62
  {token.text}
59
63
  </a>
60
64
  )