@kolkrabbi/kol-component 0.216.0 → 0.217.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 +3 -2
- package/src/atoms/ActionButton.jsx +10 -9
- package/src/atoms/FileIcon.jsx +31 -0
- package/src/atoms/ViewToggle.jsx +35 -17
- package/src/hooks/useMarquee.js +93 -0
- package/src/index.js +3 -0
- package/src/molecules/AudioPreview.jsx +4 -2
- package/src/molecules/AudioSheet.jsx +22 -36
- package/src/molecules/CodeBlock.jsx +4 -2
- package/src/molecules/ContentCard.jsx +13 -0
- package/src/molecules/ContentRow.jsx +9 -0
- package/src/molecules/DocFrontmatter.jsx +1 -1
- package/src/molecules/KindPreview.jsx +91 -5
- package/src/molecules/MediaTile.jsx +29 -0
- package/src/molecules/Modal.jsx +25 -12
- package/src/molecules/PdfPage.jsx +110 -0
- package/src/molecules/PlaybackBar.jsx +16 -8
- package/src/molecules/QuickLookFrame.jsx +88 -0
- package/src/molecules/ShellDrawer.jsx +10 -4
- package/src/molecules/Stepper.jsx +2 -2
- package/src/molecules/VideoSheet.jsx +12 -11
- package/src/organisms/ColumnBrowser.jsx +191 -37
- package/src/organisms/ContentFilters.jsx +29 -13
- package/src/organisms/MediaLibrary.jsx +2 -2
- package/src/organisms/MediaLibraryExplorer.jsx +22 -107
- package/src/organisms/MediaLibraryPages.jsx +1381 -347
- package/src/organisms/SettingsPanel.jsx +16 -6
- package/src/utilities/FullscreenOverlay.jsx +17 -3
- package/src/utilities/Popover.jsx +11 -4
- package/src/utilities/id3.js +3 -0
- package/src/utilities/layerStack.js +18 -0
- package/src/utilities/mediaKinds.js +10 -4
|
@@ -1,116 +1,31 @@
|
|
|
1
1
|
import { useState } from 'react'
|
|
2
|
-
import
|
|
3
|
-
import { MediaLibraryBrowse, MediaLibraryLibrary } from './MediaLibraryPages.jsx'
|
|
2
|
+
import { MediaLibraryBrowse } from './MediaLibraryPages.jsx'
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
|
-
* MediaLibraryExplorer — the
|
|
7
|
-
* SURFACE, which is what `MediaLibraryPages` has called them in its own comments
|
|
8
|
-
* since 2026-09-04 while shipping them as two pages a consumer stacks by hand.
|
|
5
|
+
* MediaLibraryExplorer — the media surface, and since 2026-09-22 a thin name for it.
|
|
9
6
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* - Both printed a stats line, so the consumer passed `stats={false}` too.
|
|
17
|
-
* - Both called `useBucketLibrary`, so one bucket was listed twice into two
|
|
18
|
-
* object lists that could disagree.
|
|
19
|
-
* - Every shared seam had to be handed to both by the consumer, which is the
|
|
20
|
-
* divergence-defect family the pages' own comments document at length.
|
|
7
|
+
* IT USED TO BE THE MERGE ITSELF: it held a BROWSE · FILES switch and mounted one of two pages,
|
|
8
|
+
* each of which listed the bucket, drew its own header and printed its own count. The user's read
|
|
9
|
+
* of that (2026-09-22) ended it — *"they both just display files … 4 views, not 2 modes each with
|
|
10
|
+
* 2 views"* — so the surface is ONE page now with four views (columns · rows · grid · list), one
|
|
11
|
+
* listing, one header, one count line and one filter bar, and this component only carries the
|
|
12
|
+
* view state for a consumer that wants to own it.
|
|
21
13
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* one body — every symptom above falls out of that rather than being patched.
|
|
14
|
+
* `MediaLibraryBrowse` and `MediaLibraryLibrary` remain exported: the first IS the surface, the
|
|
15
|
+
* second is the standalone wall a site embeds without a tree (kol-website's asset page).
|
|
25
16
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* free; against a live bucket it is a 30s-cached GET. Hoisting the hook and the
|
|
30
|
-
* header into a true shared parent is the deeper fix and it is a rewrite of both
|
|
31
|
-
* page bodies — worth doing, not worth blocking the surface on.
|
|
32
|
-
*
|
|
33
|
-
* `prefix` stays OWNED BY THE CONSUMER (it already was), so the folder you are
|
|
34
|
-
* in survives the switch even though the page instance does not.
|
|
35
|
-
*
|
|
36
|
-
* ADDITIVE. `variant="browse"` and `variant="library"` are untouched, so
|
|
37
|
-
* kol-r2b2 and kol-client-olina keep rendering exactly what they render today.
|
|
17
|
+
* @param {'columns'|'rows'|'grid'|'list'} view controlled view; omit and the page reads its own setting
|
|
18
|
+
* @param {Function} onViewChange (view) => void
|
|
19
|
+
* @param {'columns'|'rows'|'grid'|'list'} defaultView first view when uncontrolled and nothing is stored
|
|
38
20
|
*/
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
defaultView = 'browse',
|
|
49
|
-
headerActions,
|
|
50
|
-
className = '',
|
|
51
|
-
...pageProps
|
|
52
|
-
}) {
|
|
53
|
-
const [ownView, setOwnView] = useState(defaultView)
|
|
54
|
-
const view = viewProp ?? ownView
|
|
55
|
-
const setView = (v) => { setOwnView(v); onViewChange?.(v) }
|
|
56
|
-
|
|
57
|
-
/* The switch rides `headerActions` rather than being a fourth thing in the
|
|
58
|
-
* header's own markup: the header already has a slot for consumer chrome, and
|
|
59
|
-
* putting the view control there keeps it beside the bucket dropdown where
|
|
60
|
-
* every reference product puts it. The consumer's own actions follow it.
|
|
61
|
-
*
|
|
62
|
-
* HIDDEN BELOW `md`. At 390 the header carries a wordmark, a bucket dropdown
|
|
63
|
-
* and up to four icons; adding a two-segment strip pushed the strip off the
|
|
64
|
-
* right edge and truncated the wordmark to three glyphs. The pages already
|
|
65
|
-
* take the mobile tab pill (`tabs` / `activeTab` / `onTabChange`), which is
|
|
66
|
-
* the same control for the same question — so the phone keeps the pill and
|
|
67
|
-
* the desktop keeps the strip, rather than both competing for one row.
|
|
68
|
-
*
|
|
69
|
-
* BARE TEXT, NOT A `SegmentedToggle`. This surface already has a switch
|
|
70
|
-
* idiom and uses it twice — ROW·COLUMN on the crumb line and SELECT·FLAT on
|
|
71
|
-
* the filter bar are both `kol-helper-14`, `oq-96` active over `oq-48` at
|
|
72
|
-
* rest, letterspacing 1, no frame. A boxed toggle put a bordered chip next to
|
|
73
|
-
* an unbordered dropdown and two unbordered switches, which read as a style
|
|
74
|
-
* break because it was one. Same control, third instance, same treatment.
|
|
75
|
-
*
|
|
76
|
-
* AND IT SITS LAST, RIGHT OF A DIVIDER. The crumb row directly beneath this
|
|
77
|
-
* header reads `[list][columns] │ ROW COLUMN` — icons, divider, text switch.
|
|
78
|
-
* Placed before the icons the header mirrored the row under it, which is the
|
|
79
|
-
* same inconsistency in a different direction. Icons left, divider, text
|
|
80
|
-
* right; two rows, one arrangement. It rides `headerTrailing` rather than
|
|
81
|
-
* `headerActions` because the gear is rendered by the header itself and the
|
|
82
|
-
* switch has to clear it. */
|
|
83
|
-
/* THE GAPS ARE THE CRUMB ROW'S, MEASURED: `gap-6` (24px) around the divider,
|
|
84
|
-
* `gap-4` (16px) between the two labels. Built flat at gap-4 throughout, the
|
|
85
|
-
* divider sat 8px too tight against the icons and the row below it did not
|
|
86
|
-
* line up with the row above. Two nested containers, same two numbers. */
|
|
87
|
-
/* `ml-4` IS NOT DECORATION. The divider needs 24px on BOTH sides to match the
|
|
88
|
-
* crumb row, where its own `gap-6` container supplies both. Here the LEFT gap
|
|
89
|
-
* comes from the header's `gap-2` between this group and the gear — 8px — so
|
|
90
|
-
* the divider sat tight against the icons and open against the text. 8 + 16
|
|
91
|
-
* puts it back on 24. */
|
|
92
|
-
const trailing = (
|
|
93
|
-
<span className="max-md:hidden flex items-center gap-6 ml-4">
|
|
94
|
-
<Divider variant="vertical" />
|
|
95
|
-
<span className="flex items-center gap-4">
|
|
96
|
-
{VIEWS.map((opt) => (
|
|
97
|
-
<span key={opt.value} role="button" onClick={() => setView(opt.value)}
|
|
98
|
-
aria-pressed={view === opt.value}
|
|
99
|
-
className={`kol-helper-14 cursor-pointer select-none ${view === opt.value ? 'text-oq-96' : 'text-oq-48 hover:text-oq-64'}`}
|
|
100
|
-
style={{ letterSpacing: 1 }}>
|
|
101
|
-
{opt.label}
|
|
102
|
-
</span>
|
|
103
|
-
))}
|
|
104
|
-
</span>
|
|
105
|
-
</span>
|
|
21
|
+
export default function MediaLibraryExplorer({ view, onViewChange, defaultView, ...pageProps }) {
|
|
22
|
+
const [ownView, setOwnView] = useState(view ?? defaultView)
|
|
23
|
+
const current = view ?? ownView
|
|
24
|
+
return (
|
|
25
|
+
<MediaLibraryBrowse
|
|
26
|
+
{...pageProps}
|
|
27
|
+
view={current}
|
|
28
|
+
onViewChange={(v) => { setOwnView(v); onViewChange?.(v) }}
|
|
29
|
+
/>
|
|
106
30
|
)
|
|
107
|
-
|
|
108
|
-
const shared = { ...pageProps, headerActions, headerTrailing: trailing, className }
|
|
109
|
-
|
|
110
|
-
/* `header` and `stats` are NOT forwarded and NOT accepted. One surface prints
|
|
111
|
-
* one header and one count; a consumer suppressing either is the workaround
|
|
112
|
-
* this component exists to delete. */
|
|
113
|
-
return view === 'files'
|
|
114
|
-
? <MediaLibraryLibrary {...shared} />
|
|
115
|
-
: <MediaLibraryBrowse {...shared} />
|
|
116
31
|
}
|