@flamingo-stack/openframe-frontend-core 0.0.848 → 0.0.849
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/dist/build/export-map.json +1 -1
- package/dist/{chunk-Y4BG7SPX.cjs → chunk-36XWCVSM.cjs} +63 -63
- package/dist/{chunk-YXKAHQYS.cjs → chunk-533QK4R6.cjs} +2 -1
- package/dist/{chunk-5HOWR4TG.cjs → chunk-5CBI2ZYV.cjs} +5 -5
- package/dist/{chunk-NYT6IBIX.cjs → chunk-5PIR77V5.cjs} +4 -4
- package/dist/{chunk-IIUZE73M.cjs → chunk-6AJYGXXS.cjs} +14 -14
- package/dist/{chunk-U7UBYJEZ.cjs → chunk-BU2PSRAS.cjs} +5 -5
- package/dist/{chunk-I3YRYS23.cjs → chunk-C3P7IUTU.cjs} +37 -12
- package/dist/{chunk-O4BXHCMK.cjs → chunk-FRG724DU.cjs} +2 -2
- package/dist/{chunk-YAW7CHLV.cjs → chunk-FXLROQUT.cjs} +41 -38
- package/dist/{chunk-7YJQTQPV.cjs → chunk-IG6ROHPS.cjs} +46 -46
- package/dist/{chunk-INA2FX2N.cjs → chunk-IHY7E4EX.cjs} +2 -2
- package/dist/{chunk-Y2ZWWIUA.cjs → chunk-IN3LA2FU.cjs} +2 -2
- package/dist/{chunk-7LE4HWHA.cjs → chunk-KXBZCUDW.cjs} +11 -11
- package/dist/{chunk-C3WZXOZJ.cjs → chunk-MC3L525K.cjs} +3 -3
- package/dist/{chunk-7DW3LZ52.cjs → chunk-PV2XQJ2R.cjs} +92 -171
- package/dist/{chunk-GASFYPGH.cjs → chunk-R5JPZ6TY.cjs} +14 -14
- package/dist/{chunk-MWYEROAP.cjs → chunk-SHQY4GOE.cjs} +55 -55
- package/dist/{chunk-VW4446JR.cjs → chunk-TEKN6TJ5.cjs} +14 -14
- package/dist/{chunk-QUSCSYHJ.cjs → chunk-TX4NTH22.cjs} +45 -26
- package/dist/{chunk-2V6FCVUL.cjs → chunk-YLETC7LP.cjs} +187 -169
- package/dist/{chunk-OCJXOSIH.cjs → chunk-YYHQY3K6.cjs} +30 -30
- package/dist/{chunk-74Z34I2C.cjs → chunk-Z5UCDEKZ.cjs} +4 -4
- package/dist/{chunk-IUZVOQXP.cjs → chunk-ZY34R37A.cjs} +45 -45
- package/dist/{cloud-tenants-YAZHLPOQ.cjs → cloud-tenants-HKUUEUAY.cjs} +7 -7
- package/dist/components/case-studies/index.cjs +21 -21
- package/dist/components/chat/entity-cards/dispatch.d.ts.map +1 -1
- package/dist/components/chat/entity-cards/dispatch.js +1 -0
- package/dist/components/chat/index.cjs +5 -5
- package/dist/components/contact/index.cjs +8 -8
- package/dist/components/docs/doc-viewer.d.ts +7 -7
- package/dist/components/docs/doc-viewer.d.ts.map +1 -1
- package/dist/components/docs/doc-viewer.js +29 -16
- package/dist/components/docs/docs-hub-page.d.ts +1 -1
- package/dist/components/docs/docs-hub-page.d.ts.map +1 -1
- package/dist/components/docs/docs-hub-page.js +4 -11
- package/dist/components/docs/index.cjs +11 -11
- package/dist/components/docs/use-document-tree.d.ts.map +1 -1
- package/dist/components/docs/use-document-tree.js +24 -24
- package/dist/components/embeds/claude-embed.d.ts +2 -2
- package/dist/components/embeds/claude-embed.d.ts.map +1 -1
- package/dist/components/embeds/claude-embed.js +3 -3
- package/dist/components/embeds/embed-iframe.d.ts +5 -3
- package/dist/components/embeds/embed-iframe.d.ts.map +1 -1
- package/dist/components/embeds/embed-iframe.js +4 -3
- package/dist/components/embeds/embed-viewer-frame.d.ts +12 -9
- package/dist/components/embeds/embed-viewer-frame.d.ts.map +1 -1
- package/dist/components/embeds/embed-viewer-frame.js +21 -7
- package/dist/components/embeds/figma-embed.d.ts +4 -2
- package/dist/components/embeds/figma-embed.d.ts.map +1 -1
- package/dist/components/embeds/figma-embed.js +4 -3
- package/dist/components/embeds/file-download-card.d.ts +3 -1
- package/dist/components/embeds/file-download-card.d.ts.map +1 -1
- package/dist/components/embeds/file-download-card.js +18 -3
- package/dist/components/embeds/google-sheets-viewer.d.ts +3 -1
- package/dist/components/embeds/google-sheets-viewer.d.ts.map +1 -1
- package/dist/components/embeds/google-sheets-viewer.js +7 -4
- package/dist/components/embeds/index.cjs +8 -8
- package/dist/components/embeds/pdf-viewer.d.ts +3 -1
- package/dist/components/embeds/pdf-viewer.d.ts.map +1 -1
- package/dist/components/embeds/pdf-viewer.js +6 -2
- package/dist/components/faq/index.cjs +9 -9
- package/dist/components/features/index.cjs +7 -7
- package/dist/components/help-center-pages/index.cjs +81 -81
- package/dist/components/index.cjs +49 -49
- package/dist/components/meeting-scheduler/index.cjs +32 -32
- package/dist/components/navigation/index.cjs +10 -10
- package/dist/components/onboarding-guides/index.cjs +10 -10
- package/dist/components/product-demo/index.cjs +16 -16
- package/dist/components/related-content/index.cjs +4 -4
- package/dist/components/tickets/index.cjs +12 -12
- package/dist/components/ui/index.cjs +7 -7
- package/dist/components/ui/markdown/rich/rich-markdown-renderer.d.ts.map +1 -1
- package/dist/components/ui/markdown/rich/rich-markdown-renderer.js +7 -3
- package/dist/{devices-IZROCLFK.cjs → devices-P7M4Z7VP.cjs} +8 -8
- package/dist/{embeddable-chat-ETW6S22E.cjs → embeddable-chat-322NDFP5.cjs} +74 -74
- package/dist/index.cjs +15 -11
- package/dist/{knowledge-4IRWLTNW.cjs → knowledge-TC7JLOWI.cjs} +8 -8
- package/dist/{logs-EFDGY5IO.cjs → logs-GPOYCP4B.cjs} +14 -14
- package/dist/{policies-3KEXZ5BP.cjs → policies-ZUHOUMDD.cjs} +11 -11
- package/dist/{scripts-PCGTZLZL.cjs → scripts-FOEVDGTH.cjs} +12 -12
- package/dist/{software-update-YCDNVFJE.cjs → software-update-XGTMNFST.cjs} +10 -10
- package/dist/types/doc-source.d.ts +2 -2
- package/dist/types/doc-source.d.ts.map +1 -1
- package/dist/utils/doc-tree-nav.d.ts +7 -0
- package/dist/utils/doc-tree-nav.d.ts.map +1 -1
- package/dist/utils/doc-tree-nav.js +19 -0
- package/dist/utils/index.cjs +25 -2
- package/dist/utils/list-url.d.ts.map +1 -1
- package/dist/utils/list-url.js +2 -1
- package/dist/utils/source-grouping.d.ts +2 -2
- package/dist/utils/source-grouping.d.ts.map +1 -1
- package/dist/utils/source-grouping.js +1 -1
- package/dist/utils/source-icons.d.ts.map +1 -1
- package/dist/utils/source-icons.js +3 -0
- package/package.json +1 -1
- package/src/components/chat/entity-cards/dispatch.tsx +3 -0
- package/src/components/docs/doc-viewer.tsx +56 -35
- package/src/components/docs/docs-hub-page.tsx +13 -37
- package/src/components/docs/use-document-tree.ts +33 -23
- package/src/components/embeds/claude-embed.tsx +4 -4
- package/src/components/embeds/embed-iframe.tsx +8 -5
- package/src/components/embeds/embed-viewer-frame.tsx +35 -15
- package/src/components/embeds/figma-embed.tsx +9 -4
- package/src/components/embeds/file-download-card.tsx +28 -4
- package/src/components/embeds/google-sheets-viewer.tsx +9 -3
- package/src/components/embeds/pdf-viewer.tsx +9 -2
- package/src/components/ui/markdown/rich/rich-markdown-renderer.tsx +4 -0
- package/src/types/doc-source.ts +2 -2
- package/src/utils/doc-tree-nav.ts +27 -0
- package/src/utils/list-url.ts +2 -1
- package/src/utils/source-grouping.ts +2 -2
- package/src/utils/source-icons.ts +3 -0
- package/dist/components/docs/skeletons.d.ts +0 -25
- package/dist/components/docs/skeletons.d.ts.map +0 -1
- package/dist/components/docs/skeletons.js +0 -83
- package/src/components/docs/skeletons.tsx +0 -131
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
import { FileText, Download } from 'lucide-react';
|
|
2
2
|
import { formatFileSize } from '../../utils';
|
|
3
|
+
import { InteractiveSkeleton, TextLineSkeleton } from '../loading/unified-skeleton';
|
|
3
4
|
import { Button } from '../ui';
|
|
5
|
+
import { useLoadingScope } from '../ui/loading-scope';
|
|
4
6
|
|
|
5
7
|
export interface FileDownloadCardProps {
|
|
6
8
|
fileName?: string;
|
|
7
9
|
mimeType?: string;
|
|
8
10
|
fileSize?: number;
|
|
9
11
|
fileUrl?: string;
|
|
12
|
+
/** The file is being read: the card draws its loading form. A loading scope does the same. */
|
|
13
|
+
loading?: boolean;
|
|
10
14
|
}
|
|
11
15
|
|
|
16
|
+
/** The card's boxes, shared by the card and its loading form. */
|
|
17
|
+
const FILE_CARD_OUTER_CLASS = 'flex flex-col items-center justify-center py-16';
|
|
18
|
+
const FILE_CARD_CLASS = 'w-full max-w-md space-y-4 rounded-xl border border-ods-border bg-ods-card p-8 text-center';
|
|
19
|
+
const FILE_ICON_CLASS = 'mx-auto h-16 w-16 text-ods-text-secondary';
|
|
20
|
+
|
|
12
21
|
/**
|
|
13
22
|
* Generic downloadable-file card for the `file` document type. Used by
|
|
14
23
|
* `<DocsHubPage>`'s default `documentTypeRenderers.file`. Embedders can
|
|
@@ -18,11 +27,26 @@ export interface FileDownloadCardProps {
|
|
|
18
27
|
* renders the filename + type + size so the user knows what they were
|
|
19
28
|
* about to download).
|
|
20
29
|
*/
|
|
21
|
-
export function FileDownloadCard({ fileName, mimeType, fileSize, fileUrl }: FileDownloadCardProps) {
|
|
30
|
+
export function FileDownloadCard({ fileName, mimeType, fileSize, fileUrl, loading = false }: FileDownloadCardProps) {
|
|
31
|
+
// In a loading scope the file is being read: the card draws its own loading form, in its own boxes.
|
|
32
|
+
if (useLoadingScope() || loading) {
|
|
33
|
+
return (
|
|
34
|
+
<div className={FILE_CARD_OUTER_CLASS}>
|
|
35
|
+
<div className={FILE_CARD_CLASS}>
|
|
36
|
+
<FileText className={FILE_ICON_CLASS} />
|
|
37
|
+
<div>
|
|
38
|
+
<TextLineSkeleton type="h3" className="mx-auto w-2/3" />
|
|
39
|
+
<TextLineSkeleton type="h6" className="mx-auto mt-2 w-1/2" />
|
|
40
|
+
</div>
|
|
41
|
+
<InteractiveSkeleton.Button className="mx-auto" />
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
22
46
|
return (
|
|
23
|
-
<div className=
|
|
24
|
-
<div className=
|
|
25
|
-
<FileText className=
|
|
47
|
+
<div className={FILE_CARD_OUTER_CLASS}>
|
|
48
|
+
<div className={FILE_CARD_CLASS}>
|
|
49
|
+
<FileText className={FILE_ICON_CLASS} />
|
|
26
50
|
<div>
|
|
27
51
|
<h3 className="text-ods-text-primary text-h3">{fileName || 'File'}</h3>
|
|
28
52
|
<div className="mt-2 flex items-center justify-center gap-3 text-ods-text-secondary text-h6">
|
|
@@ -4,20 +4,25 @@ import { ExternalLink } from 'lucide-react';
|
|
|
4
4
|
import { toGoogleSheetsEmbedUrl, toGoogleSheetsOriginalUrl } from '../../utils/embed-url-converters';
|
|
5
5
|
import { GoogleSheetsIcon } from '../icons-v2-generated';
|
|
6
6
|
import { Button } from '../ui';
|
|
7
|
+
import { useLoadingScope } from '../ui/loading-scope';
|
|
7
8
|
import { EmbedViewerFrame } from './embed-viewer-frame';
|
|
8
9
|
|
|
9
10
|
export interface GoogleSheetsViewerProps {
|
|
10
11
|
externalUrl: string;
|
|
11
12
|
fileName?: string;
|
|
12
13
|
height?: string;
|
|
14
|
+
/** The document is being read: the viewer draws its loading form. A loading scope does the same. */
|
|
15
|
+
loading?: boolean;
|
|
13
16
|
}
|
|
14
17
|
|
|
15
|
-
export function GoogleSheetsViewer({ externalUrl, fileName, height }: GoogleSheetsViewerProps) {
|
|
18
|
+
export function GoogleSheetsViewer({ externalUrl, fileName, height, loading = false }: GoogleSheetsViewerProps) {
|
|
16
19
|
const displayName = fileName || 'Google Sheet';
|
|
20
|
+
// In a loading scope the document is being read: the frame draws its loading form, never "not configured".
|
|
21
|
+
const isLoading = useLoadingScope() || loading;
|
|
17
22
|
|
|
18
23
|
// Historical shape: no URL at all → standalone empty state with NO header
|
|
19
24
|
// (the frame's empty body keeps the header — that's the figma behavior).
|
|
20
|
-
if (!externalUrl) {
|
|
25
|
+
if (!externalUrl && !isLoading) {
|
|
21
26
|
return (
|
|
22
27
|
<div className="flex flex-col items-center justify-center py-16 text-center">
|
|
23
28
|
<GoogleSheetsIcon className="mb-4 h-16 w-16 text-ods-text-secondary" />
|
|
@@ -43,8 +48,9 @@ export function GoogleSheetsViewer({ externalUrl, fileName, height }: GoogleShee
|
|
|
43
48
|
Open in Google Sheets
|
|
44
49
|
</Button>
|
|
45
50
|
}
|
|
46
|
-
src={toGoogleSheetsEmbedUrl(externalUrl)}
|
|
51
|
+
src={externalUrl ? toGoogleSheetsEmbedUrl(externalUrl) : null}
|
|
47
52
|
height={height}
|
|
53
|
+
loading={loading}
|
|
48
54
|
/>
|
|
49
55
|
);
|
|
50
56
|
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { Download, Eye } from 'lucide-react';
|
|
4
4
|
import { AdobePdfIcon } from '../icons-v2-generated';
|
|
5
5
|
import { Button } from '../ui';
|
|
6
|
+
import { useLoadingScope } from '../ui/loading-scope';
|
|
6
7
|
import { EmbedViewerFrame } from './embed-viewer-frame';
|
|
7
8
|
|
|
8
9
|
export interface PdfViewerProps {
|
|
@@ -11,13 +12,17 @@ export interface PdfViewerProps {
|
|
|
11
12
|
onPreview?: () => void;
|
|
12
13
|
onDownload?: () => void;
|
|
13
14
|
height?: string;
|
|
15
|
+
/** The document is being read: the viewer draws its loading form. A loading scope does the same. */
|
|
16
|
+
loading?: boolean;
|
|
14
17
|
}
|
|
15
18
|
|
|
16
|
-
export function PdfViewer({ src, fileName, onPreview, onDownload, height }: PdfViewerProps) {
|
|
19
|
+
export function PdfViewer({ src, fileName, onPreview, onDownload, height, loading = false }: PdfViewerProps) {
|
|
17
20
|
const displayName = fileName || 'PDF Document';
|
|
21
|
+
// In a loading scope the document is being read: the frame draws its loading form, never "not available".
|
|
22
|
+
const isLoading = useLoadingScope() || loading;
|
|
18
23
|
|
|
19
24
|
// Historical shape: no src at all → standalone empty state with NO header.
|
|
20
|
-
if (!src) {
|
|
25
|
+
if (!src && !isLoading) {
|
|
21
26
|
return (
|
|
22
27
|
<div className="flex flex-col items-center justify-center py-16 text-center">
|
|
23
28
|
<AdobePdfIcon className="mb-4 h-16 w-16 text-ods-text-secondary" />
|
|
@@ -57,6 +62,8 @@ export function PdfViewer({ src, fileName, onPreview, onDownload, height }: PdfV
|
|
|
57
62
|
</div>
|
|
58
63
|
}
|
|
59
64
|
src={src}
|
|
65
|
+
loadingActionCount={2}
|
|
66
|
+
loading={loading}
|
|
60
67
|
height={height}
|
|
61
68
|
/>
|
|
62
69
|
);
|
|
@@ -101,6 +101,7 @@ const RichMarkdownInner: React.FC<InnerProps> = ({
|
|
|
101
101
|
demoteMarkdownH1ToH2,
|
|
102
102
|
skeletonSections,
|
|
103
103
|
skeletonLines,
|
|
104
|
+
skeletonTitle,
|
|
104
105
|
}) => {
|
|
105
106
|
const { ogScraperUrl } = useRichMarkdownRuntime();
|
|
106
107
|
|
|
@@ -158,6 +159,7 @@ const RichMarkdownInner: React.FC<InnerProps> = ({
|
|
|
158
159
|
allowRemoteMedia
|
|
159
160
|
skeletonSections={skeletonSections}
|
|
160
161
|
skeletonLines={skeletonLines}
|
|
162
|
+
skeletonTitle={skeletonTitle}
|
|
161
163
|
/>
|
|
162
164
|
);
|
|
163
165
|
};
|
|
@@ -174,6 +176,7 @@ const RichMarkdownRendererImpl: React.FC<RichMarkdownRendererProps> = ({
|
|
|
174
176
|
demoteMarkdownH1ToH2 = false,
|
|
175
177
|
skeletonSections,
|
|
176
178
|
skeletonLines,
|
|
179
|
+
skeletonTitle,
|
|
177
180
|
// Runtime overrides; provider fills the defaults
|
|
178
181
|
redditProxyUrl,
|
|
179
182
|
twitterProxyUrl,
|
|
@@ -199,6 +202,7 @@ const RichMarkdownRendererImpl: React.FC<RichMarkdownRendererProps> = ({
|
|
|
199
202
|
demoteMarkdownH1ToH2={demoteMarkdownH1ToH2}
|
|
200
203
|
skeletonSections={skeletonSections}
|
|
201
204
|
skeletonLines={skeletonLines}
|
|
205
|
+
skeletonTitle={skeletonTitle}
|
|
202
206
|
/>
|
|
203
207
|
</RichMarkdownRuntimeProvider>
|
|
204
208
|
);
|
package/src/types/doc-source.ts
CHANGED
|
@@ -75,12 +75,12 @@ export interface DocSourceDal<Client = unknown> {
|
|
|
75
75
|
* Doc-source registry id. The lib's `<DocViewer>` is generic over this union
|
|
76
76
|
* — the hub's `DOC_SOURCES` registry defines the actual ids. Listed here as a
|
|
77
77
|
* type-only union so the lib can flow the id into `DocRenderHandlers.sourceId`
|
|
78
|
-
* without callers having to cast `string`
|
|
78
|
+
* without callers having to cast `string` to the union.
|
|
79
79
|
*
|
|
80
80
|
* Adding a new source = add the id here AND register it in the hub. The lib
|
|
81
81
|
* never reaches into the registry — this is purely a type-narrowing handle.
|
|
82
82
|
*/
|
|
83
|
-
export type DocSourceId = 'openframe-docs' | 'data-room-docs';
|
|
83
|
+
export type DocSourceId = 'openframe-docs' | 'data-room-docs' | 'company-policies';
|
|
84
84
|
|
|
85
85
|
/**
|
|
86
86
|
* Result returned by the resolve-link endpoint. Discriminator-style: `success`
|
|
@@ -102,3 +102,30 @@ export function getDocSourceDefaultPath(
|
|
|
102
102
|
const firstFolderWithReadme = structure.find(node => node.type === 'folder' && node.hasReadme && !!node.path);
|
|
103
103
|
return firstFolderWithReadme?.path ?? null;
|
|
104
104
|
}
|
|
105
|
+
|
|
106
|
+
/** The first document under a folder (its own files first, then each subfolder's, in order), never a diagram source. */
|
|
107
|
+
export function findFirstDocPath(folder: DocNode): string | null {
|
|
108
|
+
const children = folder.children ?? [];
|
|
109
|
+
for (const child of children) {
|
|
110
|
+
if (child.type === 'file' && !child.path.toLowerCase().endsWith('.mmd')) return child.path;
|
|
111
|
+
}
|
|
112
|
+
for (const child of children) {
|
|
113
|
+
if (child.type === 'folder') {
|
|
114
|
+
const nested = findFirstDocPath(child);
|
|
115
|
+
if (nested) return nested;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* The document a source's root shows: its folder index when the tree has one, else its first document (the rule a
|
|
123
|
+
* folder with no README follows), else null (a tree with no document at all).
|
|
124
|
+
*/
|
|
125
|
+
export function rootDocumentPath(
|
|
126
|
+
structure: DocNode[],
|
|
127
|
+
folderIndexFile: string = DEFAULT_FOLDER_INDEX_FILE,
|
|
128
|
+
): string | null {
|
|
129
|
+
if (structure.some(node => node.type === 'file' && node.path === folderIndexFile)) return folderIndexFile;
|
|
130
|
+
return findFirstDocPath({ id: '', name: '', slug: '', path: '', type: 'folder', children: structure });
|
|
131
|
+
}
|
package/src/utils/list-url.ts
CHANGED
|
@@ -99,7 +99,8 @@ const BUILDERS: Record<string, (ids: string[], base: string) => string> = {
|
|
|
99
99
|
slack_message: (ids, b) => `${b}/api/slack-community/messages?ids=${ids.join(',')}`,
|
|
100
100
|
hubspot_ticket: (ids, b) => `${b}/api/tickets/internal?ids=${ids.join(',')}`,
|
|
101
101
|
hubspot_ticket_anon: (ids, b) => `${b}/api/tickets/known-issues?ids=${ids.join(',')}`,
|
|
102
|
-
data_room_doc: (ids, b) => `${b}/api/data-room/documents?ids=${ids.join(',')}`,
|
|
102
|
+
data_room_doc: (ids, b) => `${b}/api/libraries/data-room/documents?ids=${ids.join(',')}`,
|
|
103
|
+
policy_doc: (ids, b) => `${b}/api/libraries/company-policies/documents?ids=${ids.join(',')}`,
|
|
103
104
|
markdown: (ids, b) => `${b}/api/docs/pages?ids=${ids.join(',')}`,
|
|
104
105
|
financial_kpi: (ids, b) => `${b}/api/financials/kpis?ids=${ids.join(',')}`,
|
|
105
106
|
cap_table: (ids, b) => `${b}/api/financials/cap-table?ids=${ids.join(',')}`,
|
|
@@ -27,13 +27,13 @@ import { defaultDocumentTypeForTableId, getSourceLabel } from './source-icons';
|
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* Doc-table documentTypes: whole documents with their own viewer (markdown =
|
|
30
|
-
* product docs, data_room_doc = data room). They carry an in-app `path` (handed
|
|
30
|
+
* product docs, data_room_doc = data room, policy_doc = company policies). They carry an in-app `path` (handed
|
|
31
31
|
* to the host's composer as the slug), and a server never folds them
|
|
32
32
|
* into one citation (`groupsByTable`); the strip still draws them as one chip
|
|
33
33
|
* per table. The hub's per-source contract test pins this list to its
|
|
34
34
|
* doc-table configs.
|
|
35
35
|
*/
|
|
36
|
-
export const DOC_TABLE_TYPES = ['markdown', 'data_room_doc'] as const;
|
|
36
|
+
export const DOC_TABLE_TYPES = ['markdown', 'data_room_doc', 'policy_doc'] as const;
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
39
|
* Which tables a SERVER folds into one citation: rows of a knowledge table
|
|
@@ -29,6 +29,7 @@ export const SOURCE_ICON_NAMES: Record<string, string> = {
|
|
|
29
29
|
// Doc tables
|
|
30
30
|
'openframe-docs': 'openframe',
|
|
31
31
|
'data-room-docs': 'shield',
|
|
32
|
+
'company-policies': 'book-open',
|
|
32
33
|
|
|
33
34
|
// CMS / programs
|
|
34
35
|
'blog-posts': 'newspaper',
|
|
@@ -136,6 +137,7 @@ export const SOURCE_LABELS_BY_TABLE: Record<string, string> = {
|
|
|
136
137
|
// Doc tables
|
|
137
138
|
'openframe-docs': 'OpenFrame Docs',
|
|
138
139
|
'data-room-docs': 'Data Room',
|
|
140
|
+
'company-policies': 'Company Policies',
|
|
139
141
|
|
|
140
142
|
// CMS / programs
|
|
141
143
|
'blog-posts': 'Blog Posts',
|
|
@@ -242,6 +244,7 @@ export const DEFAULT_DOCUMENT_TYPE_TO_TABLE_ID: Record<string, string> = {
|
|
|
242
244
|
// Doc tables
|
|
243
245
|
markdown: 'openframe-docs',
|
|
244
246
|
data_room_doc: 'data-room-docs',
|
|
247
|
+
policy_doc: 'company-policies',
|
|
245
248
|
|
|
246
249
|
// CMS / programs
|
|
247
250
|
blog_post: 'blog-posts',
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
export declare function MarkdownSkeleton({ region, }?: {
|
|
2
|
-
/** The loading state announces itself (`LoadingRegion`). `false` inside another loading region. Default `true`. */
|
|
3
|
-
region?: boolean;
|
|
4
|
-
}): import("react").JSX.Element;
|
|
5
|
-
/**
|
|
6
|
-
* Embed-style skeleton — matches the iframe loading state for `pdf`,
|
|
7
|
-
* `google_sheet`, `figma`, and `file` document types. Used by
|
|
8
|
-
* `<DocsHubPage>` as the default for non-markdown documentTypes.
|
|
9
|
-
*
|
|
10
|
-
* The skeleton is documentType-aware so its layout matches the actual
|
|
11
|
-
* viewer that will replace it:
|
|
12
|
-
* - `pdf` → header with title + TWO buttons (Preview, Download)
|
|
13
|
-
* - `google_sheet`/`figma` → header with title + ONE button/toggle
|
|
14
|
-
* - `file` → centered FileDownloadCard-style box
|
|
15
|
-
* - undefined / others → generic (1-button header)
|
|
16
|
-
*/
|
|
17
|
-
export interface EmbedSkeletonProps {
|
|
18
|
-
/** When provided, the header layout matches the eventual viewer's
|
|
19
|
-
* button count + arrangement, so the layout doesn't shift on load. */
|
|
20
|
-
documentType?: 'pdf' | 'google_sheet' | 'figma' | 'file' | string;
|
|
21
|
-
/** The loading state announces itself (`LoadingRegion`). `false` inside another loading region. Default `true`. */
|
|
22
|
-
region?: boolean;
|
|
23
|
-
}
|
|
24
|
-
export declare function EmbedSkeleton({ documentType, region }?: EmbedSkeletonProps): import("react").JSX.Element;
|
|
25
|
-
//# sourceMappingURL=skeletons.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"skeletons.d.ts","sourceRoot":"","sources":["../../../src/components/docs/skeletons.tsx"],"names":[],"mappings":"AA2BA,wBAAgB,gBAAgB,CAAC,EAC/B,MAAa,GACd,GAAE;IACD,mHAAmH;IACnH,MAAM,CAAC,EAAE,OAAO,CAAC;CACb,+BA2BL;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,kBAAkB;IACjC;2EACuE;IACvE,YAAY,CAAC,EAAE,KAAK,GAAG,cAAc,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;IAClE,mHAAmH;IACnH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,aAAa,CAAC,EAAE,YAAY,EAAE,MAAa,EAAE,GAAE,kBAAuB,+BAiDrF"}
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { cn } from "../../utils/cn.js";
|
|
4
|
-
import { EmbedLoadingSkeleton } from "../embeds/embed-iframe.js";
|
|
5
|
-
import { LoadingRegion } from "../loading/loading-region.js";
|
|
6
|
-
import { TextLineSkeleton, UnifiedSkeleton } from "../loading/unified-skeleton.js";
|
|
7
|
-
import { MARKDOWN_H2_CLASS, MARKDOWN_PARAGRAPH_CLASS } from "../ui/markdown/base-components.js";
|
|
8
|
-
import { MARKDOWN_RENDERER_CLASS } from "../ui/markdown/engine.js";
|
|
9
|
-
import { TEXT_SIZE_PRESETS } from "../ui/markdown/text-size.js";
|
|
10
|
-
const MARKDOWN_SKELETON_BLOCKS = [
|
|
11
|
-
{ kind: "p", lines: 4 },
|
|
12
|
-
{ kind: "p", lines: 4 },
|
|
13
|
-
{ kind: "p", lines: 5 },
|
|
14
|
-
{ kind: "h2" },
|
|
15
|
-
{ kind: "p", lines: 4 },
|
|
16
|
-
{ kind: "p", lines: 5 },
|
|
17
|
-
{ kind: "h2" },
|
|
18
|
-
{ kind: "p", lines: 3 },
|
|
19
|
-
{ kind: "p", lines: 4 }
|
|
20
|
-
];
|
|
21
|
-
const MARKDOWN_SKELETON_H2_CLASS = cn(MARKDOWN_H2_CLASS, TEXT_SIZE_PRESETS.default.h2);
|
|
22
|
-
const MARKDOWN_SKELETON_P_CLASS = cn(MARKDOWN_PARAGRAPH_CLASS, TEXT_SIZE_PRESETS.default.p);
|
|
23
|
-
function MarkdownSkeleton({
|
|
24
|
-
region = true
|
|
25
|
-
} = {}) {
|
|
26
|
-
return (
|
|
27
|
-
// The renderer's root class, and its box (no margin of its own, like the rendered body): the document's first fold.
|
|
28
|
-
/* @__PURE__ */ jsx(LoadingRegion, { label: "Loading the document", announce: region, className: MARKDOWN_RENDERER_CLASS, children: MARKDOWN_SKELETON_BLOCKS.map(
|
|
29
|
-
(block, i) => block.kind === "h2" ? (
|
|
30
|
-
// biome-ignore lint/suspicious/noArrayIndexKey: skeleton blocks never reorder
|
|
31
|
-
/* @__PURE__ */ jsx("h2", { className: MARKDOWN_SKELETON_H2_CLASS, "aria-hidden": true, children: /* @__PURE__ */ jsx(TextLineSkeleton, { type: "inherit", as: "span", className: "w-1/3" }) }, i)
|
|
32
|
-
) : (
|
|
33
|
-
// The last block ends the body with no margin, like the rendered one. Its own `last:mb-0` does not apply here:
|
|
34
|
-
// the region's status line follows the blocks, so the paragraph is not the last child.
|
|
35
|
-
// biome-ignore lint/suspicious/noArrayIndexKey: skeleton blocks never reorder
|
|
36
|
-
/* @__PURE__ */ jsx(
|
|
37
|
-
"p",
|
|
38
|
-
{
|
|
39
|
-
className: cn(MARKDOWN_SKELETON_P_CLASS, i === MARKDOWN_SKELETON_BLOCKS.length - 1 && "mb-0"),
|
|
40
|
-
"aria-hidden": true,
|
|
41
|
-
children: /* @__PURE__ */ jsx(TextLineSkeleton, { type: "inherit", as: "span", lines: block.lines, className: "w-full" })
|
|
42
|
-
},
|
|
43
|
-
i
|
|
44
|
-
)
|
|
45
|
-
)
|
|
46
|
-
) })
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
function EmbedSkeleton({ documentType, region = true } = {}) {
|
|
50
|
-
if (documentType === "file") {
|
|
51
|
-
return /* @__PURE__ */ jsx(
|
|
52
|
-
LoadingRegion,
|
|
53
|
-
{
|
|
54
|
-
label: "Loading the document",
|
|
55
|
-
announce: region,
|
|
56
|
-
className: "flex flex-col items-center justify-center py-16",
|
|
57
|
-
children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-md space-y-4 rounded-xl border border-ods-border bg-ods-card p-8 text-center", children: [
|
|
58
|
-
/* @__PURE__ */ jsx(UnifiedSkeleton, { className: "mx-auto h-16 w-16 rounded" }),
|
|
59
|
-
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
60
|
-
/* @__PURE__ */ jsx(UnifiedSkeleton, { className: "mx-auto h-5 w-2/3 rounded" }),
|
|
61
|
-
/* @__PURE__ */ jsx(UnifiedSkeleton, { className: "mx-auto h-4 w-1/2 rounded" })
|
|
62
|
-
] }),
|
|
63
|
-
/* @__PURE__ */ jsx(UnifiedSkeleton, { className: "h-10 w-full rounded" })
|
|
64
|
-
] })
|
|
65
|
-
}
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
const buttonCount = documentType === "pdf" ? 2 : 1;
|
|
69
|
-
return /* @__PURE__ */ jsxs(LoadingRegion, { label: "Loading the document", announce: region, className: "space-y-4", children: [
|
|
70
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 content-sm:flex-row content-sm:items-center content-sm:justify-between", children: [
|
|
71
|
-
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
|
|
72
|
-
/* @__PURE__ */ jsx(UnifiedSkeleton, { className: "h-5 w-5 shrink-0 rounded" }),
|
|
73
|
-
/* @__PURE__ */ jsx(UnifiedSkeleton, { className: "h-6 w-2/3 rounded" })
|
|
74
|
-
] }),
|
|
75
|
-
/* @__PURE__ */ jsx("div", { className: "flex w-full items-center gap-2 content-sm:w-auto", children: Array.from({ length: buttonCount }).map((_, i) => /* @__PURE__ */ jsx(UnifiedSkeleton, { className: "h-10 w-full flex-1 rounded content-sm:w-32 content-sm:flex-initial" }, i)) })
|
|
76
|
-
] }),
|
|
77
|
-
/* @__PURE__ */ jsx(EmbedLoadingSkeleton, { region: false })
|
|
78
|
-
] });
|
|
79
|
-
}
|
|
80
|
-
export {
|
|
81
|
-
EmbedSkeleton,
|
|
82
|
-
MarkdownSkeleton
|
|
83
|
-
};
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
import { cn } from '../../utils/cn';
|
|
2
|
-
import { EmbedLoadingSkeleton } from '../embeds/embed-iframe';
|
|
3
|
-
import { LoadingRegion } from '../loading/loading-region';
|
|
4
|
-
import { TextLineSkeleton, UnifiedSkeleton } from '../loading/unified-skeleton';
|
|
5
|
-
import { MARKDOWN_H2_CLASS, MARKDOWN_PARAGRAPH_CLASS } from '../ui/markdown/base-components';
|
|
6
|
-
import { MARKDOWN_RENDERER_CLASS } from '../ui/markdown/engine';
|
|
7
|
-
import { TEXT_SIZE_PRESETS } from '../ui/markdown/text-size';
|
|
8
|
-
/**
|
|
9
|
-
* Text-style skeleton — matches a rendered markdown article layout.
|
|
10
|
-
* Used by `<DocsHubPage>` as the default for `markdown` (and unknown
|
|
11
|
-
* document types). Embedders can override via `renderSkeleton`.
|
|
12
|
-
*/
|
|
13
|
-
/** Paragraphs and headings the markdown skeleton draws (a document's first fold), with each paragraph's lines. */
|
|
14
|
-
const MARKDOWN_SKELETON_BLOCKS = [
|
|
15
|
-
{ kind: 'p', lines: 4 },
|
|
16
|
-
{ kind: 'p', lines: 4 },
|
|
17
|
-
{ kind: 'p', lines: 5 },
|
|
18
|
-
{ kind: 'h2' },
|
|
19
|
-
{ kind: 'p', lines: 4 },
|
|
20
|
-
{ kind: 'p', lines: 5 },
|
|
21
|
-
{ kind: 'h2' },
|
|
22
|
-
{ kind: 'p', lines: 3 },
|
|
23
|
-
{ kind: 'p', lines: 4 },
|
|
24
|
-
] as const;
|
|
25
|
-
const MARKDOWN_SKELETON_H2_CLASS = cn(MARKDOWN_H2_CLASS, TEXT_SIZE_PRESETS.default.h2);
|
|
26
|
-
const MARKDOWN_SKELETON_P_CLASS = cn(MARKDOWN_PARAGRAPH_CLASS, TEXT_SIZE_PRESETS.default.p);
|
|
27
|
-
|
|
28
|
-
export function MarkdownSkeleton({
|
|
29
|
-
region = true,
|
|
30
|
-
}: {
|
|
31
|
-
/** The loading state announces itself (`LoadingRegion`). `false` inside another loading region. Default `true`. */
|
|
32
|
-
region?: boolean;
|
|
33
|
-
} = {}) {
|
|
34
|
-
// The rendered document's own heading and paragraph elements (the markdown renderer's default preset), each line a
|
|
35
|
-
// bar of the element's line box.
|
|
36
|
-
return (
|
|
37
|
-
// The renderer's root class, and its box (no margin of its own, like the rendered body): the document's first fold.
|
|
38
|
-
<LoadingRegion label="Loading the document" announce={region} className={MARKDOWN_RENDERER_CLASS}>
|
|
39
|
-
{MARKDOWN_SKELETON_BLOCKS.map((block, i) =>
|
|
40
|
-
block.kind === 'h2' ? (
|
|
41
|
-
// biome-ignore lint/suspicious/noArrayIndexKey: skeleton blocks never reorder
|
|
42
|
-
<h2 key={i} className={MARKDOWN_SKELETON_H2_CLASS} aria-hidden>
|
|
43
|
-
<TextLineSkeleton type="inherit" as="span" className="w-1/3" />
|
|
44
|
-
</h2>
|
|
45
|
-
) : (
|
|
46
|
-
// The last block ends the body with no margin, like the rendered one. Its own `last:mb-0` does not apply here:
|
|
47
|
-
// the region's status line follows the blocks, so the paragraph is not the last child.
|
|
48
|
-
// biome-ignore lint/suspicious/noArrayIndexKey: skeleton blocks never reorder
|
|
49
|
-
<p
|
|
50
|
-
key={i}
|
|
51
|
-
className={cn(MARKDOWN_SKELETON_P_CLASS, i === MARKDOWN_SKELETON_BLOCKS.length - 1 && 'mb-0')}
|
|
52
|
-
aria-hidden
|
|
53
|
-
>
|
|
54
|
-
<TextLineSkeleton type="inherit" as="span" lines={block.lines} className="w-full" />
|
|
55
|
-
</p>
|
|
56
|
-
),
|
|
57
|
-
)}
|
|
58
|
-
</LoadingRegion>
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Embed-style skeleton — matches the iframe loading state for `pdf`,
|
|
64
|
-
* `google_sheet`, `figma`, and `file` document types. Used by
|
|
65
|
-
* `<DocsHubPage>` as the default for non-markdown documentTypes.
|
|
66
|
-
*
|
|
67
|
-
* The skeleton is documentType-aware so its layout matches the actual
|
|
68
|
-
* viewer that will replace it:
|
|
69
|
-
* - `pdf` → header with title + TWO buttons (Preview, Download)
|
|
70
|
-
* - `google_sheet`/`figma` → header with title + ONE button/toggle
|
|
71
|
-
* - `file` → centered FileDownloadCard-style box
|
|
72
|
-
* - undefined / others → generic (1-button header)
|
|
73
|
-
*/
|
|
74
|
-
export interface EmbedSkeletonProps {
|
|
75
|
-
/** When provided, the header layout matches the eventual viewer's
|
|
76
|
-
* button count + arrangement, so the layout doesn't shift on load. */
|
|
77
|
-
documentType?: 'pdf' | 'google_sheet' | 'figma' | 'file' | string;
|
|
78
|
-
/** The loading state announces itself (`LoadingRegion`). `false` inside another loading region. Default `true`. */
|
|
79
|
-
region?: boolean;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export function EmbedSkeleton({ documentType, region = true }: EmbedSkeletonProps = {}) {
|
|
83
|
-
// Centered card shape for the `file` documentType — matches
|
|
84
|
-
// `<FileDownloadCard>`'s `flex flex-col items-center justify-center py-16`
|
|
85
|
-
// + bordered card with icon, name, type/size row, Download button.
|
|
86
|
-
if (documentType === 'file') {
|
|
87
|
-
return (
|
|
88
|
-
<LoadingRegion
|
|
89
|
-
label="Loading the document"
|
|
90
|
-
announce={region}
|
|
91
|
-
className="flex flex-col items-center justify-center py-16"
|
|
92
|
-
>
|
|
93
|
-
<div className="w-full max-w-md space-y-4 rounded-xl border border-ods-border bg-ods-card p-8 text-center">
|
|
94
|
-
<UnifiedSkeleton className="mx-auto h-16 w-16 rounded" />
|
|
95
|
-
<div className="space-y-2">
|
|
96
|
-
<UnifiedSkeleton className="mx-auto h-5 w-2/3 rounded" />
|
|
97
|
-
<UnifiedSkeleton className="mx-auto h-4 w-1/2 rounded" />
|
|
98
|
-
</div>
|
|
99
|
-
<UnifiedSkeleton className="h-10 w-full rounded" />
|
|
100
|
-
</div>
|
|
101
|
-
</LoadingRegion>
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// PDF viewer has TWO buttons (Preview + Download); Sheets / Figma
|
|
106
|
-
// render ONE (Open / view-toggle). Default to one for unknown types.
|
|
107
|
-
const buttonCount = documentType === 'pdf' ? 2 : 1;
|
|
108
|
-
|
|
109
|
-
return (
|
|
110
|
-
<LoadingRegion label="Loading the document" announce={region} className="space-y-4">
|
|
111
|
-
{/* Header — matches the actual viewer's
|
|
112
|
-
* `flex flex-col gap-3 content-sm:flex-row content-sm:items-center content-sm:justify-between`
|
|
113
|
-
* (mobile-stacked, desktop-row). */}
|
|
114
|
-
<div className="flex flex-col gap-3 content-sm:flex-row content-sm:items-center content-sm:justify-between">
|
|
115
|
-
{/* Left: icon + title */}
|
|
116
|
-
<div className="flex min-w-0 flex-1 items-center gap-2">
|
|
117
|
-
<UnifiedSkeleton className="h-5 w-5 shrink-0 rounded" />
|
|
118
|
-
<UnifiedSkeleton className="h-6 w-2/3 rounded" />
|
|
119
|
-
</div>
|
|
120
|
-
{/* Right: 1 or 2 buttons. Mobile = full-width; desktop = auto. */}
|
|
121
|
-
<div className="flex w-full items-center gap-2 content-sm:w-auto">
|
|
122
|
-
{Array.from({ length: buttonCount }).map((_, i) => (
|
|
123
|
-
<UnifiedSkeleton key={i} className="h-10 w-full flex-1 rounded content-sm:w-32 content-sm:flex-initial" />
|
|
124
|
-
))}
|
|
125
|
-
</div>
|
|
126
|
-
</div>
|
|
127
|
-
{/* Body: the iframe viewer's own loading box (its default `calc(100vh - 250px)` height). */}
|
|
128
|
-
<EmbedLoadingSkeleton region={false} />
|
|
129
|
-
</LoadingRegion>
|
|
130
|
-
);
|
|
131
|
-
}
|