@kolkrabbi/kol-shell 0.13.2 → 0.14.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 +5 -5
- package/src/AppShell.jsx +8 -2
- package/src/NavRail.jsx +41 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kolkrabbi/kol-shell",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.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",
|
|
@@ -13,17 +13,17 @@
|
|
|
13
13
|
},
|
|
14
14
|
"peerDependencies": {
|
|
15
15
|
"@kolkrabbi/kol-component": ">=0.108.0",
|
|
16
|
-
"@kolkrabbi/kol-framework": ">=0.
|
|
16
|
+
"@kolkrabbi/kol-framework": ">=0.34.0",
|
|
17
17
|
"@kolkrabbi/kol-icons": ">=0.16.0",
|
|
18
18
|
"@kolkrabbi/kol-theme": ">=0.80.0",
|
|
19
19
|
"react": "^18.3.0 || ^19.0.0",
|
|
20
20
|
"react-dom": "^18.3.0 || ^19.0.0"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
|
-
"@kolkrabbi/kol-component": "^0.
|
|
23
|
+
"@kolkrabbi/kol-component": "^0.119.0",
|
|
24
|
+
"@kolkrabbi/kol-framework": "^0.34.0",
|
|
24
25
|
"@kolkrabbi/kol-icons": "^0.24.0",
|
|
25
|
-
"@kolkrabbi/kol-
|
|
26
|
-
"@kolkrabbi/kol-theme": "^0.80.0"
|
|
26
|
+
"@kolkrabbi/kol-theme": "^0.81.0"
|
|
27
27
|
},
|
|
28
28
|
"files": [
|
|
29
29
|
"src",
|
package/src/AppShell.jsx
CHANGED
|
@@ -31,7 +31,11 @@ import TouchDeviceOverlay, { useTouchPrimary } from './TouchDeviceOverlay.jsx'
|
|
|
31
31
|
* @param {string} props.currentPath the router's current pathname
|
|
32
32
|
* @param {Function} props.onNavigate `(path) => void`
|
|
33
33
|
* @param {ElementType} props.iconComponent icon renderer seam (see Button)
|
|
34
|
-
* @param {
|
|
34
|
+
* @param {Object} props.settings `{ icon, path, label }` — Settings as a DISCLOSURE in the pinned bottom
|
|
35
|
+
* row (RailSettingsDisclosure, 2026-08-28): click opens a panel above the
|
|
36
|
+
* row with the theme toggle and the settings page as a row; click again,
|
|
37
|
+
* Escape or any navigation closes it. Turns the rail's theme slot off.
|
|
38
|
+
* @param {boolean} props.themeToggle render the ThemeToggle above bottomItems (default true; false when `settings` is given)
|
|
35
39
|
* @param {string} props.railToggleKey a key that toggles the rail (e.g. '\\') — ignored while typing in a field;
|
|
36
40
|
* the rail comes back on every `currentPath` change (ShellHomeSystem, 2026-08-27)
|
|
37
41
|
* @param {'shell'|'bare'|'overlay'} props.touch the touch-primary policy (default 'shell' = the rail regardless):
|
|
@@ -62,6 +66,7 @@ export default function AppShell({
|
|
|
62
66
|
currentPath,
|
|
63
67
|
onNavigate,
|
|
64
68
|
iconComponent,
|
|
69
|
+
settings,
|
|
65
70
|
themeToggle,
|
|
66
71
|
railToggleKey,
|
|
67
72
|
touch = 'shell',
|
|
@@ -130,7 +135,8 @@ export default function AppShell({
|
|
|
130
135
|
currentPath={currentPath}
|
|
131
136
|
onNavigate={onNavigate}
|
|
132
137
|
iconComponent={iconComponent}
|
|
133
|
-
|
|
138
|
+
settings={settings}
|
|
139
|
+
themeToggle={themeToggle ?? !settings}
|
|
134
140
|
/>
|
|
135
141
|
)}
|
|
136
142
|
{/* THE BACK OF THE BACK — surface-primary, always, in every app; the
|
package/src/NavRail.jsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { SideNav } from '@kolkrabbi/kol-framework'
|
|
1
|
+
import { SideNav, ThemeToggle } from '@kolkrabbi/kol-framework'
|
|
2
|
+
import { Icon } from '@kolkrabbi/kol-icons'
|
|
2
3
|
import Logomark from './Logomark.jsx'
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -21,6 +22,17 @@ import Logomark from './Logomark.jsx'
|
|
|
21
22
|
* 0.13.0's footer placement: "why did you move the logo from top to bottom?
|
|
22
23
|
* … I've never seen that before so you are the first"). Its `title` is the
|
|
23
24
|
* label beside the mark in the open rail; collapsed, the mark alone.
|
|
25
|
+
*
|
|
26
|
+
* `settings` — SETTINGS IS A DISCLOSURE, NOT A ROUTE (RailSettingsDisclosure,
|
|
27
|
+
* kol-fxr 2026-08-28 — user: "put the settings where the logo is, and logo
|
|
28
|
+
* back on top" · "sidebar setting should open close on click and click again"
|
|
29
|
+
* · "put the theme toggle in the settings and out of the sidebar" · "we make
|
|
30
|
+
* it work here then ship it"): `{ icon, path, label }` renders the gear as the
|
|
31
|
+
* pinned bottom row — a SideNav panel leaf, same pixel as the route row it
|
|
32
|
+
* replaces — whose panel holds the theme toggle (`icon` collapsed /
|
|
33
|
+
* `hop-bare` expanded, the slot's two variants) and the Settings page as a
|
|
34
|
+
* row. The rail's standing theme slot is off when `settings` is given; the
|
|
35
|
+
* toggle exists in the disclosure and on the settings page only.
|
|
24
36
|
*/
|
|
25
37
|
export default function NavRail({
|
|
26
38
|
items = [],
|
|
@@ -29,17 +41,43 @@ export default function NavRail({
|
|
|
29
41
|
currentPath = '',
|
|
30
42
|
onNavigate,
|
|
31
43
|
iconComponent,
|
|
32
|
-
|
|
44
|
+
settings,
|
|
45
|
+
themeToggle = !settings,
|
|
33
46
|
hidden = false,
|
|
34
47
|
}) {
|
|
35
48
|
if (hidden) return null
|
|
36
49
|
const node = (item) => ({ id: item.path, label: item.label, icon: item.icon, to: item.path })
|
|
50
|
+
const Glyph = iconComponent ?? Icon
|
|
51
|
+
const settingsLeaf = settings && {
|
|
52
|
+
id: settings.path,
|
|
53
|
+
label: settings.label,
|
|
54
|
+
icon: settings.icon,
|
|
55
|
+
panel: ({ collapsed, close }) => (
|
|
56
|
+
<>
|
|
57
|
+
<div className="kol-sidenav-theme-slot flex">
|
|
58
|
+
<ThemeToggle variant={collapsed ? 'icon' : 'hop-bare'} size="md" />
|
|
59
|
+
</div>
|
|
60
|
+
<button
|
|
61
|
+
type="button"
|
|
62
|
+
className="kol-sidenav-hop kol-helper-12 text-strong hover:text-emphasis bg-transparent border-0 cursor-pointer text-left"
|
|
63
|
+
onClick={() => { close(); onNavigate?.(settings.path) }}
|
|
64
|
+
title={settings.label}
|
|
65
|
+
aria-label={settings.label}
|
|
66
|
+
>
|
|
67
|
+
<span className="kol-sidenav-hop-icon inline-flex items-center justify-center w-5 h-5 shrink-0" aria-hidden="true">
|
|
68
|
+
<Glyph name="arrow-right" size={16} />
|
|
69
|
+
</span>
|
|
70
|
+
<span className="kol-sidenav-hop-label flex-1 min-w-0 truncate">{settings.label}</span>
|
|
71
|
+
</button>
|
|
72
|
+
</>
|
|
73
|
+
),
|
|
74
|
+
}
|
|
37
75
|
/* the shell's route match: '/' exact, anything else by prefix */
|
|
38
76
|
const isActive = (to) => (to === '/' ? currentPath === '/' : currentPath.startsWith(to))
|
|
39
77
|
return (
|
|
40
78
|
<SideNav
|
|
41
79
|
navTree={items.map(node)}
|
|
42
|
-
bottomItems={bottomItems.map(node)}
|
|
80
|
+
bottomItems={[...bottomItems.map(node), ...(settingsLeaf ? [settingsLeaf] : [])]}
|
|
43
81
|
currentPath={currentPath}
|
|
44
82
|
isActive={isActive}
|
|
45
83
|
onNavigate={(e, to) => onNavigate?.(to)}
|