@kolkrabbi/kol-component 0.54.0 → 0.56.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 +1 -1
- package/src/organisms/ContentFilters.jsx +50 -38
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kolkrabbi/kol-component",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.56.0",
|
|
4
4
|
"description": "KOL design-system components — atoms through organisms, emitting canonical kol-* classes. Pairs with @kolkrabbi/kol-theme for styling.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -3,6 +3,7 @@ import Tag from '../atoms/Tag.jsx'
|
|
|
3
3
|
import Divider from '../atoms/Divider.jsx'
|
|
4
4
|
import Button from '../atoms/Button.jsx'
|
|
5
5
|
import { Icon } from '@kolkrabbi/kol-icons'
|
|
6
|
+
import { glyphSize } from '../hooks/glyphLadders.js'
|
|
6
7
|
import IconFrame from '../atoms/IconFrame.jsx'
|
|
7
8
|
|
|
8
9
|
/**
|
|
@@ -171,8 +172,13 @@ const ContentFilters = ({
|
|
|
171
172
|
* as the component tier's ONE documented exception to the no-casing law,
|
|
172
173
|
* because a filter value is data with no authoring site. Consumers must not
|
|
173
174
|
* uppercase these themselves. */
|
|
175
|
+
/* A group either STACKS its values in a narrow column or WRAPS them across
|
|
176
|
+
* the room it is given (`group.stack`). Both shapes are live on kol-website's
|
|
177
|
+
* /work: a short closed set like Type reads as a column you scan down, while
|
|
178
|
+
* ~45 tags must wrap or they run off the page. One shape for both meant the
|
|
179
|
+
* short group ate a full row it did not need. */
|
|
174
180
|
const renderFilterGroup = (group) => (
|
|
175
|
-
<div key={group.key} className=
|
|
181
|
+
<div key={group.key} className={`flex flex-col gap-3 ${group.stack ? 'shrink-0' : 'min-w-0 flex-1'}`}>
|
|
176
182
|
{/* THE CATEGORY LABEL IS THE ACTIVE INK — `kol-helper-12` at `text-fg-96`,
|
|
177
183
|
* the same full opacity a SELECTED layout item wears (user ruling
|
|
178
184
|
* 2026-08-15: "TAGS and other categories are ACTIVE state full opacity").
|
|
@@ -186,7 +192,7 @@ const ContentFilters = ({
|
|
|
186
192
|
<h4 className={labelClassName} style={labelUppercase ? { textTransform: 'uppercase' } : undefined}>
|
|
187
193
|
{group.label}
|
|
188
194
|
</h4>
|
|
189
|
-
<div className=
|
|
195
|
+
<div className={group.stack ? 'flex flex-col items-start gap-2' : 'flex flex-wrap gap-2'}>
|
|
190
196
|
{group.values.map((value) => (
|
|
191
197
|
<Tag
|
|
192
198
|
key={value}
|
|
@@ -228,7 +234,11 @@ const ContentFilters = ({
|
|
|
228
234
|
aria-label="Toggle filters"
|
|
229
235
|
style={{ background: 'transparent', border: 'none', cursor: 'pointer', color: 'inherit' }}
|
|
230
236
|
>
|
|
231
|
-
|
|
237
|
+
{/* SOLO ladder, md rung — a 32px square takes a 20px glyph.
|
|
238
|
+
* Both header glyphs were 16 (the sm rung) in md boxes, which is
|
|
239
|
+
* the exact hand-transcription hooks/glyphLadders.js exists to
|
|
240
|
+
* stop and the one ActionButton's docstring already names. */}
|
|
241
|
+
<IconSeam name="filter" size={glyphSize('md', true)} />
|
|
232
242
|
</button>
|
|
233
243
|
<div
|
|
234
244
|
className="kol-expand flex items-center justify-center rounded-sm cursor-pointer hover:bg-fg-04"
|
|
@@ -254,7 +264,7 @@ const ContentFilters = ({
|
|
|
254
264
|
position: searchOpen ? 'absolute' : 'relative',
|
|
255
265
|
}}
|
|
256
266
|
>
|
|
257
|
-
<IconSeam name="search" size={
|
|
267
|
+
<IconSeam name="search" size={glyphSize('md', true)} />
|
|
258
268
|
</span>
|
|
259
269
|
{searchOpen && (
|
|
260
270
|
<input
|
|
@@ -284,6 +294,34 @@ const ContentFilters = ({
|
|
|
284
294
|
</div>
|
|
285
295
|
|
|
286
296
|
<div className="flex items-center gap-8">
|
|
297
|
+
{/* The count and LIST/GRID ride the HEADER row, above the divider.
|
|
298
|
+
*
|
|
299
|
+
* "N of N" appears ONLY while the filter panel is open (user ruling
|
|
300
|
+
* 2026-08-15) — with nothing filtered it always reads "12 of 12",
|
|
301
|
+
* which is a number that has never once told anyone anything. It
|
|
302
|
+
* earns its place the moment a filter can change it.
|
|
303
|
+
*
|
|
304
|
+
* Ink stays `text-fg-64`: static information, not a toggle, so it
|
|
305
|
+
* takes neither the 96 active nor the 32 rest. */}
|
|
306
|
+
{showCount && isExpanded && (
|
|
307
|
+
<span className={countClassName} style={{ letterSpacing: 1 }}>
|
|
308
|
+
{filteredItems.length} of {totalCount}
|
|
309
|
+
</span>
|
|
310
|
+
)}
|
|
311
|
+
{layoutOptions && (
|
|
312
|
+
<div className="flex items-center gap-4">
|
|
313
|
+
{layoutOptions.map((opt) => (
|
|
314
|
+
<span
|
|
315
|
+
key={opt.value}
|
|
316
|
+
onClick={() => setLayout(opt.value)}
|
|
317
|
+
className={`${layoutClassName} cursor-pointer select-none ${layout === opt.value ? stripActiveClassName : stripRestClassName}`}
|
|
318
|
+
style={{ letterSpacing: 1 }}
|
|
319
|
+
>
|
|
320
|
+
{opt.label}
|
|
321
|
+
</span>
|
|
322
|
+
))}
|
|
323
|
+
</div>
|
|
324
|
+
)}
|
|
287
325
|
{/* RECENT / SAVED is the SAME STRIP as LIST / GRID, not a ViewToggle.
|
|
288
326
|
* Read off kol-monitor's original (_tmp/2026-08-15-shell-adoption/
|
|
289
327
|
* ContentFilters.jsx:225-232): inline spans, `kol-helper-14`,
|
|
@@ -312,16 +350,15 @@ const ContentFilters = ({
|
|
|
312
350
|
|
|
313
351
|
<Divider className="mb-4" />
|
|
314
352
|
|
|
315
|
-
{/*
|
|
316
|
-
*
|
|
317
|
-
* label above values — and appear only while the filter toggle is open.
|
|
318
|
-
* The layout strip is right-aligned and ALWAYS visible.
|
|
353
|
+
{/* BELOW the divider: the filter GROUPS only. Left-aligned columns —
|
|
354
|
+
* label above values — visible only while the filter toggle is open.
|
|
319
355
|
*
|
|
320
|
-
*
|
|
321
|
-
*
|
|
322
|
-
*
|
|
323
|
-
*
|
|
324
|
-
|
|
356
|
+
* The count + layout strip moved ABOVE the divider into the header row
|
|
357
|
+
* (user ruling 2026-08-15, later pass), reversing the earlier "one row
|
|
358
|
+
* below the divider" cut. It also settles the defect that ruling was
|
|
359
|
+
* fighting for good: the strip cannot be pushed down the page by an
|
|
360
|
+
* expanding filter group if it is not in the same row as one. */}
|
|
361
|
+
{isExpanded && (
|
|
325
362
|
<div className="flex items-start justify-between gap-16 pb-4">
|
|
326
363
|
<div className="flex items-start gap-16">
|
|
327
364
|
{isExpanded && filterGroups.map((group) => renderFilterGroup(group))}
|
|
@@ -336,31 +373,6 @@ const ContentFilters = ({
|
|
|
336
373
|
</button>
|
|
337
374
|
)}
|
|
338
375
|
</div>
|
|
339
|
-
{/* The count rides the LAYOUT row, not the header (user ruling
|
|
340
|
-
* 2026-08-15) — same `kol-helper-12` + 1px tracking as LIST/GRID
|
|
341
|
-
* beside it. Ink stays `text-fg-64`: it is static information, not
|
|
342
|
-
* a toggle, so it takes neither the 96 active nor the 32 rest. */}
|
|
343
|
-
<div className="flex items-center gap-4 flex-shrink-0">
|
|
344
|
-
{showCount && (
|
|
345
|
-
<span className={countClassName} style={{ letterSpacing: 1 }}>
|
|
346
|
-
{filteredItems.length} of {totalCount}
|
|
347
|
-
</span>
|
|
348
|
-
)}
|
|
349
|
-
{layoutOptions && (
|
|
350
|
-
<div className="flex items-center gap-4">
|
|
351
|
-
{layoutOptions.map((opt) => (
|
|
352
|
-
<span
|
|
353
|
-
key={opt.value}
|
|
354
|
-
onClick={() => setLayout(opt.value)}
|
|
355
|
-
className={`${layoutClassName} cursor-pointer select-none ${layout === opt.value ? stripActiveClassName : stripRestClassName}`}
|
|
356
|
-
style={{ letterSpacing: 1 }}
|
|
357
|
-
>
|
|
358
|
-
{opt.label}
|
|
359
|
-
</span>
|
|
360
|
-
))}
|
|
361
|
-
</div>
|
|
362
|
-
)}
|
|
363
|
-
</div>
|
|
364
376
|
</div>
|
|
365
377
|
)}
|
|
366
378
|
|