@kolkrabbi/kol-workshop 0.4.0 → 0.5.0
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 +4 -4
- package/src/docs/DocsFrontmatter.jsx +30 -12
- package/src/docs/DocumentationReader.jsx +38 -12
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kolkrabbi/kol-workshop",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
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",
|
|
@@ -13,11 +13,11 @@
|
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"d3": "^7.9.0",
|
|
16
|
-
"@kolkrabbi/kol-brand": "^0.1.2",
|
|
17
16
|
"@kolkrabbi/kol-icons": "0.8.11",
|
|
18
|
-
"@kolkrabbi/kol-
|
|
17
|
+
"@kolkrabbi/kol-component": "0.14.3",
|
|
18
|
+
"@kolkrabbi/kol-brand": "^0.1.2",
|
|
19
19
|
"@kolkrabbi/kol-theme": "0.13.3",
|
|
20
|
-
"@kolkrabbi/kol-
|
|
20
|
+
"@kolkrabbi/kol-framework": "0.9.1"
|
|
21
21
|
},
|
|
22
22
|
"peerDependencies": {
|
|
23
23
|
"react": "^18.3.0 || ^19.0.0",
|
|
@@ -21,22 +21,40 @@ const FIELD_ICONS = {
|
|
|
21
21
|
modified: null,
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
/*
|
|
25
|
-
* required
|
|
26
|
-
*
|
|
24
|
+
/* Reading ORDER, not an allowlist. The kol-docs contract first
|
|
25
|
+
* (`.kol/docs-framework/01-conventions.md`: required title/type/status/updated/
|
|
26
|
+
* tags, then recommended description/aliases, then optional), legacy
|
|
27
|
+
* sample-dialect keys after, and ANY key not named here after that — so a field
|
|
28
|
+
* can never be silently dropped for being unknown.
|
|
27
29
|
*
|
|
28
|
-
* This
|
|
30
|
+
* This was a filter over ['title','category','date','tags','modified'] — the
|
|
29
31
|
* workshop-SAMPLE dialect. No kol-docs document carries category/date/modified,
|
|
30
|
-
* so
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
32
|
+
* so it admitted title + tags and discarded the seven fields the parser had
|
|
33
|
+
* already handed it. The panel wasn't missing data; it was screening for the
|
|
34
|
+
* wrong schema, and screening is now the thing it doesn't do.
|
|
35
|
+
*
|
|
36
|
+
* `related` is the one deliberate omission — the rail renders it as live links,
|
|
37
|
+
* so printing the raw wikilinks here would be the same thing twice. */
|
|
34
38
|
const FIELD_ORDER = [
|
|
35
|
-
'title', 'type', 'status', 'updated', '
|
|
36
|
-
'description', '
|
|
37
|
-
'
|
|
39
|
+
'title', 'type', 'status', 'updated', 'tags',
|
|
40
|
+
'description', 'aliases',
|
|
41
|
+
'created', 'verified', 'audience', 'superseded_by', 'drift',
|
|
42
|
+
'category', 'date', 'modified', 'version',
|
|
38
43
|
]
|
|
39
44
|
|
|
45
|
+
const HIDDEN = new Set(['related'])
|
|
46
|
+
|
|
47
|
+
/** Contract order first, then anything else the doc carries, alphabetically. */
|
|
48
|
+
const orderFields = (metadata) => {
|
|
49
|
+
const present = Object.keys(metadata).filter(
|
|
50
|
+
(k) => !HIDDEN.has(k) && metadata[k] != null && metadata[k] !== '' &&
|
|
51
|
+
!(Array.isArray(metadata[k]) && metadata[k].length === 0)
|
|
52
|
+
)
|
|
53
|
+
const known = FIELD_ORDER.filter((k) => present.includes(k))
|
|
54
|
+
const rest = present.filter((k) => !FIELD_ORDER.includes(k)).sort()
|
|
55
|
+
return [...known, ...rest]
|
|
56
|
+
}
|
|
57
|
+
|
|
40
58
|
/* Every field rendered as a date. `updated`/`created`/`verified` are the
|
|
41
59
|
* kol-docs names; `date`/`modified` are the sample dialect's. */
|
|
42
60
|
const DATE_FIELDS = new Set(['updated', 'created', 'verified', 'date', 'modified'])
|
|
@@ -52,7 +70,7 @@ const DocsFrontmatter = ({ metadata, docId }) => {
|
|
|
52
70
|
const { openTagMode } = useTagMode()
|
|
53
71
|
if (!metadata || Object.keys(metadata).length === 0) return null
|
|
54
72
|
|
|
55
|
-
const fields =
|
|
73
|
+
const fields = orderFields(metadata)
|
|
56
74
|
|
|
57
75
|
if (fields.length === 0) return null
|
|
58
76
|
|
|
@@ -10,18 +10,41 @@ import DocsFrontmatter from './DocsFrontmatter.jsx'
|
|
|
10
10
|
import { DocSection } from './DocKit.jsx'
|
|
11
11
|
import { renderInlineTokens } from './render-tokens.jsx'
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
)
|
|
13
|
+
/**
|
|
14
|
+
* A rail section header. Same anatomy as the LEFT tree's group header — a
|
|
15
|
+
* rotating chevron, the label, and the item count pushed right — because the
|
|
16
|
+
* two rails are one system and a reader shouldn't have to learn each side
|
|
17
|
+
* separately.
|
|
18
|
+
*
|
|
19
|
+
* These were bare text. They collapsed on click with no chevron, no count and
|
|
20
|
+
* no hover, so the only way to discover they were interactive was to click
|
|
21
|
+
* something that looked inert and watch the panel vanish. An affordance that
|
|
22
|
+
* only announces itself after you've used it isn't one.
|
|
23
|
+
*/
|
|
24
|
+
const SidebarSection = ({ sectionKey, label, count, collapsedSections, toggleSection, children }) => {
|
|
25
|
+
const isOpen = !collapsedSections[sectionKey]
|
|
26
|
+
return (
|
|
27
|
+
<div>
|
|
28
|
+
<button
|
|
29
|
+
type="button"
|
|
30
|
+
className="shell-nav-group-header w-full text-left shell-sidebar-label kol-doc-eyebrow"
|
|
31
|
+
onClick={() => toggleSection(sectionKey)}
|
|
32
|
+
aria-expanded={isOpen}
|
|
33
|
+
>
|
|
34
|
+
<span className="flex items-center gap-2">
|
|
35
|
+
<Icon
|
|
36
|
+
name="chevron-right"
|
|
37
|
+
size={12}
|
|
38
|
+
className={`transition-transform ${isOpen ? 'rotate-90' : ''}`}
|
|
39
|
+
/>
|
|
40
|
+
{label}
|
|
41
|
+
</span>
|
|
42
|
+
{count > 0 && <span className="kol-mono-14 text-subtle">({count})</span>}
|
|
43
|
+
</button>
|
|
44
|
+
{isOpen && children}
|
|
45
|
+
</div>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
25
48
|
|
|
26
49
|
const DocReaderSidebar = ({ toc, allTags, related, docId, docsIndexHref, componentsHref, docFilePath }) => {
|
|
27
50
|
const navigate = useNavigate()
|
|
@@ -34,6 +57,7 @@ const DocReaderSidebar = ({ toc, allTags, related, docId, docsIndexHref, compone
|
|
|
34
57
|
<SidebarSection
|
|
35
58
|
sectionKey="toc"
|
|
36
59
|
label="On this page"
|
|
60
|
+
count={toc?.length}
|
|
37
61
|
collapsedSections={collapsedSections}
|
|
38
62
|
toggleSection={toggleSection}
|
|
39
63
|
>
|
|
@@ -44,6 +68,7 @@ const DocReaderSidebar = ({ toc, allTags, related, docId, docsIndexHref, compone
|
|
|
44
68
|
<SidebarSection
|
|
45
69
|
sectionKey="related"
|
|
46
70
|
label="Related"
|
|
71
|
+
count={related.length}
|
|
47
72
|
collapsedSections={collapsedSections}
|
|
48
73
|
toggleSection={toggleSection}
|
|
49
74
|
>
|
|
@@ -100,6 +125,7 @@ const DocReaderSidebar = ({ toc, allTags, related, docId, docsIndexHref, compone
|
|
|
100
125
|
{allTags.length > 0 && (
|
|
101
126
|
<SidebarSection
|
|
102
127
|
sectionKey="tags"
|
|
128
|
+
count={allTags?.length}
|
|
103
129
|
label="Tags"
|
|
104
130
|
collapsedSections={collapsedSections}
|
|
105
131
|
toggleSection={toggleSection}
|