@kolkrabbi/kol-shell 0.46.0 → 0.48.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/CatalogPage.jsx +59 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kolkrabbi/kol-shell",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.48.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",
|
|
@@ -14,16 +14,16 @@
|
|
|
14
14
|
"peerDependencies": {
|
|
15
15
|
"@kolkrabbi/kol-component": ">=0.174.0",
|
|
16
16
|
"@kolkrabbi/kol-icons": ">=0.16.0",
|
|
17
|
-
"@kolkrabbi/kol-theme": ">=0.
|
|
17
|
+
"@kolkrabbi/kol-theme": ">=0.138.0",
|
|
18
18
|
"gsap": "^3.13.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.176.0",
|
|
24
|
-
"@kolkrabbi/kol-framework": "^0.41.0",
|
|
25
23
|
"@kolkrabbi/kol-icons": "^0.25.0",
|
|
26
|
-
"@kolkrabbi/kol-
|
|
24
|
+
"@kolkrabbi/kol-component": "^0.177.0",
|
|
25
|
+
"@kolkrabbi/kol-framework": "^0.42.0",
|
|
26
|
+
"@kolkrabbi/kol-theme": "^0.138.0"
|
|
27
27
|
},
|
|
28
28
|
"files": [
|
|
29
29
|
"src",
|
package/src/CatalogPage.jsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useCallback, useRef, useState } from 'react'
|
|
1
2
|
import { ContentCard, ContentFilters, ContentRow } from '@kolkrabbi/kol-component'
|
|
2
3
|
import PageShell from './PageShell.jsx'
|
|
3
4
|
import { PageHeader } from '@kolkrabbi/kol-component'
|
|
@@ -18,8 +19,11 @@ import WalkthroughPanel from './WalkthroughPanel.jsx'
|
|
|
18
19
|
*
|
|
19
20
|
* Semantics are the consumer's: what RECENT / SAVED mean, what an item is,
|
|
20
21
|
* what a click does. `toCard(item, { view, layout })` → `{ key, title, detail,
|
|
21
|
-
*
|
|
22
|
-
*
|
|
22
|
+
* …every prop ContentCard / ContentRow takes }` — `title`, `detail`, `media`,
|
|
23
|
+
* `actions`, `onClick`, `href`, `onNavigate`, `expanded`, `expandedContent`, `fit`,
|
|
24
|
+
* `ratio`, `date`, `size`, `meta`, `tags`, `selected`, `variant`, … — is the whole
|
|
25
|
+
* contract: the return is SPREAD onto the card or the row (user ruling 2026-09-03,
|
|
26
|
+
* a composition forwards the whole contract of what it composes) — `expanded` / `expandedContent` reach `ContentCard catalog`'s
|
|
23
27
|
* 2×2 cell (ShellHomeSystemMonitorGaps, kol-monitor 2026-08-27) — and the page
|
|
24
28
|
* HIDES the cell's three neighbours itself (CatalogPageMonitorParity: the
|
|
25
29
|
* consumer never sees the filtered row order, so it cannot; monitor's
|
|
@@ -50,7 +54,10 @@ import WalkthroughPanel from './WalkthroughPanel.jsx'
|
|
|
50
54
|
* framework container — the site tier, so a brand book adopting this page keeps its geometry
|
|
51
55
|
* @param {ReactNode} trailingActions the header's RIGHT slot (ContentFilters' — MediaLibrary's SELECT / FLAT); never empty beside the divider
|
|
52
56
|
* @param {number} minColumn the grid track's floor in px (default 160); a shelf of three decks passes 280 — the six-track ceiling still applies
|
|
53
|
-
* @param {
|
|
57
|
+
* @param {string} cardVariant the grid card's variant, per page (default `catalog`); `toCard` may return `variant` per card
|
|
58
|
+
* @param {'catalog'|'file'} rowVariant the list row (default `catalog`, the 36px no-thumb row); `file` = the 48px thumb row, for a catalog whose grid shows a cover —
|
|
59
|
+
* its slots (`date` · `size` · `meta` · `selected`) come from `toCard` like everything else
|
|
60
|
+
* @param {'grid'|'stack'} listLayout the list's container (default `grid`, rows four across — monitor's ruling); `stack` = one row per line
|
|
54
61
|
* @param {ElementType} iconComponent icon renderer seam for ContentFilters
|
|
55
62
|
* @param {boolean} showCountOnlyWhenFiltering (default true)
|
|
56
63
|
* @param {Object} filtersProps spread onto ContentFilters last — e.g. `{ mutuallyExclusiveFilters: ['category', 'u_label'] }`
|
|
@@ -103,6 +110,13 @@ export default function CatalogPage({
|
|
|
103
110
|
passes `file`: the 48px thumb row, so the list shows the same cover small
|
|
104
111
|
(kol-client-olina 2026-09-03; user, on the bare row: "ugly ugly ugly"). */
|
|
105
112
|
rowVariant = 'catalog',
|
|
113
|
+
/* the GRID card's variant, per page; `toCard` may return `variant` per card */
|
|
114
|
+
cardVariant = 'catalog',
|
|
115
|
+
/* the LIST's container. `grid` (default) is monitor's ruling — rows four across
|
|
116
|
+
on a 240 floor, gap 8 (the documented `repeat(4, 1fr)`). `stack` is one row per
|
|
117
|
+
line, which is what a list of files is (MediaLibrary stacks); olina's deck list
|
|
118
|
+
rendered three 300px rows side by side (user: "why is it tiny?"). */
|
|
119
|
+
listLayout = 'grid',
|
|
106
120
|
iconComponent,
|
|
107
121
|
showCountOnlyWhenFiltering = true,
|
|
108
122
|
filtersProps,
|
|
@@ -111,8 +125,32 @@ export default function CatalogPage({
|
|
|
111
125
|
style,
|
|
112
126
|
}) {
|
|
113
127
|
const open = walkthrough?.open === true
|
|
128
|
+
/* THE TRACK COUNT, MEASURED (CatalogFilterFirstGroupTrackCount, 2026-09-03).
|
|
129
|
+
* `.kol-catalog-grid` and `.kol-filters-first` both read `--kol-catalog-n`
|
|
130
|
+
* from the page: up to 6 tracks, none narrower than `minColumn`, gap 24 —
|
|
131
|
+
* `min(6, floor((W + 24) / (minColumn + 24)))`, exactly what the old inline
|
|
132
|
+
* `auto-fill` resolved to, now a number the filter row can read too. In JS
|
|
133
|
+
* because the CSS form (`round()` over a length ÷ length) is Chromium-only —
|
|
134
|
+
* theme 0.137.0 rendered ONE column in Firefox. `undefined` until measured
|
|
135
|
+
* → the theme's fallback of 6, the pre-0.137.0 geometry. */
|
|
136
|
+
const [cols, setCols] = useState(null)
|
|
137
|
+
const observer = useRef(null)
|
|
138
|
+
/* a CALLBACK ref: the grid mounts and unmounts with the layout toggle, and a
|
|
139
|
+
* callback ref sees both — an effect keyed on a value out of this scope does
|
|
140
|
+
* not (the first cut referenced `renderItem`'s `layout` here and threw) */
|
|
141
|
+
const gridRef = useCallback((el) => {
|
|
142
|
+
observer.current?.disconnect()
|
|
143
|
+
observer.current = null
|
|
144
|
+
if (!el) return
|
|
145
|
+
const measure = (W) => setCols((c) => { const n = Math.max(1, Math.min(6, Math.floor((W + 24) / (minColumn + 24)))); return c === n ? c : n })
|
|
146
|
+
measure(el.getBoundingClientRect().width)
|
|
147
|
+
const ro = new ResizeObserver(([entry]) => measure(entry.contentRect.width))
|
|
148
|
+
ro.observe(el)
|
|
149
|
+
observer.current = ro
|
|
150
|
+
}, [minColumn])
|
|
151
|
+
|
|
114
152
|
return (
|
|
115
|
-
<PageShell width={width} className={className} style={{ overflow: 'hidden', '--kol-catalog-
|
|
153
|
+
<PageShell width={width} className={className} style={{ overflow: 'hidden', '--kol-catalog-n': cols ?? undefined, ...style }}>
|
|
116
154
|
{header && <PageHeader {...header} />}
|
|
117
155
|
<div style={{ flex: 1, position: 'relative' }}>
|
|
118
156
|
{open && <WalkthroughPanel steps={walkthrough.steps} iconComponent={walkthrough.iconComponent} />}
|
|
@@ -148,17 +186,28 @@ export default function CatalogPage({
|
|
|
148
186
|
* six-column ruling — below the ceiling the hide-set is
|
|
149
187
|
* desktop-only geometry. */
|
|
150
188
|
return (
|
|
151
|
-
/* the catalog grid is a CLASS (`.kol-catalog-grid`, kol-theme ≥0.
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
<div className={layout === 'list' ? undefined : 'kol-catalog-grid'} style={layout === 'list' ? { display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(min(100%, max(240px, calc((100% - 3 * 8px) / 4))), 1fr))', gap: 8 } : undefined}>
|
|
189
|
+
/* the catalog grid is a CLASS (`.kol-catalog-grid`, kol-theme ≥0.138.0) reading
|
|
190
|
+
* `--kol-catalog-n`, the count measured above and set on PageShell — the same
|
|
191
|
+
* number the filter row's first group reads */
|
|
192
|
+
<div ref={layout === 'list' ? undefined : gridRef} className={layout === 'list' ? undefined : 'kol-catalog-grid'} style={layout === 'list' ? (listLayout === 'stack' ? { display: 'flex', flexDirection: 'column', gap: 8 } : { display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(min(100%, max(240px, calc((100% - 3 * 8px) / 4))), 1fr))', gap: 8 }) : undefined}>
|
|
155
193
|
{rows.map((item, i) => {
|
|
156
194
|
if (hidden.has(i)) return null
|
|
157
195
|
const c = cards[i]
|
|
158
196
|
const key = c.key ?? item.key ?? item.id ?? item.name ?? i
|
|
197
|
+
/* A COMPOSITION FORWARDS THE WHOLE CONTRACT OF WHAT IT COMPOSES (user
|
|
198
|
+
* 2026-09-03: "why wouldn't we as standard practice ALLOW VARIANT CHANGE
|
|
199
|
+
* EVERY TIME WE USE THOSE CONTENT CARDS?"). Five tickets on this file in
|
|
200
|
+
* one day were the same defect — a key missing from `toCard` because no
|
|
201
|
+
* prior consumer had needed it: `ratio`, `trailingActions`, `rowVariant`,
|
|
202
|
+
* `date` / `size`, the list container. So `toCard`'s return is SPREAD
|
|
203
|
+
* onto the card and the row: every prop either takes is reachable per
|
|
204
|
+
* card, today and for props not written yet; `variant` per card beats
|
|
205
|
+
* the page's `cardVariant` / `rowVariant`; `fit` keeps its `cover`
|
|
206
|
+
* default. `key` is React's and is lifted out first. */
|
|
207
|
+
const { key: _key, ...forwarded } = c
|
|
159
208
|
return layout === 'list'
|
|
160
|
-
? <ContentRow key={key}
|
|
161
|
-
: <ContentCard key={key}
|
|
209
|
+
? <ContentRow key={key} {...forwarded} variant={c.variant ?? rowVariant} />
|
|
210
|
+
: <ContentCard key={key} {...forwarded} variant={c.variant ?? cardVariant} fit={c.fit ?? 'cover'} />
|
|
162
211
|
})}
|
|
163
212
|
</div>
|
|
164
213
|
)
|