@kolkrabbi/kol-styleguide 0.14.1 → 0.16.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 +9 -9
- package/src/A4Pages.jsx +38 -14
- package/src/AssetTable.jsx +20 -9
- package/src/DocumentIndex.jsx +10 -13
- package/src/DocumentLibrary.jsx +113 -0
- package/src/index.js +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kolkrabbi/kol-styleguide",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Brand guide components and the brand tool",
|
|
6
6
|
"license": "MIT",
|
|
@@ -12,20 +12,20 @@
|
|
|
12
12
|
"./src/*": "./src/*"
|
|
13
13
|
},
|
|
14
14
|
"peerDependencies": {
|
|
15
|
-
"@kolkrabbi/kol-component": ">=0.
|
|
16
|
-
"@kolkrabbi/kol-framework": ">=0.
|
|
15
|
+
"@kolkrabbi/kol-component": ">=0.315.0",
|
|
16
|
+
"@kolkrabbi/kol-framework": ">=0.64.0",
|
|
17
17
|
"@kolkrabbi/kol-icons": ">=0.18.0",
|
|
18
18
|
"@kolkrabbi/kol-print": ">=0.1.0",
|
|
19
|
-
"@kolkrabbi/kol-theme": ">=0.
|
|
19
|
+
"@kolkrabbi/kol-theme": ">=0.198.0",
|
|
20
20
|
"react": "^18.3.0 || ^19.0.0",
|
|
21
21
|
"react-dom": "^18.3.0 || ^19.0.0"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@kolkrabbi/kol-component": "^0.
|
|
25
|
-
"@kolkrabbi/kol-framework": "^0.
|
|
26
|
-
"@kolkrabbi/kol-
|
|
27
|
-
"@kolkrabbi/kol-
|
|
28
|
-
"@kolkrabbi/kol-
|
|
24
|
+
"@kolkrabbi/kol-component": "^0.315.0",
|
|
25
|
+
"@kolkrabbi/kol-framework": "^0.64.0",
|
|
26
|
+
"@kolkrabbi/kol-icons": "^0.52.0",
|
|
27
|
+
"@kolkrabbi/kol-theme": "^0.198.0",
|
|
28
|
+
"@kolkrabbi/kol-print": "^0.1.1"
|
|
29
29
|
},
|
|
30
30
|
"files": [
|
|
31
31
|
"src",
|
package/src/A4Pages.jsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useRef, useState, useLayoutEffect } from 'react'
|
|
2
|
+
import { QuickLookFrame } from '@kolkrabbi/kol-component'
|
|
2
3
|
|
|
3
4
|
/* A4 portrait @96dpi, with print-style page margins. */
|
|
4
5
|
const A4_W = 794
|
|
@@ -22,7 +23,11 @@ const CONTENT_H = A4_H - MARGIN * 2 - PRINT_SAFETY
|
|
|
22
23
|
*
|
|
23
24
|
* Re-measured on resize and as images (heroes) finish loading.
|
|
24
25
|
*/
|
|
25
|
-
|
|
26
|
+
/* `paged` (LayoutsAppPages, 2026-10-29 — user: *"one in view at a time, then next … we are not reinventing anything, just LOOK
|
|
27
|
+
* AROUND"*): one sheet in view, centred, paged with QuickLookFrame's `nav` (‹ › and `n / N`, as MediaLibrary and
|
|
28
|
+
* DocumentIndex page a PDF). Print still prints every sheet. */
|
|
29
|
+
export default function A4Pages({ children, label, paged = false }) {
|
|
30
|
+
const [at, setAt] = useState(0)
|
|
26
31
|
const measureRef = useRef(null)
|
|
27
32
|
// breaks[k]..breaks[k+1] is page k's vertical slice of the content.
|
|
28
33
|
const [breaks, setBreaks] = useState([0, CONTENT_H])
|
|
@@ -74,6 +79,37 @@ export default function A4Pages({ children, label }) {
|
|
|
74
79
|
}, [])
|
|
75
80
|
|
|
76
81
|
const pageCount = Math.max(1, breaks.length - 1)
|
|
82
|
+
const page = Math.min(at, pageCount - 1)
|
|
83
|
+
|
|
84
|
+
const sheets = Array.from({ length: pageCount }, (_, k) => {
|
|
85
|
+
const from = breaks[k] ?? 0
|
|
86
|
+
const to = breaks[k + 1] ?? from + CONTENT_H
|
|
87
|
+
return (
|
|
88
|
+
<section key={k} className={`kol-a4-sheet${paged && k !== page ? ' hidden print:block' : ''}`} aria-label={`${label} — page ${k + 1} of ${pageCount}`}>
|
|
89
|
+
<div className="kol-a4-clip" style={{ height: to - from }}>
|
|
90
|
+
{/* Negative margin (not transform) shifts the slice — Chrome's
|
|
91
|
+
print engine drops images inside transformed containers. */}
|
|
92
|
+
<div style={{ marginTop: -from }}>{children}</div>
|
|
93
|
+
</div>
|
|
94
|
+
</section>
|
|
95
|
+
)
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
if (paged) {
|
|
99
|
+
return (
|
|
100
|
+
<>
|
|
101
|
+
<div ref={measureRef} className="kol-a4-measure" aria-hidden="true">{children}</div>
|
|
102
|
+
<div className="flex justify-center print:block">
|
|
103
|
+
<QuickLookFrame
|
|
104
|
+
title={label}
|
|
105
|
+
nav={{ index: page, total: pageCount, onPrev: () => setAt((i) => (i - 1 + pageCount) % pageCount), onNext: () => setAt((i) => (i + 1) % pageCount) }}
|
|
106
|
+
>
|
|
107
|
+
<div className="flex justify-center p-6 print:p-0">{sheets}</div>
|
|
108
|
+
</QuickLookFrame>
|
|
109
|
+
</div>
|
|
110
|
+
</>
|
|
111
|
+
)
|
|
112
|
+
}
|
|
77
113
|
|
|
78
114
|
return (
|
|
79
115
|
<>
|
|
@@ -82,19 +118,7 @@ export default function A4Pages({ children, label }) {
|
|
|
82
118
|
{children}
|
|
83
119
|
</div>
|
|
84
120
|
|
|
85
|
-
{
|
|
86
|
-
const from = breaks[k] ?? 0
|
|
87
|
-
const to = breaks[k + 1] ?? from + CONTENT_H
|
|
88
|
-
return (
|
|
89
|
-
<section key={k} className="kol-a4-sheet" aria-label={`${label} — page ${k + 1} of ${pageCount}`}>
|
|
90
|
-
<div className="kol-a4-clip" style={{ height: to - from }}>
|
|
91
|
-
{/* Negative margin (not transform) shifts the slice — Chrome's
|
|
92
|
-
print engine drops images inside transformed containers. */}
|
|
93
|
-
<div style={{ marginTop: -from }}>{children}</div>
|
|
94
|
-
</div>
|
|
95
|
-
</section>
|
|
96
|
-
)
|
|
97
|
-
})}
|
|
121
|
+
{sheets}
|
|
98
122
|
</>
|
|
99
123
|
)
|
|
100
124
|
}
|
package/src/AssetTable.jsx
CHANGED
|
@@ -101,40 +101,49 @@ export default function AssetTable({
|
|
|
101
101
|
against the table's own ground — the consumer's behaviour, kept. */
|
|
102
102
|
className: (row) =>
|
|
103
103
|
`kol-table-cell-text${inkTokens && tokenFor(row.id) !== inkTokens.ink ? ' bg-fg-04' : ''}`,
|
|
104
|
-
style: { minWidth:
|
|
104
|
+
style: { minWidth: 112 },
|
|
105
105
|
render: (row) => <PreviewCell row={row} token={tokenFor(row.id)} onZoom={onPreviewZoom} />,
|
|
106
106
|
},
|
|
107
107
|
{
|
|
108
108
|
accessor: 'name',
|
|
109
109
|
header: 'Name',
|
|
110
|
-
|
|
110
|
+
/* a name wraps at its words (`lockup / hori / wide`); a path never does */
|
|
111
|
+
className: 'kol-table-cell-text kol-table-cell-text--wrap',
|
|
112
|
+
style: { minWidth: 80 },
|
|
111
113
|
},
|
|
112
114
|
hasPath && {
|
|
113
115
|
accessor: 'path',
|
|
114
116
|
header: 'Path',
|
|
115
|
-
|
|
117
|
+
/* a path never wraps at its slash (LayoutsAppPages, 2026-10-29: `marks/` ⏎ `logomark-01.svg`) — it takes the width it
|
|
118
|
+
needs, from Preview, which has more than it uses */
|
|
119
|
+
className: 'kol-table-cell-meta whitespace-nowrap',
|
|
116
120
|
render: (row) => (row.path ? <code>{row.path}</code> : null),
|
|
117
121
|
},
|
|
118
122
|
{
|
|
119
123
|
accessor: 'format',
|
|
120
124
|
header: 'Format',
|
|
121
|
-
className: 'kol-table-cell-meta',
|
|
125
|
+
className: 'kol-table-cell-meta whitespace-nowrap',
|
|
126
|
+
/* the meta cell's 160px floor is for prose; `SVG` needs a word's width — the room goes to Path (LayoutsAppPages) */
|
|
127
|
+
style: { minWidth: 0 },
|
|
122
128
|
},
|
|
123
129
|
{
|
|
124
130
|
accessor: 'dimensions',
|
|
125
131
|
header: 'Dimensions',
|
|
126
|
-
className: 'kol-table-cell-meta',
|
|
132
|
+
className: 'kol-table-cell-meta whitespace-nowrap',
|
|
133
|
+
style: { minWidth: 0 },
|
|
127
134
|
},
|
|
128
135
|
inkTokens && {
|
|
129
136
|
accessor: 'color',
|
|
130
137
|
header: 'Color',
|
|
131
|
-
className: 'kol-table-cell-meta',
|
|
138
|
+
className: 'kol-table-cell-meta whitespace-nowrap',
|
|
139
|
+
style: { minWidth: 0 },
|
|
132
140
|
render: (row) => <code>{tokenFor(row.id)}</code>,
|
|
133
141
|
},
|
|
134
142
|
hasDownload && {
|
|
135
143
|
accessor: 'download',
|
|
136
144
|
header: 'Download',
|
|
137
|
-
|
|
145
|
+
/* no fixed 96px: the chips are wider than that, and the column was clipped ("Co…") */
|
|
146
|
+
className: 'whitespace-nowrap',
|
|
138
147
|
render: (row) => (
|
|
139
148
|
<DownloadControl
|
|
140
149
|
row={row}
|
|
@@ -145,7 +154,8 @@ export default function AssetTable({
|
|
|
145
154
|
},
|
|
146
155
|
].filter(Boolean)
|
|
147
156
|
|
|
148
|
-
|
|
157
|
+
/* a DATA table: it runs the content column (Table `width="column"`), not the prose panel cap it stopped at */
|
|
158
|
+
return <Table caption={caption} columns={columns} rows={withId} variant={variant} className={className} width="column" />
|
|
149
159
|
}
|
|
150
160
|
|
|
151
161
|
/* Preview cell. With `onZoom` it is a zoom button; without, the bare node —
|
|
@@ -156,7 +166,8 @@ function PreviewCell({ row, token, onZoom }) {
|
|
|
156
166
|
|
|
157
167
|
const style = {
|
|
158
168
|
...(token ? { color: `var(${token})` } : {}),
|
|
159
|
-
|
|
169
|
+
/* up to its width, down to the column's — the preview scales before the table runs out of its column */
|
|
170
|
+
...(row.previewWidth ? { width: '100%', maxWidth: row.previewWidth } : {}),
|
|
160
171
|
}
|
|
161
172
|
|
|
162
173
|
if (!onZoom) {
|
package/src/DocumentIndex.jsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useState } from 'react'
|
|
2
|
-
import {
|
|
2
|
+
import { FileQuickLook, PageHeader, KIND_LABEL } from '@kolkrabbi/kol-component'
|
|
3
3
|
import { Contents } from './BrandGuide.jsx'
|
|
4
4
|
|
|
5
5
|
/* DOCUMENT INDEX — a folder's pages as the brand book's contents cards (BrandGuide's `Contents`, routed), grouped by
|
|
@@ -24,22 +24,19 @@ export default function DocumentIndex({ rows, title, lede, onNavigate }) {
|
|
|
24
24
|
const index = rows.map((r) => (r.file
|
|
25
25
|
? { ...r, href: r.file, meta: r.meta ?? fileLabel(r), onClick: (e) => { if (e.metaKey || e.ctrlKey || e.shiftKey || e.button !== 0) return; e.preventDefault(); setOpen(files.indexOf(r)) } }
|
|
26
26
|
: r))
|
|
27
|
-
const cur = open === null ? null : files[open]
|
|
28
|
-
const step = (d) => setOpen((i) => (i + d + files.length) % files.length)
|
|
29
27
|
return (
|
|
30
28
|
<div className="kol-page flex flex-col gap-6">
|
|
31
29
|
{title && <PageHeader title={title} subtitle={lede} size="sm" voice="mono" />}
|
|
32
30
|
<Contents index={index} onNavigate={onNavigate} />
|
|
33
|
-
{
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
)}
|
|
31
|
+
{/* the DS Quick Look over the folder's files (kol-component FileQuickLook, 2026-10-29 — the composition this file drew
|
|
32
|
+
* by hand: dims, pages ‹ ›, a download) */}
|
|
33
|
+
<FileQuickLook
|
|
34
|
+
files={files.map((f) => ({ key: f.file.split('?')[0], name: f.title, url: f.file, type: f.kind === 'image' ? 'image/' : undefined }))}
|
|
35
|
+
index={open}
|
|
36
|
+
onIndex={setOpen}
|
|
37
|
+
onClose={() => setOpen(null)}
|
|
38
|
+
meta={(x) => fileLabel(files.find((f) => f.file === x.url))}
|
|
39
|
+
/>
|
|
43
40
|
</div>
|
|
44
41
|
)
|
|
45
42
|
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { useState } from 'react'
|
|
2
|
+
import { Button, FileQuickLook, Table } from '@kolkrabbi/kol-component'
|
|
3
|
+
import { MarkdownPage, PageSection, libraryLinks } from '@kolkrabbi/kol-framework'
|
|
4
|
+
import DocumentIndex from './DocumentIndex.jsx'
|
|
5
|
+
|
|
6
|
+
/* DOCUMENT LIBRARY — a `documentLibrary` (kol-framework) drawn: a sortable table per folder, the title opening the text,
|
|
7
|
+
* the originals opening in the DS Quick Look, the markdown downloading (DocumentLibraryAndBoardParts, kol-website
|
|
8
|
+
* 2026-10-29 — record's DocumentsIndex · FolderTable · Files · MdDownload, made the DS's so brand and record draw their
|
|
9
|
+
* documents the same way: *"I already asked for tables, and download and file preview"*).
|
|
10
|
+
*
|
|
11
|
+
* <DocumentLibrary library={lib} onNavigate={navigate} urlOf={(f) => f.url} /> every folder, a section each
|
|
12
|
+
* <DocumentLibrary library={lib} folder="press" … /> one folder
|
|
13
|
+
* <DocumentView library={lib} row={row} urlOf={…} resolveLink={…} assetUrl={…} /> the open document
|
|
14
|
+
*
|
|
15
|
+
* DocumentLibrary
|
|
16
|
+
* library `{ rows, folders }` from documentLibrary
|
|
17
|
+
* folder one folder's id; omitted, every folder
|
|
18
|
+
* columns the table's columns — an array of keys (`title · kind · date · lang · assets · markdown`) and/or Table column
|
|
19
|
+
* objects, or `(defaults) => columns` to drop, reorder or add
|
|
20
|
+
* view `table` (default) · `cards` (DocumentIndex's contents cards, for anyone who still wants them)
|
|
21
|
+
* onNavigate (to) => void — a title's click; the link is a real `href` too
|
|
22
|
+
* urlOf (file) => string — an original's URL (default `file.url`; record serves the bucket in prod and a mirror in dev)
|
|
23
|
+
*
|
|
24
|
+
* DocumentFiles — the Assets cell on its own: a button per original, labelled by extension, two of one kind told apart by
|
|
25
|
+
* language (`PDF IS`, `PDF EN`); each opens Quick Look over the row's files. `DocumentMarkdown` — the source as `<stem>.md`. */
|
|
26
|
+
const LANGS = ['is', 'en', 'de']
|
|
27
|
+
const ext = (f) => (f.key ?? f.name ?? '').split('.').pop().toUpperCase()
|
|
28
|
+
export const fileLabel = (files, f) => (files.filter((x) => ext(x) === ext(f)).length > 1
|
|
29
|
+
? `${ext(f)} ${(f.key ?? f.name).split('/').pop().split(/[-.]/).filter((t) => LANGS.includes(t)).join(' ').toUpperCase()}`.trim()
|
|
30
|
+
: ext(f))
|
|
31
|
+
const plain = (e) => !(e.metaKey || e.ctrlKey || e.shiftKey || e.button !== 0)
|
|
32
|
+
|
|
33
|
+
/* the one Quick Look a page holds: `open(files, index)` and the overlay to render */
|
|
34
|
+
export function useFileQuickLook(urlOf) {
|
|
35
|
+
const [look, setLook] = useState(null)
|
|
36
|
+
const overlay = look && <FileQuickLook files={look.files} index={look.index} onIndex={(index) => setLook({ ...look, index })} onClose={() => setLook(null)} urlOf={urlOf} />
|
|
37
|
+
return [(files, index) => setLook({ files, index }), overlay]
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function DocumentFiles({ row, onOpen }) {
|
|
41
|
+
if (!row.files?.length) return null
|
|
42
|
+
return (
|
|
43
|
+
<div className="flex flex-wrap gap-1">
|
|
44
|
+
{row.files.map((f, i) => <Button key={f.key} variant="nav" size="sm" onClick={() => onOpen(row.files, i)} title={f.name ?? f.key.split('/').pop()}>{fileLabel(row.files, f)}</Button>)}
|
|
45
|
+
</div>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const DocumentMarkdown = ({ row }) => (
|
|
50
|
+
<Button variant="nav" size="sm" iconOnly="download" href={`data:text/markdown;charset=utf-8,${encodeURIComponent(row.source ?? '')}`} download={`${row.id.split('/').pop()}.md`} aria-label="Download markdown" />
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
const DEFAULT_KEYS = ['title', 'kind', 'date', 'lang', 'assets', 'markdown']
|
|
54
|
+
|
|
55
|
+
function columnsFor({ onNavigate, onOpen }) {
|
|
56
|
+
return {
|
|
57
|
+
title: { header: 'Title', accessor: 'title', wrap: true, sortable: true, render: (r) => (
|
|
58
|
+
<a href={r.to} className="underline-offset-2 hover:underline" onClick={onNavigate ? (e) => { if (!plain(e)) return; e.preventDefault(); onNavigate(r.to) } : undefined}>{r.title}</a>
|
|
59
|
+
) },
|
|
60
|
+
kind: { header: 'Kind', accessor: 'kind', sortable: true },
|
|
61
|
+
date: { header: 'Date', accessor: 'date', sortable: true },
|
|
62
|
+
lang: { header: 'Language', accessor: 'lang' },
|
|
63
|
+
assets: { header: 'Assets', accessor: 'files', render: (r) => <DocumentFiles row={r} onOpen={onOpen} /> },
|
|
64
|
+
markdown: { header: 'Markdown', accessor: 'source', render: (r) => <DocumentMarkdown row={r} /> },
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export default function DocumentLibrary({ library, folder, columns, view = 'table', onNavigate, urlOf = (f) => f.url }) {
|
|
69
|
+
const [open, overlay] = useFileQuickLook(urlOf)
|
|
70
|
+
const named = columnsFor({ onNavigate, onOpen: open })
|
|
71
|
+
const defaults = DEFAULT_KEYS.map((k) => named[k])
|
|
72
|
+
const resolve = (c) => (typeof c === 'string' ? named[c] : c)
|
|
73
|
+
const cols = (typeof columns === 'function' ? columns(defaults) : columns ?? DEFAULT_KEYS).map(resolve).filter(Boolean)
|
|
74
|
+
const folders = folder != null ? library.folders.filter((f) => f.id === folder) : library.folders
|
|
75
|
+
|
|
76
|
+
if (view === 'cards') {
|
|
77
|
+
/* the contents cards: pages as cards in their folder's part, the originals as file cards (DocumentIndex opens them) */
|
|
78
|
+
const rows = folders.flatMap((f) => library.rows.filter((r) => r.folder === f.id).flatMap((r) => [
|
|
79
|
+
{ id: r.id, to: r.to, title: r.title, label: r.kind || undefined, part: f.label },
|
|
80
|
+
...(r.files ?? []).map((x) => ({ id: `${r.id}:${x.key}`, file: urlOf(x), title: x.name ?? x.key.split('/').pop(), part: f.label })),
|
|
81
|
+
]))
|
|
82
|
+
return <DocumentIndex rows={rows} onNavigate={onNavigate} />
|
|
83
|
+
}
|
|
84
|
+
return (
|
|
85
|
+
<div>
|
|
86
|
+
{folders.map((f) => (
|
|
87
|
+
<PageSection key={f.id || 'root'} id={f.id || 'documents'} label={f.label}>
|
|
88
|
+
<Table columns={cols} rows={library.rows.filter((r) => r.folder === f.id)} width="column" variant="simple" />
|
|
89
|
+
</PageSection>
|
|
90
|
+
))}
|
|
91
|
+
{overlay}
|
|
92
|
+
</div>
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/* THE OPEN DOCUMENT: the same Assets and Markdown buttons above `MarkdownPage`, then `actions` — record's DocumentsPage.
|
|
97
|
+
* Every other prop goes to MarkdownPage (`resolveLink`, `assetUrl`, `toc`, `numbered`, …); `resolveLink` defaults to the
|
|
98
|
+
* library's own (`libraryLinks`, kol-framework) when the caller passes `library` and no resolver. */
|
|
99
|
+
export function DocumentView({ row, library, urlOf = (f) => f.url, actions, markdown = true, ...page }) {
|
|
100
|
+
const [open, overlay] = useFileQuickLook(urlOf)
|
|
101
|
+
if (library && !page.resolveLink) page.resolveLink = libraryLinks(library)
|
|
102
|
+
return (
|
|
103
|
+
<>
|
|
104
|
+
<div className="kol-page flex items-center justify-end gap-1 pb-0">
|
|
105
|
+
<DocumentFiles row={row} onOpen={open} />
|
|
106
|
+
{markdown && <DocumentMarkdown row={row} />}
|
|
107
|
+
{actions}
|
|
108
|
+
</div>
|
|
109
|
+
<MarkdownPage key={row.id} source={row.source} {...page} />
|
|
110
|
+
{overlay}
|
|
111
|
+
</>
|
|
112
|
+
)
|
|
113
|
+
}
|
package/src/index.js
CHANGED
|
@@ -27,6 +27,7 @@ export { generatePalette, fgOn, hexToHsl, hslToHex, GENERATION_MODES } from './c
|
|
|
27
27
|
export { default as AssetCard } from './AssetCard.jsx'
|
|
28
28
|
/* a folder's pages as the brand book's contents cards (plan-2026-10-28-document W5.2) */
|
|
29
29
|
export { default as DocumentIndex } from './DocumentIndex.jsx'
|
|
30
|
+
export { default as DocumentLibrary, DocumentView, DocumentFiles, DocumentMarkdown, useFileQuickLook } from './DocumentLibrary.jsx'
|
|
30
31
|
/* print (PdfToolsFromStudio, 2026-10-28): A4 sheets for any content, and markdown to PDF · DOCX · MD on @kolkrabbi/kol-print */
|
|
31
32
|
export { default as A4Pages } from './A4Pages.jsx'
|
|
32
33
|
export { default as PrintStudio } from './PrintStudio.jsx'
|