@lamberl-lee/file-preview 0.2.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/COPYING +674 -0
- package/LICENSE +165 -0
- package/README.md +165 -0
- package/dist/AudioPreview.d.ts +9 -0
- package/dist/AudioPreview.js +29 -0
- package/dist/AudioPreview.js.map +1 -0
- package/dist/CodePreview.d.ts +10 -0
- package/dist/CodePreview.js +121 -0
- package/dist/CodePreview.js.map +1 -0
- package/dist/CsvPreview.d.ts +9 -0
- package/dist/CsvPreview.js +117 -0
- package/dist/CsvPreview.js.map +1 -0
- package/dist/DocxPreview.d.ts +11 -0
- package/dist/DocxPreview.js +89 -0
- package/dist/DocxPreview.js.map +1 -0
- package/dist/EpubPreview.d.ts +9 -0
- package/dist/EpubPreview.js +693 -0
- package/dist/EpubPreview.js.map +1 -0
- package/dist/HtmlPreview.d.ts +9 -0
- package/dist/HtmlPreview.js +60 -0
- package/dist/HtmlPreview.js.map +1 -0
- package/dist/ImagePreview.d.ts +9 -0
- package/dist/ImagePreview.js +44 -0
- package/dist/ImagePreview.js.map +1 -0
- package/dist/LargeFileGate.d.ts +12 -0
- package/dist/LargeFileGate.js +88 -0
- package/dist/LargeFileGate.js.map +1 -0
- package/dist/MarkdownPreview.d.ts +8 -0
- package/dist/MarkdownPreview.js +140 -0
- package/dist/MarkdownPreview.js.map +1 -0
- package/dist/PdfPreview.d.ts +11 -0
- package/dist/PdfPreview.js +206 -0
- package/dist/PdfPreview.js.map +1 -0
- package/dist/PlainTextLargePreview.d.ts +9 -0
- package/dist/PlainTextLargePreview.js +62 -0
- package/dist/PlainTextLargePreview.js.map +1 -0
- package/dist/PluginPreviewRenderer.d.ts +13 -0
- package/dist/PluginPreviewRenderer.js +89 -0
- package/dist/PluginPreviewRenderer.js.map +1 -0
- package/dist/PptxPreview.d.ts +16 -0
- package/dist/PptxPreview.js +376 -0
- package/dist/PptxPreview.js.map +1 -0
- package/dist/PreviewErrorBoundary.d.ts +29 -0
- package/dist/PreviewErrorBoundary.js +53 -0
- package/dist/PreviewErrorBoundary.js.map +1 -0
- package/dist/PreviewFallback.d.ts +18 -0
- package/dist/PreviewFallback.js +143 -0
- package/dist/PreviewFallback.js.map +1 -0
- package/dist/PreviewLoading.d.ts +8 -0
- package/dist/PreviewLoading.js +14 -0
- package/dist/PreviewLoading.js.map +1 -0
- package/dist/RtfPreview.d.ts +10 -0
- package/dist/RtfPreview.js +240 -0
- package/dist/RtfPreview.js.map +1 -0
- package/dist/ShikiSourceView.d.ts +11 -0
- package/dist/ShikiSourceView.js +112 -0
- package/dist/ShikiSourceView.js.map +1 -0
- package/dist/SvgPreview.d.ts +9 -0
- package/dist/SvgPreview.js +89 -0
- package/dist/SvgPreview.js.map +1 -0
- package/dist/TextPreview.d.ts +9 -0
- package/dist/TextPreview.js +9 -0
- package/dist/TextPreview.js.map +1 -0
- package/dist/VideoPreview.d.ts +9 -0
- package/dist/VideoPreview.js +18 -0
- package/dist/VideoPreview.js.map +1 -0
- package/dist/XlsxPreview.d.ts +12 -0
- package/dist/XlsxPreview.js +856 -0
- package/dist/XlsxPreview.js.map +1 -0
- package/dist/ZipPreview.d.ts +9 -0
- package/dist/ZipPreview.js +153 -0
- package/dist/ZipPreview.js.map +1 -0
- package/dist/core/binary.d.ts +10 -0
- package/dist/core/binary.js +27 -0
- package/dist/core/binary.js.map +1 -0
- package/dist/core/config.d.ts +17 -0
- package/dist/core/config.js +19 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/download.d.ts +5 -0
- package/dist/core/download.js +20 -0
- package/dist/core/download.js.map +1 -0
- package/dist/core/i18n.d.ts +101 -0
- package/dist/core/i18n.js +200 -0
- package/dist/core/i18n.js.map +1 -0
- package/dist/core/plugin.d.ts +38 -0
- package/dist/core/plugin.js +46 -0
- package/dist/core/plugin.js.map +1 -0
- package/dist/core/registry.d.ts +13 -0
- package/dist/core/registry.js +33 -0
- package/dist/core/registry.js.map +1 -0
- package/dist/core/source.d.ts +14 -0
- package/dist/core/source.js +131 -0
- package/dist/core/source.js.map +1 -0
- package/dist/core/types.d.ts +88 -0
- package/dist/core/types.js +27 -0
- package/dist/core/types.js.map +1 -0
- package/dist/hooks/useObjectUrlFromSource.d.ts +9 -0
- package/dist/hooks/useObjectUrlFromSource.js +50 -0
- package/dist/hooks/useObjectUrlFromSource.js.map +1 -0
- package/dist/hooks/useSourceBase64.d.ts +10 -0
- package/dist/hooks/useSourceBase64.js +32 -0
- package/dist/hooks/useSourceBase64.js.map +1 -0
- package/dist/hooks/useSourceText.d.ts +10 -0
- package/dist/hooks/useSourceText.js +32 -0
- package/dist/hooks/useSourceText.js.map +1 -0
- package/dist/icons.d.ts +44 -0
- package/dist/icons.js +248 -0
- package/dist/icons.js.map +1 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.js +147 -0
- package/dist/index.js.map +1 -0
- package/dist/limits.d.ts +26 -0
- package/dist/limits.js +45 -0
- package/dist/limits.js.map +1 -0
- package/dist/performance-limits.d.ts +27 -0
- package/dist/performance-limits.js +54 -0
- package/dist/performance-limits.js.map +1 -0
- package/dist/plugins/audio-plugin.d.ts +7 -0
- package/dist/plugins/audio-plugin.js +11 -0
- package/dist/plugins/audio-plugin.js.map +1 -0
- package/dist/plugins/builtin-plugins.d.ts +9 -0
- package/dist/plugins/builtin-plugins.js +43 -0
- package/dist/plugins/builtin-plugins.js.map +1 -0
- package/dist/plugins/csv-plugin.d.ts +7 -0
- package/dist/plugins/csv-plugin.js +11 -0
- package/dist/plugins/csv-plugin.js.map +1 -0
- package/dist/plugins/docx-plugin.d.ts +7 -0
- package/dist/plugins/docx-plugin.js +15 -0
- package/dist/plugins/docx-plugin.js.map +1 -0
- package/dist/plugins/epub-plugin.d.ts +7 -0
- package/dist/plugins/epub-plugin.js +15 -0
- package/dist/plugins/epub-plugin.js.map +1 -0
- package/dist/plugins/html-plugin.d.ts +7 -0
- package/dist/plugins/html-plugin.js +11 -0
- package/dist/plugins/html-plugin.js.map +1 -0
- package/dist/plugins/image-plugin.d.ts +7 -0
- package/dist/plugins/image-plugin.js +11 -0
- package/dist/plugins/image-plugin.js.map +1 -0
- package/dist/plugins/markdown-plugin.d.ts +7 -0
- package/dist/plugins/markdown-plugin.js +11 -0
- package/dist/plugins/markdown-plugin.js.map +1 -0
- package/dist/plugins/pdf-plugin.d.ts +7 -0
- package/dist/plugins/pdf-plugin.js +15 -0
- package/dist/plugins/pdf-plugin.js.map +1 -0
- package/dist/plugins/pptx-plugin.d.ts +7 -0
- package/dist/plugins/pptx-plugin.js +15 -0
- package/dist/plugins/pptx-plugin.js.map +1 -0
- package/dist/plugins/rtf-plugin.d.ts +7 -0
- package/dist/plugins/rtf-plugin.js +15 -0
- package/dist/plugins/rtf-plugin.js.map +1 -0
- package/dist/plugins/source-code-plugin.d.ts +7 -0
- package/dist/plugins/source-code-plugin.js +11 -0
- package/dist/plugins/source-code-plugin.js.map +1 -0
- package/dist/plugins/svg-plugin.d.ts +7 -0
- package/dist/plugins/svg-plugin.js +11 -0
- package/dist/plugins/svg-plugin.js.map +1 -0
- package/dist/plugins/text-plugin.d.ts +7 -0
- package/dist/plugins/text-plugin.js +11 -0
- package/dist/plugins/text-plugin.js.map +1 -0
- package/dist/plugins/video-plugin.d.ts +7 -0
- package/dist/plugins/video-plugin.js +11 -0
- package/dist/plugins/video-plugin.js.map +1 -0
- package/dist/plugins/xlsx-plugin.d.ts +7 -0
- package/dist/plugins/xlsx-plugin.js +15 -0
- package/dist/plugins/xlsx-plugin.js.map +1 -0
- package/dist/plugins/zip-plugin.d.ts +7 -0
- package/dist/plugins/zip-plugin.js +15 -0
- package/dist/plugins/zip-plugin.js.map +1 -0
- package/dist/preview-adapters/AudioPreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/AudioPreviewAdapter.js +31 -0
- package/dist/preview-adapters/AudioPreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/CsvPreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/CsvPreviewAdapter.js +28 -0
- package/dist/preview-adapters/CsvPreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/DocxPreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/DocxPreviewAdapter.js +16 -0
- package/dist/preview-adapters/DocxPreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/EpubPreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/EpubPreviewAdapter.js +28 -0
- package/dist/preview-adapters/EpubPreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/HtmlPreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/HtmlPreviewAdapter.js +28 -0
- package/dist/preview-adapters/HtmlPreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/ImagePreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/ImagePreviewAdapter.js +31 -0
- package/dist/preview-adapters/ImagePreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/MarkdownPreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/MarkdownPreviewAdapter.js +28 -0
- package/dist/preview-adapters/MarkdownPreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/PdfPreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/PdfPreviewAdapter.js +16 -0
- package/dist/preview-adapters/PdfPreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/PptxPreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/PptxPreviewAdapter.js +16 -0
- package/dist/preview-adapters/PptxPreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/RtfPreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/RtfPreviewAdapter.js +54 -0
- package/dist/preview-adapters/RtfPreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/SourceCodePreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/SourceCodePreviewAdapter.js +35 -0
- package/dist/preview-adapters/SourceCodePreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/SvgPreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/SvgPreviewAdapter.js +28 -0
- package/dist/preview-adapters/SvgPreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/TextPreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/TextPreviewAdapter.js +28 -0
- package/dist/preview-adapters/TextPreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/UnsupportedPluginPreview.d.ts +11 -0
- package/dist/preview-adapters/UnsupportedPluginPreview.js +34 -0
- package/dist/preview-adapters/UnsupportedPluginPreview.js.map +1 -0
- package/dist/preview-adapters/VideoPreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/VideoPreviewAdapter.js +31 -0
- package/dist/preview-adapters/VideoPreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/XlsxPreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/XlsxPreviewAdapter.js +17 -0
- package/dist/preview-adapters/XlsxPreviewAdapter.js.map +1 -0
- package/dist/preview-adapters/ZipPreviewAdapter.d.ts +8 -0
- package/dist/preview-adapters/ZipPreviewAdapter.js +28 -0
- package/dist/preview-adapters/ZipPreviewAdapter.js.map +1 -0
- package/dist/remote-url.d.ts +20 -0
- package/dist/remote-url.js +478 -0
- package/dist/remote-url.js.map +1 -0
- package/dist/rtf/load-rtfjs.d.ts +42 -0
- package/dist/rtf/load-rtfjs.js +71 -0
- package/dist/rtf/load-rtfjs.js.map +1 -0
- package/dist/rtf/normalize-codepage.d.ts +33 -0
- package/dist/rtf/normalize-codepage.js +88 -0
- package/dist/rtf/normalize-codepage.js.map +1 -0
- package/dist/shiki.d.ts +35 -0
- package/dist/shiki.js +128 -0
- package/dist/shiki.js.map +1 -0
- package/dist/styles/AudioPreview.css +35 -0
- package/dist/styles/CsvPreview.css +106 -0
- package/dist/styles/DocxPreview.css +93 -0
- package/dist/styles/EpubPreview.css +509 -0
- package/dist/styles/HtmlPreview.css +15 -0
- package/dist/styles/ImagePreview.css +45 -0
- package/dist/styles/LargeFileGate.css +55 -0
- package/dist/styles/MarkdownPreview.css +291 -0
- package/dist/styles/PdfPreview.css +68 -0
- package/dist/styles/PlainTextLargePreview.css +85 -0
- package/dist/styles/PluginDebugBar.css +30 -0
- package/dist/styles/PptxPreview.css +207 -0
- package/dist/styles/PreviewFallback.css +88 -0
- package/dist/styles/PreviewLoading.css +13 -0
- package/dist/styles/RtfPreview.css +99 -0
- package/dist/styles/ShikiSourceView.css +159 -0
- package/dist/styles/SvgPreview.css +99 -0
- package/dist/styles/VideoPreview.css +19 -0
- package/dist/styles/ViewModeBar.css +38 -0
- package/dist/styles/XlsxPreview.css +361 -0
- package/dist/styles/ZipPreview.css +86 -0
- package/dist/styles/base.css +238 -0
- package/dist/styles/index.css +39 -0
- package/dist/support-status.d.ts +19 -0
- package/dist/support-status.js +174 -0
- package/dist/support-status.js.map +1 -0
- package/dist/utils.d.ts +17 -0
- package/dist/utils.js +205 -0
- package/dist/utils.js.map +1 -0
- package/package.json +125 -0
- package/scripts/copy-pdf-worker.mjs +31 -0
- package/scripts/copy-rtfjs-bundles.mjs +49 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codepage normalization for RTF input.
|
|
3
|
+
*
|
|
4
|
+
* rtf.js defaults to Windows-1252 when a document declares only `\rtf1\ansi`
|
|
5
|
+
* without `\ansicpgN`. Files that look like
|
|
6
|
+
*
|
|
7
|
+
* {\rtf1\ansi\deff0
|
|
8
|
+
* {\fonttbl{\f0\fcharset134 SimSun;}}
|
|
9
|
+
* \f0 \'d6\'d0\'b9\'fa\par}
|
|
10
|
+
*
|
|
11
|
+
* (very common in legacy WPS / Mac TextEdit exports) then decode as
|
|
12
|
+
* mojibake even though the font table tells us the document is GBK-encoded.
|
|
13
|
+
*
|
|
14
|
+
* Fix: sniff the font table for the first non-default `\fcharsetN`, map it
|
|
15
|
+
* to a Windows codepage, and inject `\ansicpgN` after `\ansi`. We never
|
|
16
|
+
* overwrite an existing `\ansicpg` — the document author knows best.
|
|
17
|
+
*
|
|
18
|
+
* RTF is 7-bit-clean (non-ASCII bytes always get escaped as `\'XX` or `\uN`),
|
|
19
|
+
* so we operate on the bytes as Latin-1 without changing semantics.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Public entry point: take RTF bytes, return either the same bytes or a
|
|
23
|
+
* patched copy with `\ansicpgN` injected based on font-table sniffing.
|
|
24
|
+
*
|
|
25
|
+
* Also returns the codepage that was applied (or `null`) — callers can
|
|
26
|
+
* use this for diagnostic logging.
|
|
27
|
+
*/
|
|
28
|
+
declare function normalizeRtfCodepage(buffer: ArrayBuffer): {
|
|
29
|
+
bytes: Uint8Array;
|
|
30
|
+
injectedCodepage: number | null;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export { normalizeRtfCodepage };
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
const FCHARSET_TO_CODEPAGE = {
|
|
2
|
+
0: 1252,
|
|
3
|
+
// ANSI (default Latin-1) — never inject this
|
|
4
|
+
// 2: 42 Symbol — pseudo
|
|
5
|
+
77: 1e4,
|
|
6
|
+
// Mac Roman
|
|
7
|
+
78: 10001,
|
|
8
|
+
// Mac Japanese
|
|
9
|
+
79: 10003,
|
|
10
|
+
// Mac Korean
|
|
11
|
+
80: 10008,
|
|
12
|
+
// Mac Simplified Chinese
|
|
13
|
+
81: 10002,
|
|
14
|
+
// Mac Traditional Chinese
|
|
15
|
+
128: 932,
|
|
16
|
+
// Shift-JIS (Japanese)
|
|
17
|
+
129: 949,
|
|
18
|
+
// EUC-KR (Korean)
|
|
19
|
+
130: 1361,
|
|
20
|
+
// Johab (Korean)
|
|
21
|
+
134: 936,
|
|
22
|
+
// GBK (Simplified Chinese)
|
|
23
|
+
136: 950,
|
|
24
|
+
// Big5 (Traditional Chinese)
|
|
25
|
+
161: 1253,
|
|
26
|
+
// Greek
|
|
27
|
+
162: 1254,
|
|
28
|
+
// Turkish
|
|
29
|
+
163: 1258,
|
|
30
|
+
// Vietnamese
|
|
31
|
+
177: 1255,
|
|
32
|
+
// Hebrew
|
|
33
|
+
178: 1256,
|
|
34
|
+
// Arabic
|
|
35
|
+
186: 1257,
|
|
36
|
+
// Baltic
|
|
37
|
+
204: 1251,
|
|
38
|
+
// Cyrillic
|
|
39
|
+
222: 874,
|
|
40
|
+
// Thai
|
|
41
|
+
238: 1250
|
|
42
|
+
// Eastern European
|
|
43
|
+
};
|
|
44
|
+
function detectCharsetFromFontTable(rtfText) {
|
|
45
|
+
const header = rtfText.slice(0, 8192);
|
|
46
|
+
const re = /\\fcharset(\d+)/g;
|
|
47
|
+
let m;
|
|
48
|
+
while ((m = re.exec(header)) !== null) {
|
|
49
|
+
const charset = parseInt(m[1], 10);
|
|
50
|
+
const cp = FCHARSET_TO_CODEPAGE[charset];
|
|
51
|
+
if (cp && cp !== 1252) return cp;
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
function injectAnsiCpg(bytes, codepage) {
|
|
56
|
+
const text = new TextDecoder("latin1").decode(bytes);
|
|
57
|
+
if (/\\ansicpg\d/.test(text)) return bytes;
|
|
58
|
+
const patched = text.replace(
|
|
59
|
+
/\\ansi(?=[^a-zA-Z0-9])/,
|
|
60
|
+
`\\ansi\\ansicpg${codepage}`
|
|
61
|
+
);
|
|
62
|
+
if (patched === text) return bytes;
|
|
63
|
+
const out = new Uint8Array(patched.length);
|
|
64
|
+
for (let i = 0; i < patched.length; i++) {
|
|
65
|
+
out[i] = patched.charCodeAt(i) & 255;
|
|
66
|
+
}
|
|
67
|
+
return out;
|
|
68
|
+
}
|
|
69
|
+
function normalizeRtfCodepage(buffer) {
|
|
70
|
+
const bytes = new Uint8Array(buffer);
|
|
71
|
+
const head = new TextDecoder("latin1").decode(bytes.slice(0, 256));
|
|
72
|
+
if (!head.trimStart().startsWith("{\\rtf")) {
|
|
73
|
+
return { bytes, injectedCodepage: null };
|
|
74
|
+
}
|
|
75
|
+
if (/\\ansicpg\d/.test(head)) {
|
|
76
|
+
return { bytes, injectedCodepage: null };
|
|
77
|
+
}
|
|
78
|
+
const text = new TextDecoder("latin1").decode(bytes);
|
|
79
|
+
const cp = detectCharsetFromFontTable(text);
|
|
80
|
+
if (cp === null) {
|
|
81
|
+
return { bytes, injectedCodepage: null };
|
|
82
|
+
}
|
|
83
|
+
return { bytes: injectAnsiCpg(bytes, cp), injectedCodepage: cp };
|
|
84
|
+
}
|
|
85
|
+
export {
|
|
86
|
+
normalizeRtfCodepage
|
|
87
|
+
};
|
|
88
|
+
//# sourceMappingURL=normalize-codepage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/rtf/normalize-codepage.ts"],"sourcesContent":["/**\n * Codepage normalization for RTF input.\n *\n * rtf.js defaults to Windows-1252 when a document declares only `\\rtf1\\ansi`\n * without `\\ansicpgN`. Files that look like\n *\n * {\\rtf1\\ansi\\deff0\n * {\\fonttbl{\\f0\\fcharset134 SimSun;}}\n * \\f0 \\'d6\\'d0\\'b9\\'fa\\par}\n *\n * (very common in legacy WPS / Mac TextEdit exports) then decode as\n * mojibake even though the font table tells us the document is GBK-encoded.\n *\n * Fix: sniff the font table for the first non-default `\\fcharsetN`, map it\n * to a Windows codepage, and inject `\\ansicpgN` after `\\ansi`. We never\n * overwrite an existing `\\ansicpg` — the document author knows best.\n *\n * RTF is 7-bit-clean (non-ASCII bytes always get escaped as `\\'XX` or `\\uN`),\n * so we operate on the bytes as Latin-1 without changing semantics.\n */\n\n/**\n * Map RTF `\\fcharsetN` values to Windows codepages.\n * Mirrors the `_charsetMap` in rtf.js's Helper.ts.\n */\nconst FCHARSET_TO_CODEPAGE: Record<number, number> = {\n 0: 1252, // ANSI (default Latin-1) — never inject this\n // 2: 42 Symbol — pseudo\n 77: 10000, // Mac Roman\n 78: 10001, // Mac Japanese\n 79: 10003, // Mac Korean\n 80: 10008, // Mac Simplified Chinese\n 81: 10002, // Mac Traditional Chinese\n 128: 932, // Shift-JIS (Japanese)\n 129: 949, // EUC-KR (Korean)\n 130: 1361, // Johab (Korean)\n 134: 936, // GBK (Simplified Chinese)\n 136: 950, // Big5 (Traditional Chinese)\n 161: 1253, // Greek\n 162: 1254, // Turkish\n 163: 1258, // Vietnamese\n 177: 1255, // Hebrew\n 178: 1256, // Arabic\n 186: 1257, // Baltic\n 204: 1251, // Cyrillic\n 222: 874, // Thai\n 238: 1250, // Eastern European\n};\n\n/**\n * Look at the bytes (as Latin-1 string), find a `\\fcharsetN` for which\n * `_charsetMap[N]` is a non-1252 codepage, and return that codepage.\n *\n * Returns `null` if no useful charset is declared — caller leaves the\n * stream unchanged.\n */\nfunction detectCharsetFromFontTable(rtfText: string): number | null {\n // Limit search to the document header area (first ~8 KB). The font table\n // is always declared near the top, and scanning the entire document\n // would risk matching `\\fcharsetN` inside style/list overrides which\n // are unrelated to the document's primary encoding.\n const header = rtfText.slice(0, 8192);\n\n // Find every \\fcharsetN occurrence in the header. We pick the FIRST\n // one with a CJK / non-Latin mapping — that's the document's primary\n // text font, the one rtf.js will use for unscoped text.\n const re = /\\\\fcharset(\\d+)/g;\n let m: RegExpExecArray | null;\n while ((m = re.exec(header)) !== null) {\n const charset = parseInt(m[1], 10);\n const cp = FCHARSET_TO_CODEPAGE[charset];\n if (cp && cp !== 1252) return cp;\n }\n return null;\n}\n\n/**\n * Inject `\\ansicpgN` after `\\ansi` in the byte stream. Returns the\n * modified Uint8Array, or `bytes` unchanged if no injection happened.\n */\nfunction injectAnsiCpg(bytes: Uint8Array, codepage: number): Uint8Array {\n // Decode as Latin-1 — every byte maps 1:1 to a JS char in 0x00-0xff,\n // so bytewise edits to ASCII regions stay byte-identical.\n const text = new TextDecoder(\"latin1\").decode(bytes);\n\n // Already has \\ansicpg? Don't second-guess.\n if (/\\\\ansicpg\\d/.test(text)) return bytes;\n\n // Insert right after `\\ansi` (not `\\ansiN` — `\\ansicpg` is what we want\n // to avoid colliding with). Only one replacement.\n const patched = text.replace(\n /\\\\ansi(?=[^a-zA-Z0-9])/,\n `\\\\ansi\\\\ansicpg${codepage}`,\n );\n if (patched === text) return bytes; // \\ansi not found — leave alone\n\n // Re-encode. TextEncoder produces UTF-8; for ASCII-only modifications\n // we want byte-identical output, so write a Latin-1 array manually.\n const out = new Uint8Array(patched.length);\n for (let i = 0; i < patched.length; i++) {\n out[i] = patched.charCodeAt(i) & 0xff;\n }\n return out;\n}\n\n/**\n * Public entry point: take RTF bytes, return either the same bytes or a\n * patched copy with `\\ansicpgN` injected based on font-table sniffing.\n *\n * Also returns the codepage that was applied (or `null`) — callers can\n * use this for diagnostic logging.\n */\nexport function normalizeRtfCodepage(buffer: ArrayBuffer): {\n bytes: Uint8Array;\n injectedCodepage: number | null;\n} {\n const bytes = new Uint8Array(buffer);\n\n // Cheap header peek — if we can't even decode the first bytes as RTF,\n // skip the work and let rtf.js produce its own error.\n const head = new TextDecoder(\"latin1\").decode(bytes.slice(0, 256));\n if (!head.trimStart().startsWith(\"{\\\\rtf\")) {\n return { bytes, injectedCodepage: null };\n }\n\n // Already declares its codepage? Trust it.\n if (/\\\\ansicpg\\d/.test(head)) {\n return { bytes, injectedCodepage: null };\n }\n\n const text = new TextDecoder(\"latin1\").decode(bytes);\n const cp = detectCharsetFromFontTable(text);\n if (cp === null) {\n return { bytes, injectedCodepage: null };\n }\n\n return { bytes: injectAnsiCpg(bytes, cp), injectedCodepage: cp };\n}\n"],"mappings":"AAyBA,MAAM,uBAA+C;AAAA,EACnD,GAAG;AAAA;AAAA;AAAA,EAEH,IAAI;AAAA;AAAA,EACJ,IAAI;AAAA;AAAA,EACJ,IAAI;AAAA;AAAA,EACJ,IAAI;AAAA;AAAA,EACJ,IAAI;AAAA;AAAA,EACJ,KAAK;AAAA;AAAA,EACL,KAAK;AAAA;AAAA,EACL,KAAK;AAAA;AAAA,EACL,KAAK;AAAA;AAAA,EACL,KAAK;AAAA;AAAA,EACL,KAAK;AAAA;AAAA,EACL,KAAK;AAAA;AAAA,EACL,KAAK;AAAA;AAAA,EACL,KAAK;AAAA;AAAA,EACL,KAAK;AAAA;AAAA,EACL,KAAK;AAAA;AAAA,EACL,KAAK;AAAA;AAAA,EACL,KAAK;AAAA;AAAA,EACL,KAAK;AAAA;AACP;AASA,SAAS,2BAA2B,SAAgC;AAKlE,QAAM,SAAS,QAAQ,MAAM,GAAG,IAAI;AAKpC,QAAM,KAAK;AACX,MAAI;AACJ,UAAQ,IAAI,GAAG,KAAK,MAAM,OAAO,MAAM;AACrC,UAAM,UAAU,SAAS,EAAE,CAAC,GAAG,EAAE;AACjC,UAAM,KAAK,qBAAqB,OAAO;AACvC,QAAI,MAAM,OAAO,KAAM,QAAO;AAAA,EAChC;AACA,SAAO;AACT;AAMA,SAAS,cAAc,OAAmB,UAA8B;AAGtE,QAAM,OAAO,IAAI,YAAY,QAAQ,EAAE,OAAO,KAAK;AAGnD,MAAI,cAAc,KAAK,IAAI,EAAG,QAAO;AAIrC,QAAM,UAAU,KAAK;AAAA,IACnB;AAAA,IACA,kBAAkB,QAAQ;AAAA,EAC5B;AACA,MAAI,YAAY,KAAM,QAAO;AAI7B,QAAM,MAAM,IAAI,WAAW,QAAQ,MAAM;AACzC,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,QAAI,CAAC,IAAI,QAAQ,WAAW,CAAC,IAAI;AAAA,EACnC;AACA,SAAO;AACT;AASO,SAAS,qBAAqB,QAGnC;AACA,QAAM,QAAQ,IAAI,WAAW,MAAM;AAInC,QAAM,OAAO,IAAI,YAAY,QAAQ,EAAE,OAAO,MAAM,MAAM,GAAG,GAAG,CAAC;AACjE,MAAI,CAAC,KAAK,UAAU,EAAE,WAAW,QAAQ,GAAG;AAC1C,WAAO,EAAE,OAAO,kBAAkB,KAAK;AAAA,EACzC;AAGA,MAAI,cAAc,KAAK,IAAI,GAAG;AAC5B,WAAO,EAAE,OAAO,kBAAkB,KAAK;AAAA,EACzC;AAEA,QAAM,OAAO,IAAI,YAAY,QAAQ,EAAE,OAAO,KAAK;AACnD,QAAM,KAAK,2BAA2B,IAAI;AAC1C,MAAI,OAAO,MAAM;AACf,WAAO,EAAE,OAAO,kBAAkB,KAAK;AAAA,EACzC;AAEA,SAAO,EAAE,OAAO,cAAc,OAAO,EAAE,GAAG,kBAAkB,GAAG;AACjE;","names":[]}
|
package/dist/shiki.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ShikiTransformer } from 'shiki';
|
|
2
|
+
export { codeToHtml as shikiCodeToHtml } from 'shiki';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Shiki highlighter — lazy loading via main entry
|
|
6
|
+
*
|
|
7
|
+
* The `shiki` main entry automatically code-splits each language and theme
|
|
8
|
+
* into separate async chunks. Only the ones actually used are loaded.
|
|
9
|
+
*
|
|
10
|
+
* Loading sequence for first code preview:
|
|
11
|
+
* 0KB (React.lazy) → core + JS engine + 1 lang + 2 themes ≈ 49KB gzip
|
|
12
|
+
*
|
|
13
|
+
* Turbopack/webpack automatically splits each @shikijs/langs/* and
|
|
14
|
+
* @shikijs/themes/* into separate chunks.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Highlight code with dual theme support (light/dark CSS variables)
|
|
19
|
+
*
|
|
20
|
+
* This is a wrapper around shiki's codeToHtml that:
|
|
21
|
+
* - Uses github-light/github-dark dual themes
|
|
22
|
+
* - Outputs CSS variables (defaultColor: false) for zero-cost theme switching
|
|
23
|
+
* - Adds line numbers via transformer
|
|
24
|
+
*/
|
|
25
|
+
declare function highlightCode(content: string, language: string): Promise<string>;
|
|
26
|
+
/**
|
|
27
|
+
* Map file extension → Shiki language ID
|
|
28
|
+
*/
|
|
29
|
+
declare function getShikiLanguage(fileName: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* Transformer: add data-line attribute to each line for CSS line numbers
|
|
32
|
+
*/
|
|
33
|
+
declare function transformerLineNumbers(): ShikiTransformer;
|
|
34
|
+
|
|
35
|
+
export { getShikiLanguage, highlightCode, transformerLineNumbers };
|
package/dist/shiki.js
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { codeToHtml as shikiCodeToHtml } from "shiki";
|
|
2
|
+
async function highlightCode(content, language) {
|
|
3
|
+
return shikiCodeToHtml(content, {
|
|
4
|
+
lang: language,
|
|
5
|
+
themes: {
|
|
6
|
+
light: "github-light",
|
|
7
|
+
dark: "github-dark"
|
|
8
|
+
},
|
|
9
|
+
defaultColor: false,
|
|
10
|
+
transformers: [transformerLineNumbers()]
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
function getShikiLanguage(fileName) {
|
|
14
|
+
const ext = fileName.toLowerCase().split(".").pop() || "";
|
|
15
|
+
const baseName = fileName.split("/").pop() || "";
|
|
16
|
+
const extMap = {
|
|
17
|
+
// Web
|
|
18
|
+
js: "javascript",
|
|
19
|
+
mjs: "javascript",
|
|
20
|
+
cjs: "javascript",
|
|
21
|
+
jsx: "jsx",
|
|
22
|
+
ts: "typescript",
|
|
23
|
+
tsx: "tsx",
|
|
24
|
+
html: "html",
|
|
25
|
+
htm: "html",
|
|
26
|
+
css: "css",
|
|
27
|
+
scss: "scss",
|
|
28
|
+
less: "less",
|
|
29
|
+
vue: "vue",
|
|
30
|
+
svelte: "svelte",
|
|
31
|
+
// Scripting
|
|
32
|
+
py: "python",
|
|
33
|
+
pyw: "python",
|
|
34
|
+
rb: "ruby",
|
|
35
|
+
php: "php",
|
|
36
|
+
pl: "perl",
|
|
37
|
+
pm: "perl",
|
|
38
|
+
lua: "lua",
|
|
39
|
+
r: "r",
|
|
40
|
+
// Systems
|
|
41
|
+
java: "java",
|
|
42
|
+
c: "c",
|
|
43
|
+
h: "c",
|
|
44
|
+
cpp: "cpp",
|
|
45
|
+
cc: "cpp",
|
|
46
|
+
cxx: "cpp",
|
|
47
|
+
hpp: "cpp",
|
|
48
|
+
cs: "csharp",
|
|
49
|
+
go: "go",
|
|
50
|
+
rs: "rust",
|
|
51
|
+
swift: "swift",
|
|
52
|
+
kt: "kotlin",
|
|
53
|
+
kts: "kotlin",
|
|
54
|
+
scala: "scala",
|
|
55
|
+
dart: "dart",
|
|
56
|
+
// Shell
|
|
57
|
+
sh: "bash",
|
|
58
|
+
bash: "bash",
|
|
59
|
+
zsh: "bash",
|
|
60
|
+
ps1: "powershell",
|
|
61
|
+
bat: "bat",
|
|
62
|
+
cmd: "bat",
|
|
63
|
+
// Data / Config
|
|
64
|
+
json: "json",
|
|
65
|
+
yml: "yaml",
|
|
66
|
+
yaml: "yaml",
|
|
67
|
+
toml: "toml",
|
|
68
|
+
ini: "ini",
|
|
69
|
+
cfg: "ini",
|
|
70
|
+
conf: "ini",
|
|
71
|
+
env: "ini",
|
|
72
|
+
sql: "sql",
|
|
73
|
+
graphql: "graphql",
|
|
74
|
+
gql: "graphql",
|
|
75
|
+
xml: "xml",
|
|
76
|
+
svg: "xml",
|
|
77
|
+
// DevOps
|
|
78
|
+
dockerfile: "dockerfile",
|
|
79
|
+
makefile: "makefile",
|
|
80
|
+
nginx: "nginx",
|
|
81
|
+
diff: "diff",
|
|
82
|
+
patch: "diff",
|
|
83
|
+
// Docs
|
|
84
|
+
md: "markdown",
|
|
85
|
+
mdx: "mdx",
|
|
86
|
+
tex: "latex",
|
|
87
|
+
adoc: "asciidoc",
|
|
88
|
+
// Functional / Other
|
|
89
|
+
ex: "elixir",
|
|
90
|
+
exs: "elixir",
|
|
91
|
+
clj: "clojure",
|
|
92
|
+
cljs: "clojure",
|
|
93
|
+
erl: "erlang",
|
|
94
|
+
hs: "haskell",
|
|
95
|
+
m: "matlab",
|
|
96
|
+
vim: "vim",
|
|
97
|
+
coffee: "coffeescript",
|
|
98
|
+
wasm: "wasm",
|
|
99
|
+
objectivec: "objectivec",
|
|
100
|
+
objectivecpp: "objectivec"
|
|
101
|
+
};
|
|
102
|
+
if (extMap[ext]) return extMap[ext];
|
|
103
|
+
const lowerBase = baseName.toLowerCase();
|
|
104
|
+
if (lowerBase === "dockerfile") return "dockerfile";
|
|
105
|
+
if (lowerBase === "makefile" || lowerBase === "gnumakefile") return "makefile";
|
|
106
|
+
if (lowerBase === "gemfile") return "ruby";
|
|
107
|
+
if (lowerBase === "rakefile") return "ruby";
|
|
108
|
+
if (lowerBase === ".gitignore" || lowerBase === ".env") return "ini";
|
|
109
|
+
if (lowerBase === ".eslintrc" || lowerBase === ".prettierrc") return "json";
|
|
110
|
+
if (lowerBase === "vagrantfile") return "ruby";
|
|
111
|
+
return "text";
|
|
112
|
+
}
|
|
113
|
+
function transformerLineNumbers() {
|
|
114
|
+
return {
|
|
115
|
+
name: "line-numbers",
|
|
116
|
+
line(lineProps, line) {
|
|
117
|
+
if (!lineProps.properties) lineProps.properties = {};
|
|
118
|
+
lineProps.properties["data-line"] = String(line);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
export {
|
|
123
|
+
getShikiLanguage,
|
|
124
|
+
highlightCode,
|
|
125
|
+
shikiCodeToHtml,
|
|
126
|
+
transformerLineNumbers
|
|
127
|
+
};
|
|
128
|
+
//# sourceMappingURL=shiki.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shiki.ts"],"sourcesContent":["/**\n * Shiki highlighter — lazy loading via main entry\n *\n * The `shiki` main entry automatically code-splits each language and theme\n * into separate async chunks. Only the ones actually used are loaded.\n *\n * Loading sequence for first code preview:\n * 0KB (React.lazy) → core + JS engine + 1 lang + 2 themes ≈ 49KB gzip\n *\n * Turbopack/webpack automatically splits each @shikijs/langs/* and\n * @shikijs/themes/* into separate chunks.\n */\n\nimport { codeToHtml as shikiCodeToHtml } from \"shiki\";\nimport type { ShikiTransformer } from \"shiki\";\n\n// Re-export for convenience\nexport { shikiCodeToHtml };\n\n/**\n * Highlight code with dual theme support (light/dark CSS variables)\n *\n * This is a wrapper around shiki's codeToHtml that:\n * - Uses github-light/github-dark dual themes\n * - Outputs CSS variables (defaultColor: false) for zero-cost theme switching\n * - Adds line numbers via transformer\n */\nexport async function highlightCode(\n content: string,\n language: string\n): Promise<string> {\n return shikiCodeToHtml(content, {\n lang: language,\n themes: {\n light: \"github-light\",\n dark: \"github-dark\",\n },\n defaultColor: false,\n transformers: [transformerLineNumbers()],\n });\n}\n\n/**\n * Map file extension → Shiki language ID\n */\nexport function getShikiLanguage(fileName: string): string {\n const ext = fileName.toLowerCase().split(\".\").pop() || \"\";\n const baseName = fileName.split(\"/\").pop() || \"\";\n\n const extMap: Record<string, string> = {\n // Web\n js: \"javascript\",\n mjs: \"javascript\",\n cjs: \"javascript\",\n jsx: \"jsx\",\n ts: \"typescript\",\n tsx: \"tsx\",\n html: \"html\",\n htm: \"html\",\n css: \"css\",\n scss: \"scss\",\n less: \"less\",\n vue: \"vue\",\n svelte: \"svelte\",\n // Scripting\n py: \"python\",\n pyw: \"python\",\n rb: \"ruby\",\n php: \"php\",\n pl: \"perl\",\n pm: \"perl\",\n lua: \"lua\",\n r: \"r\",\n // Systems\n java: \"java\",\n c: \"c\",\n h: \"c\",\n cpp: \"cpp\",\n cc: \"cpp\",\n cxx: \"cpp\",\n hpp: \"cpp\",\n cs: \"csharp\",\n go: \"go\",\n rs: \"rust\",\n swift: \"swift\",\n kt: \"kotlin\",\n kts: \"kotlin\",\n scala: \"scala\",\n dart: \"dart\",\n // Shell\n sh: \"bash\",\n bash: \"bash\",\n zsh: \"bash\",\n ps1: \"powershell\",\n bat: \"bat\",\n cmd: \"bat\",\n // Data / Config\n json: \"json\",\n yml: \"yaml\",\n yaml: \"yaml\",\n toml: \"toml\",\n ini: \"ini\",\n cfg: \"ini\",\n conf: \"ini\",\n env: \"ini\",\n sql: \"sql\",\n graphql: \"graphql\",\n gql: \"graphql\",\n xml: \"xml\",\n svg: \"xml\",\n // DevOps\n dockerfile: \"dockerfile\",\n makefile: \"makefile\",\n nginx: \"nginx\",\n diff: \"diff\",\n patch: \"diff\",\n // Docs\n md: \"markdown\",\n mdx: \"mdx\",\n tex: \"latex\",\n adoc: \"asciidoc\",\n // Functional / Other\n ex: \"elixir\",\n exs: \"elixir\",\n clj: \"clojure\",\n cljs: \"clojure\",\n erl: \"erlang\",\n hs: \"haskell\",\n m: \"matlab\",\n vim: \"vim\",\n coffee: \"coffeescript\",\n wasm: \"wasm\",\n objectivec: \"objectivec\",\n objectivecpp: \"objectivec\",\n };\n\n if (extMap[ext]) return extMap[ext];\n\n // Check base filename (case-insensitive)\n const lowerBase = baseName.toLowerCase();\n if (lowerBase === \"dockerfile\") return \"dockerfile\";\n if (lowerBase === \"makefile\" || lowerBase === \"gnumakefile\") return \"makefile\";\n if (lowerBase === \"gemfile\") return \"ruby\";\n if (lowerBase === \"rakefile\") return \"ruby\";\n if (lowerBase === \".gitignore\" || lowerBase === \".env\") return \"ini\";\n if (lowerBase === \".eslintrc\" || lowerBase === \".prettierrc\") return \"json\";\n if (lowerBase === \"vagrantfile\") return \"ruby\";\n\n return \"text\";\n}\n\n/**\n * Transformer: add data-line attribute to each line for CSS line numbers\n */\nexport function transformerLineNumbers(): ShikiTransformer {\n return {\n name: \"line-numbers\",\n line(lineProps, line) {\n // lineProps is a hast element; properties are in .properties\n if (!lineProps.properties) lineProps.properties = {};\n lineProps.properties[\"data-line\"] = String(line);\n },\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
.fv-audio {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
align-items: center;
|
|
5
|
+
justify-content: center;
|
|
6
|
+
height: 100%;
|
|
7
|
+
min-height: 300px;
|
|
8
|
+
gap: 1.5rem;
|
|
9
|
+
padding: 1.5rem;
|
|
10
|
+
}
|
|
11
|
+
.fv-audio__icon-wrap {
|
|
12
|
+
width: 6rem;
|
|
13
|
+
height: 6rem;
|
|
14
|
+
border-radius: 9999px;
|
|
15
|
+
background: linear-gradient(135deg, color-mix(in srgb, #8b5cf6 20%, transparent), color-mix(in srgb, #ec4899 20%, transparent));
|
|
16
|
+
display: flex;
|
|
17
|
+
align-items: center;
|
|
18
|
+
justify-content: center;
|
|
19
|
+
color: #8b5cf6;
|
|
20
|
+
}
|
|
21
|
+
.fv-audio__info {
|
|
22
|
+
text-align: center;
|
|
23
|
+
}
|
|
24
|
+
.fv-audio__name {
|
|
25
|
+
font-weight: 500;
|
|
26
|
+
}
|
|
27
|
+
.fv-audio__label {
|
|
28
|
+
font-size: var(--fv-font-size-sm);
|
|
29
|
+
color: var(--fv-muted-foreground);
|
|
30
|
+
margin-top: 0.25rem;
|
|
31
|
+
}
|
|
32
|
+
.fv-audio__player {
|
|
33
|
+
width: 100%;
|
|
34
|
+
max-width: 28rem;
|
|
35
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
.fv-csv {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
height: 100%;
|
|
5
|
+
}
|
|
6
|
+
.fv-csv__toolbar {
|
|
7
|
+
display: flex;
|
|
8
|
+
align-items: center;
|
|
9
|
+
gap: 0.75rem;
|
|
10
|
+
padding: 0.75rem;
|
|
11
|
+
border-bottom: 1px solid var(--fv-border);
|
|
12
|
+
background: color-mix(in srgb, var(--fv-muted) 30%, transparent);
|
|
13
|
+
}
|
|
14
|
+
.fv-csv__search-wrap {
|
|
15
|
+
position: relative;
|
|
16
|
+
flex: 1;
|
|
17
|
+
max-width: 20rem;
|
|
18
|
+
}
|
|
19
|
+
.fv-csv__search-icon {
|
|
20
|
+
position: absolute;
|
|
21
|
+
left: 0.625rem;
|
|
22
|
+
top: 50%;
|
|
23
|
+
transform: translateY(-50%);
|
|
24
|
+
color: var(--fv-muted-foreground);
|
|
25
|
+
pointer-events: none;
|
|
26
|
+
}
|
|
27
|
+
.fv-csv__search-input {
|
|
28
|
+
width: 100%;
|
|
29
|
+
padding: 0.375rem 0.75rem 0.375rem 2rem;
|
|
30
|
+
font-size: var(--fv-font-size-sm);
|
|
31
|
+
background: var(--fv-primary-foreground, #fff);
|
|
32
|
+
border: 1px solid var(--fv-border);
|
|
33
|
+
border-radius: var(--fv-radius);
|
|
34
|
+
outline: none;
|
|
35
|
+
color: var(--fv-primary);
|
|
36
|
+
}
|
|
37
|
+
.fv-csv__search-input:focus {
|
|
38
|
+
box-shadow: 0 0 0 2px color-mix(in srgb, var(--fv-primary) 20%, transparent);
|
|
39
|
+
}
|
|
40
|
+
.fv-csv__row-count {
|
|
41
|
+
font-size: var(--fv-font-size-xs);
|
|
42
|
+
color: var(--fv-muted-foreground);
|
|
43
|
+
}
|
|
44
|
+
.fv-csv__table-wrap {
|
|
45
|
+
overflow: auto;
|
|
46
|
+
flex: 1;
|
|
47
|
+
}
|
|
48
|
+
.fv-csv__table {
|
|
49
|
+
width: 100%;
|
|
50
|
+
font-size: var(--fv-font-size-sm);
|
|
51
|
+
border-collapse: collapse;
|
|
52
|
+
}
|
|
53
|
+
.fv-csv__thead {
|
|
54
|
+
position: sticky;
|
|
55
|
+
top: 0;
|
|
56
|
+
background: color-mix(in srgb, var(--fv-muted) 80%, transparent);
|
|
57
|
+
backdrop-filter: blur(4px);
|
|
58
|
+
z-index: 10;
|
|
59
|
+
}
|
|
60
|
+
.fv-csv__th {
|
|
61
|
+
padding: 0.5rem 0.75rem;
|
|
62
|
+
text-align: left;
|
|
63
|
+
font-weight: 500;
|
|
64
|
+
font-size: var(--fv-font-size-xs);
|
|
65
|
+
color: var(--fv-muted-foreground);
|
|
66
|
+
cursor: pointer;
|
|
67
|
+
white-space: nowrap;
|
|
68
|
+
transition: background 0.15s;
|
|
69
|
+
}
|
|
70
|
+
.fv-csv__th:hover {
|
|
71
|
+
background: var(--fv-muted);
|
|
72
|
+
}
|
|
73
|
+
.fv-csv__th-inner {
|
|
74
|
+
display: flex;
|
|
75
|
+
align-items: center;
|
|
76
|
+
gap: 0.25rem;
|
|
77
|
+
}
|
|
78
|
+
.fv-csv__sort-icon {
|
|
79
|
+
opacity: 0.5;
|
|
80
|
+
}
|
|
81
|
+
.fv-csv__sort-icon--active {
|
|
82
|
+
opacity: 1;
|
|
83
|
+
color: var(--fv-primary);
|
|
84
|
+
}
|
|
85
|
+
.fv-csv__th-num {
|
|
86
|
+
width: 3rem;
|
|
87
|
+
cursor: default;
|
|
88
|
+
}
|
|
89
|
+
.fv-csv__td {
|
|
90
|
+
padding: 0.5rem 0.75rem;
|
|
91
|
+
border-bottom: 1px solid var(--fv-border);
|
|
92
|
+
white-space: nowrap;
|
|
93
|
+
}
|
|
94
|
+
.fv-csv__td:hover {
|
|
95
|
+
background: color-mix(in srgb, var(--fv-muted) 50%, transparent);
|
|
96
|
+
}
|
|
97
|
+
.fv-csv__td-num {
|
|
98
|
+
color: var(--fv-muted-foreground);
|
|
99
|
+
font-size: var(--fv-font-size-xs);
|
|
100
|
+
font-family: var(--fv-font-mono);
|
|
101
|
+
}
|
|
102
|
+
.fv-csv__empty {
|
|
103
|
+
padding: 2rem 0.75rem;
|
|
104
|
+
text-align: center;
|
|
105
|
+
color: var(--fv-muted-foreground);
|
|
106
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
.fv-docx {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
height: 100%;
|
|
5
|
+
}
|
|
6
|
+
.fv-docx__info-bar {
|
|
7
|
+
padding: 0.375rem 1rem;
|
|
8
|
+
border-bottom: 1px solid var(--fv-border);
|
|
9
|
+
background: color-mix(in srgb, var(--fv-muted) 30%, transparent);
|
|
10
|
+
display: flex;
|
|
11
|
+
align-items: center;
|
|
12
|
+
justify-content: space-between;
|
|
13
|
+
}
|
|
14
|
+
.fv-docx__info-bar span {
|
|
15
|
+
font-size: var(--fv-font-size-xs);
|
|
16
|
+
color: var(--fv-muted-foreground);
|
|
17
|
+
}
|
|
18
|
+
.fv-docx__viewport {
|
|
19
|
+
flex: 1;
|
|
20
|
+
overflow: auto;
|
|
21
|
+
background: var(--fv-canvas-bg);
|
|
22
|
+
position: relative;
|
|
23
|
+
}
|
|
24
|
+
.fv-docx__overlay {
|
|
25
|
+
position: absolute;
|
|
26
|
+
inset: 0;
|
|
27
|
+
z-index: 10;
|
|
28
|
+
display: flex;
|
|
29
|
+
flex-direction: column;
|
|
30
|
+
align-items: center;
|
|
31
|
+
justify-content: center;
|
|
32
|
+
background: var(--fv-canvas-bg);
|
|
33
|
+
}
|
|
34
|
+
.fv-docx__overlay-title {
|
|
35
|
+
font-size: var(--fv-font-size-lg);
|
|
36
|
+
font-weight: 500;
|
|
37
|
+
color: var(--fv-danger);
|
|
38
|
+
}
|
|
39
|
+
.fv-docx__overlay-msg {
|
|
40
|
+
font-size: var(--fv-font-size-sm);
|
|
41
|
+
color: var(--fv-muted-foreground);
|
|
42
|
+
max-width: 28rem;
|
|
43
|
+
text-align: center;
|
|
44
|
+
margin-top: 0.5rem;
|
|
45
|
+
}
|
|
46
|
+
.fv-docx__overlay-spinner {
|
|
47
|
+
margin-bottom: 0.75rem;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* Container layout */
|
|
51
|
+
.docx-preview-container {
|
|
52
|
+
padding: 20px 0;
|
|
53
|
+
display: flex;
|
|
54
|
+
flex-direction: column;
|
|
55
|
+
align-items: center;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* Override docx-wrapper to center pages */
|
|
59
|
+
.docx-preview-container .docx-wrapper {
|
|
60
|
+
background: transparent !important;
|
|
61
|
+
padding: 0 !important;
|
|
62
|
+
display: flex;
|
|
63
|
+
flex-direction: column;
|
|
64
|
+
align-items: center;
|
|
65
|
+
gap: 20px;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* Page styling */
|
|
69
|
+
.docx-preview-container .docx-wrapper > section.docx {
|
|
70
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.08) !important;
|
|
71
|
+
margin-bottom: 0 !important;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* Dark mode adjustments */
|
|
75
|
+
@media (prefers-color-scheme: dark) {
|
|
76
|
+
.docx-preview-container .docx-wrapper > section.docx {
|
|
77
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 1px 2px rgba(0, 0, 0, 0.3) !important;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
[data-fv-theme="dark"] .docx-preview-container .docx-wrapper > section.docx {
|
|
81
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 1px 2px rgba(0, 0, 0, 0.3) !important;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* Ensure images scale within pages */
|
|
85
|
+
.docx-preview-container .docx-wrapper img {
|
|
86
|
+
max-width: 100%;
|
|
87
|
+
height: auto;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/* Fix table rendering */
|
|
91
|
+
.docx-preview-container .docx-wrapper table {
|
|
92
|
+
border-collapse: collapse;
|
|
93
|
+
}
|