@kolkrabbi/kol-workshop 0.31.0 → 0.32.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kolkrabbi/kol-workshop",
3
- "version": "0.31.0",
3
+ "version": "0.32.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,9 +13,9 @@
13
13
  },
14
14
  "dependencies": {
15
15
  "d3": "^7.9.0",
16
- "@kolkrabbi/kol-search": "^0.2.0",
17
16
  "@kolkrabbi/kol-brand": "^0.1.3",
18
- "@kolkrabbi/kol-markdown": "^0.1.2"
17
+ "@kolkrabbi/kol-markdown": "^0.1.2",
18
+ "@kolkrabbi/kol-search": "^0.2.0"
19
19
  },
20
20
  "peerDependencies": {
21
21
  "@kolkrabbi/kol-component": ">=0.228.0",
@@ -28,9 +28,9 @@
28
28
  },
29
29
  "devDependencies": {
30
30
  "@kolkrabbi/kol-component": "^0.230.0",
31
- "@kolkrabbi/kol-framework": "^0.46.0",
32
- "@kolkrabbi/kol-theme": "^0.157.0",
33
- "@kolkrabbi/kol-icons": "^0.29.1"
31
+ "@kolkrabbi/kol-icons": "^0.30.0",
32
+ "@kolkrabbi/kol-theme": "^0.158.0",
33
+ "@kolkrabbi/kol-framework": "^0.47.0"
34
34
  },
