@kolkrabbi/kol-workshop 0.3.1 → 0.3.2

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.1",
3
+ "version": "0.3.2",
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,10 +14,10 @@
14
14
  "dependencies": {
15
15
  "d3": "^7.9.0",
16
16
  "@kolkrabbi/kol-brand": "^0.1.2",
17
+ "@kolkrabbi/kol-component": "0.14.0",
17
18
  "@kolkrabbi/kol-icons": "0.8.10",
18
- "@kolkrabbi/kol-component": "0.13.1",
19
- "@kolkrabbi/kol-framework": "0.6.4",
20
- "@kolkrabbi/kol-theme": "0.12.2"
19
+ "@kolkrabbi/kol-framework": "0.7.0",
20
+ "@kolkrabbi/kol-theme": "0.13.0"
21
21
  },
22
22
  "peerDependencies": {
23
23
  "react": "^18.3.0 || ^19.0.0",
@@ -172,6 +172,13 @@ const DocumentationReader = ({
172
172
 
173
173
  const rawMarkdown = useMemo(() => {
174
174
  if (!doc) return null
175
+ /* Primary resolution (2026-07-30): through the doc's own file path — exact
176
+ * and collision-proof (the endsWith(docId) heuristic below grabbed the
177
+ * FIRST basename match, so duplicate filenames across folders rendered the
178
+ * wrong doc). The heuristic stays as a fallback for hand-built inventories
179
+ * whose `file` doesn't mirror the module keys. */
180
+ const byFile = doc.file && Object.keys(modules).find((p) => p.endsWith(doc.file))
181
+ if (byFile) return modules[byFile]
175
182
  // For index files, the docId is like "00-metadata-index" but the file is "index.md"
176
183
  // For regular files, docId matches the filename (e.g., "0.0.1-writing-guidelines")
177
184
  const path = Object.keys(modules).find((p) => {
@@ -25,17 +25,27 @@ export function buildInventory(modules) {
25
25
  const parentFolder = normalisedPath.split('/').slice(-2, -1)[0] ?? ''
26
26
  const baseId = filename.replace(/\.md$/, '')
27
27
 
28
- // Make index.md IDs unique by prefixing with parent folder
29
- const id = baseId === 'index' ? `${parentFolder}-index` : baseId
28
+ // Make index.md / INDEX.md IDs unique by prefixing with parent folder
29
+ const id = baseId.toLowerCase() === 'index' ? `${parentFolder}-${baseId}` : baseId
30
30
 
31
31
  const rawTitle = title || metadata.title || id
32
32
  const cleanTitle = rawTitle
33
33
  .replace(/^Design System\s*[-–—:]\s*/i, '')
34
34
  .replace(/\bCheat Sheet\b/i, 'Quicklook')
35
35
 
36
- return { id, file: normalisedPath, title: cleanTitle, metadata }
36
+ return { id, file: normalisedPath, title: cleanTitle, metadata, parentFolder }
37
37
  })
38
38
 
39
+ /* Collision safety (2026-07-30): filename-only ids collide across folders in
40
+ * any real vault (02-icons/01-inventory vs 03-components/01-inventory — the
41
+ * React dup-key bug from the 07-29 vault experiment). A collided id gains
42
+ * its parent folder, same convention the index handling already uses. */
43
+ const counts = inventory.reduce((m, d) => (m[d.id] = (m[d.id] ?? 0) + 1, m), {})
44
+ for (const d of inventory) {
45
+ if (counts[d.id] > 1) d.id = `${d.parentFolder}-${d.id}`
46
+ }
47
+ for (const d of inventory) delete d.parentFolder
48
+
39
49
  inventory.sort((a, b) => a.file.localeCompare(b.file))
40
50
  return inventory
41
51
  }
@@ -21,8 +21,12 @@ export const ShellFullHeightContext = createContext(null)
21
21
  // useLayoutEffect(() => { setTocCollapsed(true) ; return () => setTocCollapsed(false) }, [setTocCollapsed])
22
22
  export const ShellTocCollapsedContext = createContext(null)
23
23
 
24
+ /* overflow-x-hidden (2026-07-30): long tree rows (component names + counters)
25
+ * overflowed the 256px rail into an internal horizontal scroll — with the
26
+ * scrollbar hidden it read as content silently walking off, and the pan
27
+ * gesture shoved the whole grid sideways exposing the outer padding. */
24
28
  const NavColumn = ({ children }) => (
25
- <aside aria-label="Navigation" className="shell-sidebar-sticky hidden lg:block shrink-0 h-full min-h-0 overflow-y-auto overscroll-none pt-6 md:pt-6 lg:pt-8 pb-8">
29
+ <aside aria-label="Navigation" className="shell-sidebar-sticky hidden lg:block shrink-0 h-full min-h-0 overflow-y-auto overflow-x-hidden overscroll-none pt-6 md:pt-6 lg:pt-8 pb-8">
26
30
  {children}
27
31
  </aside>
28
32
  )
@@ -41,7 +45,7 @@ const MainColumn = ({ children, fullHeight }) => (
41
45
  )
42
46
 
43
47
  const TocColumn = ({ children }) => (
44
- <aside aria-label="Table of contents" className="shell-sidebar-sticky hidden lg:block shrink-0 h-full min-h-0 overflow-y-auto overscroll-none pt-6 md:pt-6 lg:pt-8 pb-8">
48
+ <aside aria-label="Table of contents" className="shell-sidebar-sticky hidden lg:block shrink-0 h-full min-h-0 overflow-y-auto overflow-x-hidden overscroll-none pt-6 md:pt-6 lg:pt-8 pb-8">
45
49
  {children}
46
50
  </aside>
47
51
  )