@kolkrabbi/kol-shell 0.35.0 → 0.37.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-shell",
3
- "version": "0.35.0",
3
+ "version": "0.37.0",
4
4
  "private": false,
5
5
  "description": "KOL application shell — fixed 48px NavRail + AppShell layout root, PageShell/PageHeader scaffolds, ContentFilters catalog organism, GridCard, SettingsScaffold, WalkthroughPanel, ShortcutsOverlay. App chrome (kol-framework owns site chrome). Nav items, content, shortcuts and settings are consumer-injected. Sits above @kolkrabbi/kol-{theme,component,framework}.",
6
6
  "license": "MIT",
@@ -20,10 +20,10 @@
20
20
  "react-dom": "^18.3.0 || ^19.0.0"
21
21
  },
22
22
  "devDependencies": {
23
- "@kolkrabbi/kol-component": "^0.152.0",
24
- "@kolkrabbi/kol-framework": "^0.36.0",
23
+ "@kolkrabbi/kol-component": "^0.154.1",
25
24
  "@kolkrabbi/kol-icons": "^0.25.0",
26
- "@kolkrabbi/kol-theme": "^0.121.0"
25
+ "@kolkrabbi/kol-framework": "^0.36.0",
26
+ "@kolkrabbi/kol-theme": "^0.122.0"
27
27
  },
28
28
  "files": [
29
29
  "src",
package/src/AppShell.jsx CHANGED
@@ -56,6 +56,14 @@ import TouchDeviceOverlay, { useTouchPrimary } from './TouchDeviceOverlay.jsx'
56
56
  * `bare` renders the children with NO shell on a coarse-pointer device unless
57
57
  * localStorage `kol-desktop` is '1' (fxr's gate); `overlay` keeps the shell and
58
58
  * mounts TouchDeviceOverlay once (monitor's)
59
+ * @param {string[]} [props.drawerOpenOn=[]] paths whose ENTRY opens the drawer (ShellDrawerOpenOnRoute,
60
+ * kol-mirror 2026-09-01 — user: "the rail should load open on home, not
61
+ * everywhere"): a home that is a catalog IS navigation, and arriving there
62
+ * with the nav folded hides the one thing the page is for. Matched like the
63
+ * rail's active row — `'/'` exact, anything else by prefix. Every other path
64
+ * keeps the close-on-navigate rule; above `drawerBelow` there is no drawer
65
+ * and the list is inert. A list, not a boolean: the policy is per-route and
66
+ * the shell already owns the route.
59
67
  * @param {string} props.appName TouchDeviceOverlay's subject
60
68
  * @param {boolean} props.navKeys Option+1…9 navigates to the rail's nth ROW through `onNavigate` — with a
61
69
  * `logomark` that is the mark ('/') then the items, which is the order on
@@ -107,6 +115,7 @@ export default function AppShell({
107
115
  settingsPath,
108
116
  settingsKey,
109
117
  drawerBelow = 768,
118
+ drawerOpenOn = [],
110
119
  children,
111
120
  }) {
112
121
  const [navHidden, setNavHidden] = useState(false)
@@ -193,10 +202,13 @@ export default function AppShell({
193
202
  * `setNavHidden(false)` also made `navHidden` unusable as a consumer seam —
194
203
  * child effects run before parent effects, so a consumer hiding the rail on a
195
204
  * path change was overwritten in the same commit. */
205
+ /* …unless the destination is one where nav IS the page (`drawerOpenOn`):
206
+ * there the entry OPENS it. Runs on mount, on the fold and on navigation
207
+ * alike — `drawer` is a dep — so a phone arriving on home gets the rail. */
196
208
  useEffect(() => {
197
- if (drawer) setDrawerOpen(false)
209
+ if (drawer) setDrawerOpen(drawerOpenOn.some((p) => (p === '/' ? currentPath === '/' : currentPath.startsWith(p))))
198
210
  else setNavHidden(false)
199
- }, [currentPath, drawer])
211
+ }, [currentPath, drawer, drawerOpenOn])
200
212
 
201
213
  /* THE WASH ALSO GOES ON THE ROOT (2026-08-30). It is set on the content
202
214
  * wrapper below, which every page inherits — but a PORTALLED surface does
@@ -9,9 +9,20 @@ import { SettingsRow } from '@kolkrabbi/kol-component'
9
9
  /**
10
10
  * SettingsShortcuts — the keyboard-shortcuts block of a settings page
11
11
  * (ShellHomeSystem, kol-fxr 2026-08-27): the same `[{ section, items: [{ id,
12
- * label, combo }] }]` array `ShortcutsOverlay` takes, laid out six columns ×
12
+ * label, combo }] }]` array `ShortcutsOverlay` takes, laid out UP TO six columns ×
13
13
  * two sections per column, filled column-first (user, 2026-08-27) — each
14
- * section an eyebrow (`kol-eyebrow`, strong ink) over SettingsRows. A combo is one
14
+ * section an eyebrow (`kol-eyebrow`, strong ink) over SettingsRows. The six
15
+ * is a CEILING, not a command (SettingsShortcutsGridColumns, kol-mirror
16
+ * 2026-09-01 — the fourth home of the cols-as-command defect, unswept when
17
+ * CatalogPage was the third): `grid-cols-6` computed six 18px slivers in a
18
+ * 350px row. Same idiom as CatalogPage / ContentCollection — no track under
19
+ * the 150px floor (`GRAB AND PAN THE DESK` / `Space + drag`, the widest cells
20
+ * in the estate), none wider than the container, and the count falls out of
21
+ * the width: two at 390, six on the desk, where the sixth-share clears the
22
+ * floor so nothing moves. Below `md` the grid flows by ROW — the two-row
23
+ * column-first shape is a desk ruling and would overflow implicit columns
24
+ * off the right edge on a phone. Gap is `gap-x-6 md:gap-x-12`, the rung
25
+ * ContentFiltersMobileGaps set for this shape (48px was 17% of the row). A combo is one
15
26
  * token by nature — the value cell is `whitespace-nowrap` and the label yields
16
27
  * (SettingsShortcutsComboWrap, kol-monitor 2026-08-27: `⌘ K` broke as `⌘` over
17
28
  * `K` in the six-column grid — the cell was squeezed to min-content, not full).
@@ -27,7 +38,10 @@ import { SettingsRow } from '@kolkrabbi/kol-component'
27
38
  */
28
39
  export default function SettingsShortcuts({ sections = [], comboLabel = (c) => c, className = '' }) {
29
40
  return (
30
- <div className={`grid grid-cols-6 grid-rows-2 grid-flow-col gap-x-12 gap-y-6 ${className}`.trim()}>
41
+ <div
42
+ className={`grid md:grid-rows-2 md:grid-flow-col gap-x-6 md:gap-x-12 gap-y-6 ${className}`.trim()}
43
+ style={{ gridTemplateColumns: 'repeat(auto-fill, minmax(min(100%, max(150px, calc((100% - 5 * 48px) / 6))), 1fr))' }}
44
+ >
31
45
  {sections.map(({ section, items }) => (
32
46
  <div key={section} style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
33
47
  <span className="kol-eyebrow text-strong mb-2">{section}</span>