35
35
  "files": [
36
36
  "src",
@@ -79,9 +79,39 @@ export const SHELL_SCROLL_ROOT = '#shell-scroll'
79
79
  * overflow (`.shell-rail`, kol-components-workshop.css): exactly one region
80
80
  * tall, a seam toward the page, the chrome inset inside the seam.
81
81
  * overflow-x-hidden (2026-07-30): long tree rows must not scroll sideways. */
82
- const NavColumn = ({ children }) => (
82
+ /* RESIZABLE RAILS (2026-09-30, the names audit; Round 3 Q3 — decided on the recommendation, the
83
+ * user asleep, for review). A 6px grab strip on the edge facing the page: drag to set the width
84
+ * (200–420, remembered), double-click to reset to the shell's 256. The width is the shell's own
85
+ * token, `--kol-shell-nav-w` / `--kol-shell-toc-w`, set on the shell root, so the grid tracks and
86
+ * the rail's own box follow it. */
87
+ const RAIL_MIN = 200
88
+ const RAIL_MAX = 420
89
+ const RailGrip = ({ side, width, onChange }) => {
90
+ const start = (e) => {
91
+ e.preventDefault()
92
+ const x0 = e.clientX
93
+ const w0 = width
94
+ const move = (m) => onChange(Math.round(Math.min(RAIL_MAX, Math.max(RAIL_MIN, w0 + (side === 'end' ? m.clientX - x0 : x0 - m.clientX)))))
95
+ const up = () => { window.removeEventListener('pointermove', move); window.removeEventListener('pointerup', up) }
96
+ window.addEventListener('pointermove', move)
97
+ window.addEventListener('pointerup', up)
98
+ }
99
+ return (
100
+ <div
101
+ role="separator"
102
+ aria-orientation="vertical"
103
+ aria-label="Resize rail"
104
+ onPointerDown={start}
105
+ onDoubleClick={() => onChange(null)}
106
+ className={`absolute top-0 hidden h-full w-1.5 cursor-col-resize hover:bg-oq-08 lg:block ${side === 'end' ? 'right-0' : 'left-0'}`}
107
+ />
108
+ )
109
+ }
110
+
111
+ const NavColumn = ({ children, grip }) => (
83
112
  <aside aria-label="Navigation" className="shell-rail shell-rail--nav shell-sidebar-sticky hidden lg:block pt-6 md:pt-6 lg:pt-8 pb-8">
84
113
  {children}
114
+ {grip}
85
115
  </aside>
86
116
  )
87
117
 
@@ -118,8 +148,9 @@ const MainColumn = ({ children, fullHeight, width = 'canvas', padStart, padEnd }
118
148
  /* `xl`, not `lg` — the grid only declares a third column at xl (gridCols
119
149
  * below). The breakpoint here and the one in gridCols are one decision and
120
150
  * must not be stated twice differently. */
121
- const TocColumn = ({ children }) => (
151
+ const TocColumn = ({ children, grip }) => (
122
152
  <aside aria-label="Table of contents" className="shell-rail shell-rail--toc shell-sidebar-sticky hidden xl:block pt-6 md:pt-6 lg:pt-8 pb-8">
153
+ {grip}
123
154
  {/* The width is the grid track (--kol-shell-toc-w). An empty rail still
124
155
  * holds its column (user ruling 2026-08-01): a rail that disappears
125
156
  * re-flows main and the same page ends up at two widths. */}
@@ -164,6 +195,10 @@ const ShellLayout = ({ routes = [], basePath = '/', brand: brandProp, brandLogoS
164
195
  const [prefs, setPrefs] = useState(readSettings)
165
196
  const setPref = (key, value) => setPrefs((p) => { const next = { ...p, [key]: value }; writeSettings(next); return next })
166
197
  const [navCollapsed, setNavCollapsed] = useState(() => readSettings().navHidden === true)
198
+ /* rail widths — null = the shell's token; a number is the viewer's own (remembered) */
199
+ const [navW, setNavW] = useState(() => readSettings().navW ?? null)
200
+ const [tocW, setTocW] = useState(() => readSettings().tocW ?? null)
201
+ const setRailW = (key, set) => (w) => { set(w); writeSettings({ ...readSettings(), [key]: w }) }
167
202
  const [tocCollapsed, setTocCollapsed] = useState(() => readSettings().tocHidden === true)
168
203
  const [isSettingsOpen, setIsSettingsOpen] = useState(false)
169
204
  /* ONE QUERY (user ruling 2026-08-01). The palette's text used to live here
@@ -430,13 +465,17 @@ const ShellLayout = ({ routes = [], basePath = '/', brand: brandProp, brandLogoS
430
465
  <ShellContentWidthContext.Provider value={setContentWidth}>
431
466
  <ShellTocCollapsedContext.Provider value={setTocCollapsed}>
432
467
  <ShellNavCollapsedContext.Provider value={setNavCollapsed}>
433
- <div className="fixed inset-0 flex flex-col bg-surface-primary text-auto">
468
+ <div
469
+ className="fixed inset-0 flex flex-col bg-surface-primary text-auto"
470
+ style={{ ...(navW ? { '--kol-shell-nav-w': `${navW}px` } : {}), ...(tocW ? { '--kol-shell-toc-w': `${tocW}px` } : {}) }}
471
+ >
434
472
  <ShellHeader
435
473
  brand={brand}
436
474
  nav={navItems}
437
475
  isActive={isActive}
438
476
  onNavigate={handleNavigate}
439
477
  actions={searchTrigger}
478
+ menuBelowLg
440
479
  onMenuClick={() => {
441
480
  if (window.matchMedia('(min-width: 1024px)').matches) {
442
481
  /* Both rails to ONE target state — independent `!p` flips made
@@ -464,7 +503,7 @@ const ShellLayout = ({ routes = [], basePath = '/', brand: brandProp, brandLogoS
464
503
  >
465
504
  <div className={`shell-content-grid grid ${gridCols}`} data-layout={layoutType} style={{ paddingInline: 'var(--kol-pad-chrome-x)' }}>
466
505
  {showNav && (
467
- <NavColumn>
506
+ <NavColumn grip={<RailGrip side="end" width={navW ?? 256} onChange={setRailW('navW', setNavW)} />}>
468
507
  {renderSidebar ? renderSidebar({ activeRoute }) : <ShellSidebar routes={routes} basePath={basePath} />}
469
508
  </NavColumn>
470
509
  )}
@@ -482,7 +521,7 @@ const ShellLayout = ({ routes = [], basePath = '/', brand: brandProp, brandLogoS
482
521
  * the grid's third track so main keeps one width across
483
522
  * every route (user ruling 2026-08-01). */}
484
523
  {showToc && (
485
- <TocColumn>
524
+ <TocColumn grip={<RailGrip side="start" width={tocW ?? 256} onChange={setRailW('tocW', setTocW)} />}>
486
525
  {effectiveTocContent}
487
526
  </TocColumn>
488
527
  )}