@l1yp/file-viewer 0.1.4 → 0.1.6
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/README.md +57 -6
- package/dist/assets/step.worker-CfDTYOf_.js.map +1 -0
- package/dist/components/AnsiText.d.ts +47 -0
- package/dist/components/AnsiText.js +41 -0
- package/dist/components/AnsiText.js.map +1 -0
- package/dist/components/CertViewer.js +1 -1
- package/dist/components/CertViewer.js.map +1 -1
- package/dist/components/CertViewer.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/CodeView.js +1 -1
- package/dist/components/CodeView.js.map +1 -1
- package/dist/components/CodeView.vue_vue_type_script_setup_true_lang.js +80 -71
- package/dist/components/CodeView.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/DocxEmbeddedFiles.js +9 -0
- package/dist/components/DocxEmbeddedFiles.js.map +1 -0
- package/dist/components/DocxEmbeddedFiles.vue.d.ts +15 -0
- package/dist/components/DocxEmbeddedFiles.vue_vue_type_script_setup_true_lang.js +69 -0
- package/dist/components/DocxEmbeddedFiles.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/DocxNavigationPane.js +1 -1
- package/dist/components/DocxNavigationPane.js.map +1 -1
- package/dist/components/DocxNavigationPane.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/DocxViewer.js +1 -1
- package/dist/components/DocxViewer.js.map +1 -1
- package/dist/components/DocxViewer.vue.d.ts +1 -1
- package/dist/components/DocxViewer.vue_vue_type_script_setup_true_lang.js +182 -50
- package/dist/components/DocxViewer.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/EplViewer.js +1 -1
- package/dist/components/EplViewer.js.map +1 -1
- package/dist/components/EplViewer.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/FileViewerBody.js +1 -1
- package/dist/components/FileViewerBody.js.map +1 -1
- package/dist/components/FileViewerBody.vue.d.ts +1 -0
- package/dist/components/FileViewerBody.vue_vue_type_script_setup_true_lang.js +292 -281
- package/dist/components/FileViewerBody.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/FileViewerPanel.js +1 -1
- package/dist/components/FileViewerPanel.js.map +1 -1
- package/dist/components/FileViewerPanel.vue.d.ts +6 -1
- package/dist/components/FileViewerPanel.vue_vue_type_script_setup_true_lang.js +53 -51
- package/dist/components/FileViewerPanel.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/HarViewer.js +1 -1
- package/dist/components/HarViewer.js.map +1 -1
- package/dist/components/HarViewer.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/JksViewer.js +1 -1
- package/dist/components/JksViewer.js.map +1 -1
- package/dist/components/JksViewer.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/LogViewer.js +1 -1
- package/dist/components/LogViewer.js.map +1 -1
- package/dist/components/LogViewer.vue.d.ts +3 -1
- package/dist/components/LogViewer.vue_vue_type_script_setup_true_lang.js +284 -280
- package/dist/components/LogViewer.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/ModelViewModes.js +9 -0
- package/dist/components/ModelViewModes.js.map +1 -0
- package/dist/components/ModelViewModes.vue.d.ts +11 -0
- package/dist/components/ModelViewModes.vue_vue_type_script_setup_true_lang.js +49 -0
- package/dist/components/ModelViewModes.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/ModelViewer.js +1 -1
- package/dist/components/ModelViewer.js.map +1 -1
- package/dist/components/ModelViewer.vue.d.ts +2 -1
- package/dist/components/ModelViewer.vue_vue_type_script_setup_true_lang.js +183 -96
- package/dist/components/ModelViewer.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/PdfNavigationPane.js +1 -1
- package/dist/components/PdfNavigationPane.js.map +1 -1
- package/dist/components/PdfNavigationPane.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/PdfViewer.js +1 -1
- package/dist/components/PdfViewer.js.map +1 -1
- package/dist/components/PdfViewer.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/PptxNavigationPane.js +1 -1
- package/dist/components/PptxNavigationPane.js.map +1 -1
- package/dist/components/PptxNavigationPane.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/PsdViewer.js +1 -1
- package/dist/components/PsdViewer.js.map +1 -1
- package/dist/components/PsdViewer.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/SqliteViewer.js +1 -1
- package/dist/components/SqliteViewer.js.map +1 -1
- package/dist/components/SqliteViewer.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/ViewerLoadError.js +9 -0
- package/dist/components/ViewerLoadError.js.map +1 -0
- package/dist/components/ViewerLoadError.vue.d.ts +17 -0
- package/dist/components/ViewerLoadError.vue_vue_type_script_setup_true_lang.js +58 -0
- package/dist/components/ViewerLoadError.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/XlsxChart.js +1 -1
- package/dist/components/XlsxChart.js.map +1 -1
- package/dist/components/XlsxChart.vue_vue_type_script_setup_true_lang.js +9 -9
- package/dist/components/XlsxChart.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/XlsxImageLayer.js +9 -0
- package/dist/components/XlsxImageLayer.js.map +1 -0
- package/dist/components/XlsxImageLayer.vue.d.ts +9 -0
- package/dist/components/XlsxImageLayer.vue_vue_type_script_setup_true_lang.js +46 -0
- package/dist/components/XlsxImageLayer.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/XlsxViewer.js +1 -1
- package/dist/components/XlsxViewer.js.map +1 -1
- package/dist/components/XlsxViewer.vue_vue_type_script_setup_true_lang.js +230 -216
- package/dist/components/XlsxViewer.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/epl/EplResource.js +1 -1
- package/dist/components/epl/EplResource.js.map +1 -1
- package/dist/components/epl/EplResource.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/optionalViewer.d.ts +3 -2
- package/dist/components/optionalViewer.js +6 -3
- package/dist/components/optionalViewer.js.map +1 -1
- package/dist/composables/useFileViewer.d.ts +11 -3
- package/dist/composables/useFileViewer.js.map +1 -1
- package/dist/composables/useTeleportTheme.d.ts +7 -0
- package/dist/composables/useTeleportTheme.js +42 -0
- package/dist/composables/useTeleportTheme.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +29 -28
- package/dist/lib/ansi.d.ts +44 -0
- package/dist/lib/ansi.js +224 -0
- package/dist/lib/ansi.js.map +1 -0
- package/dist/lib/cfb.d.ts +37 -0
- package/dist/lib/cfb.js +112 -0
- package/dist/lib/cfb.js.map +1 -0
- package/dist/lib/docxEmbeddedDom.d.ts +22 -0
- package/dist/lib/docxEmbeddedDom.js +128 -0
- package/dist/lib/docxEmbeddedDom.js.map +1 -0
- package/dist/lib/docxEmbeddings.d.ts +41 -0
- package/dist/lib/docxEmbeddings.js +226 -0
- package/dist/lib/docxEmbeddings.js.map +1 -0
- package/dist/lib/docxTheme.d.ts +6 -0
- package/dist/lib/docxTheme.js +64 -0
- package/dist/lib/docxTheme.js.map +1 -0
- package/dist/lib/epl/code/structures.js +82 -0
- package/dist/lib/epl/code/structures.js.map +1 -0
- package/dist/lib/epl/code/variable.js +16 -0
- package/dist/lib/epl/code/variable.js.map +1 -0
- package/dist/lib/epl/eplDocument.js +28 -22
- package/dist/lib/epl/eplDocument.js.map +1 -1
- package/dist/lib/epl/index.d.ts +2 -1
- package/dist/lib/epl/index.js.map +1 -1
- package/dist/lib/epl/sections/code.js +37 -0
- package/dist/lib/epl/sections/code.js.map +1 -0
- package/dist/lib/epl/sections/esystemInfo.js +29 -0
- package/dist/lib/epl/sections/esystemInfo.js.map +1 -0
- package/dist/lib/epl/sections/losable.js +33 -0
- package/dist/lib/epl/sections/losable.js.map +1 -0
- package/dist/lib/epl/sections/projectConfig.js +39 -0
- package/dist/lib/epl/sections/projectConfig.js.map +1 -0
- package/dist/lib/epl/sections/resource.js +84 -0
- package/dist/lib/epl/sections/resource.js.map +1 -0
- package/dist/lib/fileType.d.ts +3 -1
- package/dist/lib/fileType.js +150 -137
- package/dist/lib/fileType.js.map +1 -1
- package/dist/lib/modelAppearance.d.ts +7 -0
- package/dist/lib/modelAppearance.js +41 -0
- package/dist/lib/modelAppearance.js.map +1 -0
- package/dist/lib/msi.js +62 -154
- package/dist/lib/msi.js.map +1 -1
- package/dist/lib/olePackage.d.ts +8 -0
- package/dist/lib/olePackage.js +37 -0
- package/dist/lib/olePackage.js.map +1 -0
- package/dist/lib/pptxFirstSlide.d.ts +11 -0
- package/dist/lib/pptxFirstSlide.js +34 -0
- package/dist/lib/pptxFirstSlide.js.map +1 -0
- package/dist/lib/step.d.ts +10 -0
- package/dist/lib/step.js +35 -0
- package/dist/lib/step.js.map +1 -0
- package/dist/lib/step.worker.d.ts +1 -0
- package/dist/lib/step.worker.js +18 -0
- package/dist/lib/step.worker.js.map +1 -0
- package/dist/lib/stepObject.d.ts +4 -0
- package/dist/lib/stepObject.js +52 -0
- package/dist/lib/stepObject.js.map +1 -0
- package/dist/lib/stepTypes.d.ts +60 -0
- package/dist/lib/viewerKind.js +10 -5
- package/dist/lib/viewerKind.js.map +1 -1
- package/dist/lib/xlsx.d.ts +1 -1
- package/dist/lib/xlsx.js +106 -89
- package/dist/lib/xlsx.js.map +1 -1
- package/dist/lib/xlsxCharts.js +71 -119
- package/dist/lib/xlsxCharts.js.map +1 -1
- package/dist/lib/xlsxImages.d.ts +43 -0
- package/dist/lib/xlsxImages.js +114 -0
- package/dist/lib/xlsxImages.js.map +1 -0
- package/dist/lib/xlsxParts.d.ts +17 -0
- package/dist/lib/xlsxParts.js +86 -0
- package/dist/lib/xlsxParts.js.map +1 -0
- package/dist/style.css +1 -1
- package/package.json +8 -3
|
@@ -1,45 +1,50 @@
|
|
|
1
1
|
import { fileExt as e } from "../lib/fileType.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { hasAnsiSequences as t, parseAnsi as n } from "../lib/ansi.js";
|
|
3
|
+
import { escapeHtml as ee, highlightCode as r, highlightLines as te } from "../lib/highlight.js";
|
|
4
|
+
import { computeFoldRegions as ne } from "../lib/codefold.js";
|
|
5
|
+
import { canFormat as re, formatCode as ie } from "../lib/codeformat.js";
|
|
6
|
+
import { langLabel as ae, searchLangs as oe } from "../lib/highlightLangs.js";
|
|
6
7
|
import i from "./icons/Icon.js";
|
|
7
|
-
import
|
|
8
|
+
import a from "./AnsiText.js";
|
|
9
|
+
import { Fragment as o, computed as s, createBlock as c, createCommentVNode as l, createElementBlock as u, createElementVNode as d, createVNode as f, defineComponent as p, normalizeClass as m, onBeforeUnmount as se, openBlock as h, reactive as ce, ref as g, renderList as _, toDisplayString as v, unref as y, vModelText as le, watch as b, withDirectives as ue } from "vue";
|
|
8
10
|
//#region src/components/CodeView.vue?vue&type=script&setup=true&lang.ts
|
|
9
|
-
var
|
|
11
|
+
var de = { class: "cv" }, fe = { class: "cv__tools" }, pe = ["aria-expanded"], me = {
|
|
10
12
|
key: 0,
|
|
11
13
|
class: "cv__langpop",
|
|
12
14
|
role: "menu"
|
|
13
|
-
},
|
|
15
|
+
}, he = { class: "cv__langlist" }, ge = ["aria-checked"], _e = ["aria-checked", "onClick"], ve = { class: "cv__langitem-label" }, ye = {
|
|
14
16
|
key: 1,
|
|
15
17
|
class: "cv__langempty"
|
|
16
|
-
},
|
|
18
|
+
}, be = ["disabled", "title"], xe = {
|
|
17
19
|
key: 0,
|
|
18
20
|
class: "cv__scroll cv__scroll--blob"
|
|
19
|
-
},
|
|
21
|
+
}, Se = { class: "cv__codewrap" }, Ce = {
|
|
20
22
|
class: "cv__gutter",
|
|
21
23
|
"aria-hidden": "true"
|
|
22
|
-
},
|
|
24
|
+
}, x = { class: "cv__codecol" }, S = { class: "cv__pre" }, C = {
|
|
25
|
+
key: 0,
|
|
26
|
+
class: "hljs"
|
|
27
|
+
}, w = ["innerHTML"], T = {
|
|
23
28
|
key: 1,
|
|
24
29
|
class: "cv__scroll"
|
|
25
30
|
}, E = { class: "cv__rows" }, D = { class: "cv__gut" }, O = ["title", "onClick"], k = {
|
|
26
31
|
key: 1,
|
|
27
32
|
class: "cv__fold cv__fold--empty"
|
|
28
|
-
}, A = { class: "cv__ln" },
|
|
33
|
+
}, A = { class: "cv__ln" }, we = { class: "cv__code hljs" }, Te = ["innerHTML"], Ee = ["title", "onClick"], De = 4e3, j = /*@__PURE__*/ p({
|
|
29
34
|
__name: "CodeView",
|
|
30
35
|
props: {
|
|
31
36
|
code: {},
|
|
32
37
|
lang: {},
|
|
33
38
|
name: {}
|
|
34
39
|
},
|
|
35
|
-
setup(
|
|
36
|
-
let
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}),
|
|
40
|
-
let G = g(!1), K = g(null), q = g(""), J =
|
|
40
|
+
setup(p) {
|
|
41
|
+
let j = p, M = g(null), N = s(() => M.value ?? j.lang), P = g(null), F = g(!1), I = g(!1), L = s(() => P.value ?? j.code), R = s(() => e(j.name ?? "")), z = s(() => !N.value && t(L.value) ? n(L.value) : null), B = s(() => z.value !== null), V = s(() => z.value?.text ?? L.value), Oe = s(() => !B.value && re(R.value, N.value)), ke = s(() => V.value.split("\n")), H = s(() => ke.value.length), Ae = s(() => H.value <= De), je = s(() => B.value ? [] : te(L.value, N.value)), U = s(() => ne(V.value)), W = ce(/* @__PURE__ */ new Set());
|
|
42
|
+
b(() => [j.code, j.lang], () => {
|
|
43
|
+
P.value = null, I.value = !1, M.value = null;
|
|
44
|
+
}), b(L, () => W.clear());
|
|
45
|
+
let G = g(!1), K = g(null), q = g(""), J = s(() => oe(q.value));
|
|
41
46
|
function Y(e) {
|
|
42
|
-
|
|
47
|
+
M.value = e, G.value = !1, q.value = "";
|
|
43
48
|
}
|
|
44
49
|
function X(e) {
|
|
45
50
|
K.value && !K.value.contains(e.target) && (G.value = !1);
|
|
@@ -47,32 +52,32 @@ var le = { class: "cv" }, ue = { class: "cv__tools" }, de = ["aria-expanded"], f
|
|
|
47
52
|
function Z(e) {
|
|
48
53
|
e.key === "Escape" && (G.value = !1);
|
|
49
54
|
}
|
|
50
|
-
|
|
55
|
+
b(G, (e) => {
|
|
51
56
|
typeof document > "u" || (e ? (document.addEventListener("click", X), document.addEventListener("keydown", Z)) : (document.removeEventListener("click", X), document.removeEventListener("keydown", Z)));
|
|
52
|
-
}),
|
|
57
|
+
}), se(() => {
|
|
53
58
|
typeof document > "u" || (document.removeEventListener("click", X), document.removeEventListener("keydown", Z));
|
|
54
59
|
});
|
|
55
60
|
let Q;
|
|
56
|
-
async function
|
|
57
|
-
if (
|
|
58
|
-
|
|
61
|
+
async function Me() {
|
|
62
|
+
if (P.value != null) {
|
|
63
|
+
P.value = null;
|
|
59
64
|
return;
|
|
60
65
|
}
|
|
61
|
-
if (!
|
|
62
|
-
|
|
66
|
+
if (!F.value) {
|
|
67
|
+
F.value = !0, I.value = !1;
|
|
63
68
|
try {
|
|
64
|
-
|
|
65
|
-
ext:
|
|
66
|
-
lang:
|
|
69
|
+
P.value = await ie(j.code, {
|
|
70
|
+
ext: R.value,
|
|
71
|
+
lang: N.value
|
|
67
72
|
});
|
|
68
73
|
} catch {
|
|
69
|
-
|
|
74
|
+
I.value = !0, clearTimeout(Q), Q = setTimeout(() => I.value = !1, 2200);
|
|
70
75
|
} finally {
|
|
71
|
-
|
|
76
|
+
F.value = !1;
|
|
72
77
|
}
|
|
73
78
|
}
|
|
74
79
|
}
|
|
75
|
-
let
|
|
80
|
+
let Ne = s(() => {
|
|
76
81
|
let e = [], t = H.value, n = 0;
|
|
77
82
|
for (; n < t;) {
|
|
78
83
|
e.push(n);
|
|
@@ -84,99 +89,103 @@ var le = { class: "cv" }, ue = { class: "cv__tools" }, de = ["aria-expanded"], f
|
|
|
84
89
|
function $(e) {
|
|
85
90
|
W.has(e) ? W.delete(e) : W.add(e);
|
|
86
91
|
}
|
|
87
|
-
let
|
|
88
|
-
return (e, t) => (h(),
|
|
92
|
+
let Pe = s(() => N.value ? r(L.value, N.value) : ee(L.value)), Fe = s(() => Array.from({ length: H.value }, (e, t) => t + 1).join("\n"));
|
|
93
|
+
return (e, t) => (h(), u("div", de, [d("div", fe, [d("div", {
|
|
89
94
|
ref_key: "langMenuRef",
|
|
90
95
|
ref: K,
|
|
91
96
|
class: "cv__lang"
|
|
92
|
-
}, [
|
|
97
|
+
}, [d("button", {
|
|
93
98
|
type: "button",
|
|
94
|
-
class:
|
|
99
|
+
class: m(["cv__toolbtn", { "cv__toolbtn--on": G.value }]),
|
|
95
100
|
title: "高亮语言 —— 选择用哪种语言着色(自动识别不准时手动指定)",
|
|
96
101
|
"aria-haspopup": !0,
|
|
97
102
|
"aria-expanded": G.value,
|
|
98
103
|
onClick: t[0] ||= (e) => G.value = !G.value
|
|
99
|
-
}, [
|
|
104
|
+
}, [f(i, {
|
|
100
105
|
name: "code",
|
|
101
106
|
size: 12
|
|
102
|
-
}),
|
|
107
|
+
}), d("span", null, v(y(ae)(N.value)), 1)], 10, pe), G.value ? (h(), u("div", me, [ue(d("input", {
|
|
103
108
|
"onUpdate:modelValue": t[1] ||= (e) => q.value = e,
|
|
104
109
|
class: "cv__langsearch",
|
|
105
110
|
type: "text",
|
|
106
111
|
placeholder: "搜索语言…",
|
|
107
112
|
spellcheck: "false",
|
|
108
113
|
autocomplete: "off"
|
|
109
|
-
}, null, 512), [[
|
|
110
|
-
q.value ?
|
|
114
|
+
}, null, 512), [[le, q.value]]), d("div", he, [
|
|
115
|
+
q.value ? l("", !0) : (h(), u("button", {
|
|
111
116
|
key: 0,
|
|
112
117
|
type: "button",
|
|
113
|
-
class:
|
|
118
|
+
class: m(["cv__langitem", { "cv__langitem--on": N.value === "" }]),
|
|
114
119
|
role: "menuitemradio",
|
|
115
|
-
"aria-checked":
|
|
120
|
+
"aria-checked": N.value === "",
|
|
116
121
|
onClick: t[2] ||= (e) => Y("")
|
|
117
|
-
}, [t[3] ||=
|
|
122
|
+
}, [t[3] ||= d("span", { class: "cv__langitem-label" }, "纯文本(无高亮)", -1), N.value === "" ? (h(), c(i, {
|
|
118
123
|
key: 0,
|
|
119
124
|
name: "check",
|
|
120
125
|
size: 14,
|
|
121
126
|
class: "cv__langitem-check"
|
|
122
|
-
})) :
|
|
123
|
-
(h(!0),
|
|
127
|
+
})) : l("", !0)], 10, ge)),
|
|
128
|
+
(h(!0), u(o, null, _(J.value, (e) => (h(), u("button", {
|
|
124
129
|
key: e.id,
|
|
125
130
|
type: "button",
|
|
126
|
-
class:
|
|
131
|
+
class: m(["cv__langitem", { "cv__langitem--on": N.value === e.id }]),
|
|
127
132
|
role: "menuitemradio",
|
|
128
|
-
"aria-checked":
|
|
133
|
+
"aria-checked": N.value === e.id,
|
|
129
134
|
onClick: (t) => Y(e.id)
|
|
130
|
-
}, [
|
|
135
|
+
}, [d("span", ve, v(e.label), 1), N.value === e.id ? (h(), c(i, {
|
|
131
136
|
key: 0,
|
|
132
137
|
name: "check",
|
|
133
138
|
size: 14,
|
|
134
139
|
class: "cv__langitem-check"
|
|
135
|
-
})) :
|
|
136
|
-
q.value && !J.value.length ? (h(),
|
|
137
|
-
])])) :
|
|
140
|
+
})) : l("", !0)], 10, _e))), 128)),
|
|
141
|
+
q.value && !J.value.length ? (h(), u("p", ye, "无匹配语言")) : l("", !0)
|
|
142
|
+
])])) : l("", !0)], 512), Oe.value ? (h(), u("button", {
|
|
138
143
|
key: 0,
|
|
139
144
|
type: "button",
|
|
140
|
-
class:
|
|
141
|
-
"cv__toolbtn--on":
|
|
142
|
-
"cv__fmt--err":
|
|
145
|
+
class: m(["cv__toolbtn cv__fmt", {
|
|
146
|
+
"cv__toolbtn--on": P.value != null,
|
|
147
|
+
"cv__fmt--err": I.value
|
|
143
148
|
}]),
|
|
144
|
-
disabled:
|
|
145
|
-
title:
|
|
146
|
-
onClick:
|
|
147
|
-
}, v(
|
|
149
|
+
disabled: F.value,
|
|
150
|
+
title: I.value ? "格式化失败:源码可能无法解析" : P.value == null ? "用 Prettier 格式化" : "还原为原始格式",
|
|
151
|
+
onClick: Me
|
|
152
|
+
}, v(I.value ? "格式化失败" : F.value ? "格式化中…" : P.value == null ? "格式化" : "还原"), 11, be)) : l("", !0)]), Ae.value ? (h(), u("div", T, [d("div", E, [(h(!0), u(o, null, _(Ne.value, (e) => (h(), u("div", {
|
|
148
153
|
key: e,
|
|
149
154
|
class: "cv__row"
|
|
150
155
|
}, [
|
|
151
|
-
|
|
156
|
+
d("span", D, [U.value.has(e) ? (h(), u("button", {
|
|
152
157
|
key: 0,
|
|
153
158
|
type: "button",
|
|
154
159
|
class: "cv__fold",
|
|
155
160
|
title: W.has(e) ? "展开" : "折叠",
|
|
156
161
|
onClick: (t) => $(e)
|
|
157
|
-
}, [
|
|
162
|
+
}, [f(i, {
|
|
158
163
|
name: "chevronRight",
|
|
159
164
|
size: 12,
|
|
160
|
-
class:
|
|
161
|
-
}, null, 8, ["class"])], 8, O)) : (h(),
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}, null, 8,
|
|
166
|
-
|
|
165
|
+
class: m({ "cv__fold--open": !W.has(e) })
|
|
166
|
+
}, null, 8, ["class"])], 8, O)) : (h(), u("span", k)), d("span", A, v(e + 1), 1)]),
|
|
167
|
+
d("code", we, [z.value ? (h(), c(y(a), {
|
|
168
|
+
key: 0,
|
|
169
|
+
line: z.value.lines[e] ?? ""
|
|
170
|
+
}, null, 8, ["line"])) : (h(), u("span", {
|
|
171
|
+
key: 1,
|
|
172
|
+
innerHTML: je.value[e]
|
|
173
|
+
}, null, 8, Te))]),
|
|
174
|
+
W.has(e) ? (h(), u("button", {
|
|
167
175
|
key: 0,
|
|
168
176
|
type: "button",
|
|
169
177
|
class: "cv__ellipsis",
|
|
170
178
|
title: `展开折叠的 ${(U.value.get(e) ?? e) - e} 行`,
|
|
171
179
|
onClick: (t) => $(e)
|
|
172
|
-
}, " ⋯ ", 8,
|
|
173
|
-
]))), 128))])])) : (h(),
|
|
180
|
+
}, " ⋯ ", 8, Ee)) : l("", !0)
|
|
181
|
+
]))), 128))])])) : (h(), u("div", xe, [d("div", Se, [d("pre", Ce, v(Fe.value), 1), d("div", x, [d("pre", S, [z.value ? (h(), u("code", C, [f(y(a), { lines: z.value.lines }, null, 8, ["lines"])])) : (h(), u("code", {
|
|
182
|
+
key: 1,
|
|
174
183
|
class: "hljs",
|
|
175
|
-
innerHTML:
|
|
176
|
-
}, null, 8, w)])])])]))]));
|
|
184
|
+
innerHTML: Pe.value
|
|
185
|
+
}, null, 8, w))])])])]))]));
|
|
177
186
|
}
|
|
178
187
|
});
|
|
179
188
|
//#endregion
|
|
180
|
-
export {
|
|
189
|
+
export { j as default };
|
|
181
190
|
|
|
182
191
|
//# sourceMappingURL=CodeView.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodeView.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../src/components/CodeView.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, reactive, ref, watch } from 'vue'\nimport { escapeHtml, highlightCode, highlightLines } from '@/lib/highlight'\nimport { computeFoldRegions } from '@/lib/codefold'\nimport { canFormat, formatCode } from '@/lib/codeformat'\nimport { fileExt } from '@/lib/fileType'\nimport { langLabel, searchLangs } from '@/lib/highlightLangs'\nimport Icon from '@/components/icons/Icon.vue'\n\n/**\n * The side viewer's source-code view: a line-number gutter + syntax-highlighted code, with indentation-based\n * code FOLDING (click a chevron to collapse a block; see lib/codefold.ts), on-demand Prettier FORMATTING (the\n * 格式化 button, shown only for languages Prettier can parse — see lib/codeformat.ts; loaded lazily), and a\n * manual HIGHLIGHT-LANGUAGE picker (the 语言 button — auto-detection by extension/mime is often empty or wrong,\n * so any file can be re-colorized as JSON / XML / Python / … or forced to plain text; see lib/highlightLangs).\n * Used for every non-rendered file (plain text, code, or markdown/html/svg viewed as source). Highlighting is\n * split per line (see highlightLines) so rows can be hidden individually.\n *\n * Very large files (> {@link MAX_FOLD_LINES}) skip the per-line DOM and fall back to a single highlighted block\n * — folding a 10k-line file isn't worth tens of thousands of row elements, and such files mostly reach the\n * streaming log viewer anyway (see isLogFile).\n */\nconst props = defineProps<{ code: string; lang: string; name?: string }>()\n\nconst MAX_FOLD_LINES = 4000\n\n// Manual highlight-language override (null = use the auto-detected `props.lang`; '' = forced plain text). The\n// effective language feeds highlighting AND the 格式化 button (so \"force JSON, then format\" works). Reset when a\n// different file / detected language arrives (see the reset watch below).\nconst langOverride = ref<string | null>(null)\nconst effLang = computed(() => langOverride.value ?? props.lang)\n\n// Formatted output (null = showing the original). The view always renders `displayCode`.\nconst formatted = ref<string | null>(null)\nconst formatting = ref(false)\nconst formatErr = ref(false)\nconst displayCode = computed(() => formatted.value ?? props.code)\n\nconst ext = computed(() => fileExt(props.name ?? ''))\nconst canFmt = computed(() => canFormat(ext.value, effLang.value))\n\nconst rawLines = computed(() => displayCode.value.split('\\n'))\nconst lineCount = computed(() => rawLines.value.length)\nconst foldable = computed(() => lineCount.value <= MAX_FOLD_LINES)\n\nconst lineHtml = computed(() => highlightLines(displayCode.value, effLang.value))\nconst regions = computed(() => computeFoldRegions(displayCode.value))\nconst folded = reactive(new Set<number>())\n\n// A new file (or a re-detected language) resets the formatting toggle AND the manual language override; any\n// change to the shown code clears stale fold state.\nwatch(\n () => [props.code, props.lang],\n () => {\n formatted.value = null\n formatErr.value = false\n langOverride.value = null\n },\n)\nwatch(displayCode, () => folded.clear())\n\n// ── highlight-language picker ────────────────────────────────────────────────────────────────────\nconst langMenuOpen = ref(false)\nconst langMenuRef = ref<HTMLElement | null>(null)\nconst langQuery = ref('')\nconst langResults = computed(() => searchLangs(langQuery.value))\n\nfunction chooseLang(id: string): void {\n langOverride.value = id\n langMenuOpen.value = false\n langQuery.value = ''\n}\n\n// Close the menu on an outside click or Esc — listeners live only while it's open (SSR-guarded). The toggle\n// button + popup both sit inside langMenuRef, so a click on either is \"inside\" and never self-closes.\nfunction onLangDocPointer(e: MouseEvent): void {\n if (langMenuRef.value && !langMenuRef.value.contains(e.target as Node)) langMenuOpen.value = false\n}\nfunction onLangKey(e: KeyboardEvent): void {\n if (e.key === 'Escape') langMenuOpen.value = false\n}\nwatch(langMenuOpen, (on) => {\n if (typeof document === 'undefined') return\n if (on) {\n document.addEventListener('click', onLangDocPointer)\n document.addEventListener('keydown', onLangKey)\n } else {\n document.removeEventListener('click', onLangDocPointer)\n document.removeEventListener('keydown', onLangKey)\n }\n})\nonBeforeUnmount(() => {\n if (typeof document === 'undefined') return\n document.removeEventListener('click', onLangDocPointer)\n document.removeEventListener('keydown', onLangKey)\n})\n\nlet errTimer: ReturnType<typeof setTimeout> | undefined\nasync function toggleFormat(): Promise<void> {\n if (formatted.value != null) {\n formatted.value = null // revert to the original\n return\n }\n if (formatting.value) return\n formatting.value = true\n formatErr.value = false\n try {\n formatted.value = await formatCode(props.code, { ext: ext.value, lang: effLang.value })\n } catch {\n formatErr.value = true\n clearTimeout(errTimer)\n errTimer = setTimeout(() => (formatErr.value = false), 2200)\n } finally {\n formatting.value = false\n }\n}\n\n// Visible line indices, skipping the bodies of folded regions (and any nested folds within them).\nconst visible = computed(() => {\n const out: number[] = []\n const n = lineCount.value\n let i = 0\n while (i < n) {\n out.push(i)\n const end = folded.has(i) ? regions.value.get(i) : undefined\n i = end != null ? end + 1 : i + 1\n }\n return out\n})\n\nfunction toggle(i: number): void {\n if (folded.has(i)) folded.delete(i)\n else folded.add(i)\n}\n\n// Blob fallback for huge files: one highlighted block + a newline-joined gutter.\nconst blobHtml = computed(() =>\n effLang.value ? highlightCode(displayCode.value, effLang.value) : escapeHtml(displayCode.value),\n)\nconst blobGutter = computed(() =>\n Array.from({ length: lineCount.value }, (_, i) => i + 1).join('\\n'),\n)\n</script>\n\n<template>\n <div class=\"cv\">\n <!-- floating tools, top-right over the code: highlight-language picker + Prettier format toggle -->\n <div class=\"cv__tools\">\n <!-- highlight-language picker: force which grammar colorizes the source (auto-detect is often empty/wrong) -->\n <div ref=\"langMenuRef\" class=\"cv__lang\">\n <button\n type=\"button\"\n class=\"cv__toolbtn\"\n :class=\"{ 'cv__toolbtn--on': langMenuOpen }\"\n title=\"高亮语言 —— 选择用哪种语言着色(自动识别不准时手动指定)\"\n :aria-haspopup=\"true\"\n :aria-expanded=\"langMenuOpen\"\n @click=\"langMenuOpen = !langMenuOpen\"\n >\n <Icon name=\"code\" :size=\"12\" /><span>{{ langLabel(effLang) }}</span>\n </button>\n <div v-if=\"langMenuOpen\" class=\"cv__langpop\" role=\"menu\">\n <input\n v-model=\"langQuery\"\n class=\"cv__langsearch\"\n type=\"text\"\n placeholder=\"搜索语言…\"\n spellcheck=\"false\"\n autocomplete=\"off\"\n />\n <div class=\"cv__langlist\">\n <button\n v-if=\"!langQuery\"\n type=\"button\"\n class=\"cv__langitem\"\n :class=\"{ 'cv__langitem--on': effLang === '' }\"\n role=\"menuitemradio\"\n :aria-checked=\"effLang === ''\"\n @click=\"chooseLang('')\"\n >\n <span class=\"cv__langitem-label\">纯文本(无高亮)</span>\n <Icon v-if=\"effLang === ''\" name=\"check\" :size=\"14\" class=\"cv__langitem-check\" />\n </button>\n <button\n v-for=\"l in langResults\"\n :key=\"l.id\"\n type=\"button\"\n class=\"cv__langitem\"\n :class=\"{ 'cv__langitem--on': effLang === l.id }\"\n role=\"menuitemradio\"\n :aria-checked=\"effLang === l.id\"\n @click=\"chooseLang(l.id)\"\n >\n <span class=\"cv__langitem-label\">{{ l.label }}</span>\n <Icon v-if=\"effLang === l.id\" name=\"check\" :size=\"14\" class=\"cv__langitem-check\" />\n </button>\n <p v-if=\"langQuery && !langResults.length\" class=\"cv__langempty\">无匹配语言</p>\n </div>\n </div>\n </div>\n\n <!-- format toggle (only for languages Prettier can parse) -->\n <button\n v-if=\"canFmt\"\n type=\"button\"\n class=\"cv__toolbtn cv__fmt\"\n :class=\"{ 'cv__toolbtn--on': formatted != null, 'cv__fmt--err': formatErr }\"\n :disabled=\"formatting\"\n :title=\"\n formatErr\n ? '格式化失败:源码可能无法解析'\n : formatted != null\n ? '还原为原始格式'\n : '用 Prettier 格式化'\n \"\n @click=\"toggleFormat\"\n >\n {{\n formatErr\n ? '格式化失败'\n : formatting\n ? '格式化中…'\n : formatted != null\n ? '还原'\n : '格式化'\n }}\n </button>\n </div>\n\n <!-- huge file: single highlighted block (no folding) -->\n <div v-if=\"!foldable\" class=\"cv__scroll cv__scroll--blob\">\n <div class=\"cv__codewrap\">\n <pre class=\"cv__gutter\" aria-hidden=\"true\">{{ blobGutter }}</pre>\n <div class=\"cv__codecol\">\n <pre class=\"cv__pre\"><code class=\"hljs\" v-html=\"blobHtml\" /></pre>\n </div>\n </div>\n </div>\n\n <!-- foldable: one row per visible line, with a fold chevron on block headers -->\n <div v-else class=\"cv__scroll\">\n <div class=\"cv__rows\">\n <div v-for=\"i in visible\" :key=\"i\" class=\"cv__row\">\n <span class=\"cv__gut\">\n <button\n v-if=\"regions.has(i)\"\n type=\"button\"\n class=\"cv__fold\"\n :title=\"folded.has(i) ? '展开' : '折叠'\"\n @click=\"toggle(i)\"\n >\n <Icon name=\"chevronRight\" :size=\"12\" :class=\"{ 'cv__fold--open': !folded.has(i) }\" />\n </button>\n <span v-else class=\"cv__fold cv__fold--empty\" />\n <span class=\"cv__ln\">{{ i + 1 }}</span>\n </span>\n <code class=\"cv__code hljs\" v-html=\"lineHtml[i]\" />\n <button\n v-if=\"folded.has(i)\"\n type=\"button\"\n class=\"cv__ellipsis\"\n :title=\"`展开折叠的 ${(regions.get(i) ?? i) - i} 行`\"\n @click=\"toggle(i)\"\n >\n ⋯\n </button>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n.cv {\n position: relative;\n flex: 1 1 auto;\n min-height: 0;\n display: flex;\n flex-direction: column;\n}\n\n/* Floating tools bar — top-right, above the code (highlight-language picker + format toggle). */\n.cv__tools {\n position: absolute;\n top: 8px;\n right: 14px;\n z-index: 3;\n display: flex;\n align-items: flex-start;\n gap: 6px;\n}\n\n/* Shared small pill used by both floating tools. */\n.cv__toolbtn {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n max-width: 190px;\n padding: 3px 10px;\n font-family: inherit;\n font-size: 11.5px;\n color: var(--muted);\n background: var(--surface);\n border: 1px solid var(--border-2);\n border-radius: 7px;\n cursor: pointer;\n box-shadow: var(--shadow);\n transition:\n background 0.15s,\n color 0.15s,\n border-color 0.15s;\n}\n.cv__toolbtn:hover {\n border-color: var(--accent);\n color: var(--accent);\n}\n.cv__toolbtn span {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.cv__toolbtn--on {\n color: #fff;\n background: var(--accent);\n border-color: var(--accent);\n}\n.cv__toolbtn--on:hover {\n color: #fff;\n}\n\n/* Format toggle specifics (disabled + error states). */\n.cv__fmt:disabled {\n cursor: default;\n opacity: 0.7;\n}\n.cv__fmt--err {\n color: var(--danger);\n border-color: var(--danger);\n}\n\n/* Highlight-language picker dropdown (anchored under its pill, right-aligned). */\n.cv__lang {\n position: relative;\n display: inline-flex;\n}\n.cv__langpop {\n position: absolute;\n top: calc(100% + 6px);\n right: 0;\n z-index: 4;\n width: 224px;\n padding: 7px;\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: 10px;\n box-shadow: var(--shadow);\n}\n.cv__langsearch {\n width: 100%;\n box-sizing: border-box;\n padding: 6px 9px;\n font-family: inherit;\n font-size: 12px;\n color: var(--text);\n background: var(--surface-2);\n border: 1px solid var(--border);\n border-radius: 7px;\n outline: none;\n}\n.cv__langsearch:focus {\n border-color: var(--accent);\n}\n.cv__langlist {\n max-height: 288px;\n overflow-y: auto;\n overscroll-behavior: contain;\n margin-top: 6px;\n}\n.cv__langitem {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n padding: 6px 8px;\n background: transparent;\n border: none;\n border-radius: 6px;\n color: var(--text);\n font-family: inherit;\n font-size: 12.5px;\n text-align: left;\n cursor: pointer;\n transition:\n background 0.12s,\n color 0.12s;\n}\n.cv__langitem:hover {\n background: var(--surface-2);\n color: var(--accent);\n}\n.cv__langitem--on {\n color: var(--accent);\n}\n.cv__langitem-label {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.cv__langitem-check {\n flex-shrink: 0;\n color: var(--accent);\n}\n.cv__langempty {\n margin: 0;\n padding: 10px 8px;\n font-size: 12px;\n color: var(--faint);\n text-align: center;\n}\n\n.cv__scroll {\n flex: 1 1 auto;\n min-height: 0;\n overflow: auto;\n overscroll-behavior: contain;\n background: var(--code-bg);\n}\n\n/* Foldable per-line view -------------------------------------------------------------------------- */\n.cv__rows {\n min-width: max-content;\n padding: 14px 0;\n font-family: var(--font-mono);\n font-size: var(--fv-code-fs, 12.5px);\n line-height: var(--fv-code-lh, 21px);\n}\n.cv__row {\n display: flex;\n align-items: flex-start;\n}\n/* Gutter (fold chevron + line number) sticks to the left so it stays put while long lines scroll. */\n.cv__gut {\n position: sticky;\n left: 0;\n z-index: 1;\n flex-shrink: 0;\n display: flex;\n align-items: flex-start;\n background: var(--code-bg);\n user-select: none;\n}\n.cv__fold {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 16px;\n height: var(--fv-code-lh, 21px);\n padding: 0;\n border: none;\n background: transparent;\n color: var(--faint);\n cursor: pointer;\n}\n.cv__fold--empty {\n cursor: default;\n}\n.cv__fold :deep(svg) {\n transition: transform 0.12s;\n}\n.cv__fold--open {\n transform: rotate(90deg);\n}\n.cv__fold:hover :deep(svg) {\n color: var(--accent);\n}\n.cv__ln {\n flex-shrink: 0;\n width: 48px;\n padding: 0 12px 0 4px;\n text-align: right;\n color: var(--faint);\n}\n.cv__code {\n flex: 1 1 auto;\n padding: 0 18px 0 14px;\n white-space: pre;\n color: var(--text);\n background: transparent;\n border: none;\n font-family: inherit;\n tab-size: 2;\n}\n.cv__ellipsis {\n align-self: center;\n margin: 0 0 0 2px;\n padding: 0 7px;\n font-family: inherit;\n line-height: 1.3;\n color: var(--muted);\n background: var(--surface-2);\n border: 1px solid var(--border-2);\n border-radius: 5px;\n cursor: pointer;\n}\n.cv__ellipsis:hover {\n border-color: var(--accent);\n color: var(--accent);\n}\n\n/* Huge-file blob fallback (mirrors the panel's original source layout) ----------------------------- */\n.cv__scroll--blob {\n overflow-x: hidden;\n overflow-y: auto;\n}\n.cv__codewrap {\n display: flex;\n align-items: stretch;\n min-height: 100%;\n padding: 14px 0;\n}\n.cv__gutter {\n flex-shrink: 0;\n margin: 0;\n padding: 0 12px 0 16px;\n border-right: 1px solid var(--code-border);\n text-align: right;\n font-family: var(--font-mono);\n font-size: var(--fv-code-fs, 12.5px);\n line-height: var(--fv-code-lh, 21px);\n color: var(--faint);\n user-select: none;\n white-space: pre;\n}\n.cv__codecol {\n flex: 1 1 auto;\n min-width: 0;\n overflow-x: auto;\n}\n.cv__pre {\n margin: 0;\n padding: 0 18px 0 14px;\n font-family: var(--font-mono);\n font-size: var(--fv-code-fs, 12.5px);\n line-height: var(--fv-code-lh, 21px);\n color: var(--text);\n white-space: pre;\n tab-size: 2;\n}\n.cv__pre code {\n font-family: inherit;\n background: transparent;\n border: none;\n padding: 0;\n}\n</style>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CodeView.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../src/components/CodeView.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, reactive, ref, watch } from 'vue'\nimport { escapeHtml, highlightCode, highlightLines } from '@/lib/highlight'\nimport { computeFoldRegions } from '@/lib/codefold'\nimport { canFormat, formatCode } from '@/lib/codeformat'\nimport { fileExt } from '@/lib/fileType'\nimport { hasAnsiSequences, parseAnsi } from '@/lib/ansi'\nimport { langLabel, searchLangs } from '@/lib/highlightLangs'\nimport Icon from '@/components/icons/Icon.vue'\nimport AnsiText from '@/components/AnsiText'\n\n/**\n * The side viewer's source-code view: a line-number gutter + syntax-highlighted code, with indentation-based\n * code FOLDING (click a chevron to collapse a block; see lib/codefold.ts), on-demand Prettier FORMATTING (the\n * 格式化 button, shown only for languages Prettier can parse — see lib/codeformat.ts; loaded lazily), and a\n * manual HIGHLIGHT-LANGUAGE picker (the 语言 button — auto-detection by extension/mime is often empty or wrong,\n * so any file can be re-colorized as JSON / XML / Python / … or forced to plain text; see lib/highlightLangs).\n * Used for every non-rendered file (plain text, code, or markdown/html/svg viewed as source). Highlighting is\n * split per line (see highlightLines) so rows can be hidden individually.\n *\n * Very large files (> {@link MAX_FOLD_LINES}) skip the per-line DOM and fall back to a single highlighted block\n * — folding a 10k-line file isn't worth tens of thousands of row elements, and such files mostly reach the\n * streaming log viewer anyway (see isLogFile).\n */\nconst props = defineProps<{ code: string; lang: string; name?: string }>()\n\nconst MAX_FOLD_LINES = 4000\n\n// Manual highlight-language override (null = use the auto-detected `props.lang`; '' = forced plain text). The\n// effective language feeds highlighting AND the 格式化 button (so \"force JSON, then format\" works). Reset when a\n// different file / detected language arrives (see the reset watch below).\nconst langOverride = ref<string | null>(null)\nconst effLang = computed(() => langOverride.value ?? props.lang)\n\n// Formatted output (null = showing the original). The view always renders `displayCode`.\nconst formatted = ref<string | null>(null)\nconst formatting = ref(false)\nconst formatErr = ref(false)\nconst displayCode = computed(() => formatted.value ?? props.code)\n\nconst ext = computed(() => fileExt(props.name ?? ''))\n// ANSI presentation is meaningful only in plain-text mode. Selecting a syntax language deliberately returns to\n// highlight.js; forcing \"纯文本\" on an otherwise-highlighted file enables ANSI restoration when controls exist.\nconst ansiDocument = computed(() =>\n !effLang.value && hasAnsiSequences(displayCode.value) ? parseAnsi(displayCode.value) : null,\n)\nconst ansiMode = computed(() => ansiDocument.value !== null)\nconst plainDisplayCode = computed(() => ansiDocument.value?.text ?? displayCode.value)\nconst canFmt = computed(() => !ansiMode.value && canFormat(ext.value, effLang.value))\n\nconst rawLines = computed(() => plainDisplayCode.value.split('\\n'))\nconst lineCount = computed(() => rawLines.value.length)\nconst foldable = computed(() => lineCount.value <= MAX_FOLD_LINES)\n\nconst lineHtml = computed(() =>\n ansiMode.value ? [] : highlightLines(displayCode.value, effLang.value),\n)\nconst regions = computed(() => computeFoldRegions(plainDisplayCode.value))\nconst folded = reactive(new Set<number>())\n\n// A new file (or a re-detected language) resets the formatting toggle AND the manual language override; any\n// change to the shown code clears stale fold state.\nwatch(\n () => [props.code, props.lang],\n () => {\n formatted.value = null\n formatErr.value = false\n langOverride.value = null\n },\n)\nwatch(displayCode, () => folded.clear())\n\n// ── highlight-language picker ────────────────────────────────────────────────────────────────────\nconst langMenuOpen = ref(false)\nconst langMenuRef = ref<HTMLElement | null>(null)\nconst langQuery = ref('')\nconst langResults = computed(() => searchLangs(langQuery.value))\n\nfunction chooseLang(id: string): void {\n langOverride.value = id\n langMenuOpen.value = false\n langQuery.value = ''\n}\n\n// Close the menu on an outside click or Esc — listeners live only while it's open (SSR-guarded). The toggle\n// button + popup both sit inside langMenuRef, so a click on either is \"inside\" and never self-closes.\nfunction onLangDocPointer(e: MouseEvent): void {\n if (langMenuRef.value && !langMenuRef.value.contains(e.target as Node)) langMenuOpen.value = false\n}\nfunction onLangKey(e: KeyboardEvent): void {\n if (e.key === 'Escape') langMenuOpen.value = false\n}\nwatch(langMenuOpen, (on) => {\n if (typeof document === 'undefined') return\n if (on) {\n document.addEventListener('click', onLangDocPointer)\n document.addEventListener('keydown', onLangKey)\n } else {\n document.removeEventListener('click', onLangDocPointer)\n document.removeEventListener('keydown', onLangKey)\n }\n})\nonBeforeUnmount(() => {\n if (typeof document === 'undefined') return\n document.removeEventListener('click', onLangDocPointer)\n document.removeEventListener('keydown', onLangKey)\n})\n\nlet errTimer: ReturnType<typeof setTimeout> | undefined\nasync function toggleFormat(): Promise<void> {\n if (formatted.value != null) {\n formatted.value = null // revert to the original\n return\n }\n if (formatting.value) return\n formatting.value = true\n formatErr.value = false\n try {\n formatted.value = await formatCode(props.code, { ext: ext.value, lang: effLang.value })\n } catch {\n formatErr.value = true\n clearTimeout(errTimer)\n errTimer = setTimeout(() => (formatErr.value = false), 2200)\n } finally {\n formatting.value = false\n }\n}\n\n// Visible line indices, skipping the bodies of folded regions (and any nested folds within them).\nconst visible = computed(() => {\n const out: number[] = []\n const n = lineCount.value\n let i = 0\n while (i < n) {\n out.push(i)\n const end = folded.has(i) ? regions.value.get(i) : undefined\n i = end != null ? end + 1 : i + 1\n }\n return out\n})\n\nfunction toggle(i: number): void {\n if (folded.has(i)) folded.delete(i)\n else folded.add(i)\n}\n\n// Blob fallback for huge files: one highlighted block + a newline-joined gutter.\nconst blobHtml = computed(() =>\n effLang.value ? highlightCode(displayCode.value, effLang.value) : escapeHtml(displayCode.value),\n)\nconst blobGutter = computed(() =>\n Array.from({ length: lineCount.value }, (_, i) => i + 1).join('\\n'),\n)\n</script>\n\n<template>\n <div class=\"cv\">\n <!-- floating tools, top-right over the code: highlight-language picker + Prettier format toggle -->\n <div class=\"cv__tools\">\n <!-- highlight-language picker: force which grammar colorizes the source (auto-detect is often empty/wrong) -->\n <div ref=\"langMenuRef\" class=\"cv__lang\">\n <button\n type=\"button\"\n class=\"cv__toolbtn\"\n :class=\"{ 'cv__toolbtn--on': langMenuOpen }\"\n title=\"高亮语言 —— 选择用哪种语言着色(自动识别不准时手动指定)\"\n :aria-haspopup=\"true\"\n :aria-expanded=\"langMenuOpen\"\n @click=\"langMenuOpen = !langMenuOpen\"\n >\n <Icon name=\"code\" :size=\"12\" /><span>{{ langLabel(effLang) }}</span>\n </button>\n <div v-if=\"langMenuOpen\" class=\"cv__langpop\" role=\"menu\">\n <input\n v-model=\"langQuery\"\n class=\"cv__langsearch\"\n type=\"text\"\n placeholder=\"搜索语言…\"\n spellcheck=\"false\"\n autocomplete=\"off\"\n />\n <div class=\"cv__langlist\">\n <button\n v-if=\"!langQuery\"\n type=\"button\"\n class=\"cv__langitem\"\n :class=\"{ 'cv__langitem--on': effLang === '' }\"\n role=\"menuitemradio\"\n :aria-checked=\"effLang === ''\"\n @click=\"chooseLang('')\"\n >\n <span class=\"cv__langitem-label\">纯文本(无高亮)</span>\n <Icon v-if=\"effLang === ''\" name=\"check\" :size=\"14\" class=\"cv__langitem-check\" />\n </button>\n <button\n v-for=\"l in langResults\"\n :key=\"l.id\"\n type=\"button\"\n class=\"cv__langitem\"\n :class=\"{ 'cv__langitem--on': effLang === l.id }\"\n role=\"menuitemradio\"\n :aria-checked=\"effLang === l.id\"\n @click=\"chooseLang(l.id)\"\n >\n <span class=\"cv__langitem-label\">{{ l.label }}</span>\n <Icon v-if=\"effLang === l.id\" name=\"check\" :size=\"14\" class=\"cv__langitem-check\" />\n </button>\n <p v-if=\"langQuery && !langResults.length\" class=\"cv__langempty\">无匹配语言</p>\n </div>\n </div>\n </div>\n\n <!-- format toggle (only for languages Prettier can parse) -->\n <button\n v-if=\"canFmt\"\n type=\"button\"\n class=\"cv__toolbtn cv__fmt\"\n :class=\"{ 'cv__toolbtn--on': formatted != null, 'cv__fmt--err': formatErr }\"\n :disabled=\"formatting\"\n :title=\"\n formatErr\n ? '格式化失败:源码可能无法解析'\n : formatted != null\n ? '还原为原始格式'\n : '用 Prettier 格式化'\n \"\n @click=\"toggleFormat\"\n >\n {{\n formatErr\n ? '格式化失败'\n : formatting\n ? '格式化中…'\n : formatted != null\n ? '还原'\n : '格式化'\n }}\n </button>\n </div>\n\n <!-- huge file: single highlighted block (no folding) -->\n <div v-if=\"!foldable\" class=\"cv__scroll cv__scroll--blob\">\n <div class=\"cv__codewrap\">\n <pre class=\"cv__gutter\" aria-hidden=\"true\">{{ blobGutter }}</pre>\n <div class=\"cv__codecol\">\n <pre\n class=\"cv__pre\"\n ><code v-if=\"ansiDocument\" class=\"hljs\"><AnsiText :lines=\"ansiDocument.lines\" /></code><code v-else class=\"hljs\" v-html=\"blobHtml\" /></pre>\n </div>\n </div>\n </div>\n\n <!-- foldable: one row per visible line, with a fold chevron on block headers -->\n <div v-else class=\"cv__scroll\">\n <div class=\"cv__rows\">\n <div v-for=\"i in visible\" :key=\"i\" class=\"cv__row\">\n <span class=\"cv__gut\">\n <button\n v-if=\"regions.has(i)\"\n type=\"button\"\n class=\"cv__fold\"\n :title=\"folded.has(i) ? '展开' : '折叠'\"\n @click=\"toggle(i)\"\n >\n <Icon name=\"chevronRight\" :size=\"12\" :class=\"{ 'cv__fold--open': !folded.has(i) }\" />\n </button>\n <span v-else class=\"cv__fold cv__fold--empty\" />\n <span class=\"cv__ln\">{{ i + 1 }}</span>\n </span>\n <code class=\"cv__code hljs\">\n <AnsiText v-if=\"ansiDocument\" :line=\"ansiDocument.lines[i] ?? ''\" />\n <span v-else v-html=\"lineHtml[i]\" />\n </code>\n <button\n v-if=\"folded.has(i)\"\n type=\"button\"\n class=\"cv__ellipsis\"\n :title=\"`展开折叠的 ${(regions.get(i) ?? i) - i} 行`\"\n @click=\"toggle(i)\"\n >\n ⋯\n </button>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n.cv {\n position: relative;\n flex: 1 1 auto;\n min-height: 0;\n display: flex;\n flex-direction: column;\n}\n\n/* Floating tools bar — top-right, above the code (highlight-language picker + format toggle). */\n.cv__tools {\n position: absolute;\n top: 8px;\n right: 14px;\n z-index: 3;\n display: flex;\n align-items: flex-start;\n gap: 6px;\n}\n\n/* Shared small pill used by both floating tools. */\n.cv__toolbtn {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n max-width: 190px;\n padding: 3px 10px;\n font-family: inherit;\n font-size: 11.5px;\n color: var(--muted);\n background: var(--surface);\n border: 1px solid var(--border-2);\n border-radius: 7px;\n cursor: pointer;\n box-shadow: var(--shadow);\n transition:\n background 0.15s,\n color 0.15s,\n border-color 0.15s;\n}\n.cv__toolbtn:hover {\n border-color: var(--accent);\n color: var(--accent);\n}\n.cv__toolbtn span {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.cv__toolbtn--on {\n color: #fff;\n background: var(--accent);\n border-color: var(--accent);\n}\n.cv__toolbtn--on:hover {\n color: #fff;\n}\n\n/* Format toggle specifics (disabled + error states). */\n.cv__fmt:disabled {\n cursor: default;\n opacity: 0.7;\n}\n.cv__fmt--err {\n color: var(--danger);\n border-color: var(--danger);\n}\n\n/* Highlight-language picker dropdown (anchored under its pill, right-aligned). */\n.cv__lang {\n position: relative;\n display: inline-flex;\n}\n.cv__langpop {\n position: absolute;\n top: calc(100% + 6px);\n right: 0;\n z-index: 4;\n width: 224px;\n padding: 7px;\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: 10px;\n box-shadow: var(--shadow);\n}\n.cv__langsearch {\n width: 100%;\n box-sizing: border-box;\n padding: 6px 9px;\n font-family: inherit;\n font-size: 12px;\n color: var(--text);\n background: var(--surface-2);\n border: 1px solid var(--border);\n border-radius: 7px;\n outline: none;\n}\n.cv__langsearch:focus {\n border-color: var(--accent);\n}\n.cv__langlist {\n max-height: 288px;\n overflow-y: auto;\n overscroll-behavior: contain;\n margin-top: 6px;\n}\n.cv__langitem {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n padding: 6px 8px;\n background: transparent;\n border: none;\n border-radius: 6px;\n color: var(--text);\n font-family: inherit;\n font-size: 12.5px;\n text-align: left;\n cursor: pointer;\n transition:\n background 0.12s,\n color 0.12s;\n}\n.cv__langitem:hover {\n background: var(--surface-2);\n color: var(--accent);\n}\n.cv__langitem--on {\n color: var(--accent);\n}\n.cv__langitem-label {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.cv__langitem-check {\n flex-shrink: 0;\n color: var(--accent);\n}\n.cv__langempty {\n margin: 0;\n padding: 10px 8px;\n font-size: 12px;\n color: var(--faint);\n text-align: center;\n}\n\n.cv__scroll {\n flex: 1 1 auto;\n min-height: 0;\n overflow: auto;\n overscroll-behavior: contain;\n background: var(--code-bg);\n}\n\n/* Foldable per-line view -------------------------------------------------------------------------- */\n.cv__rows {\n min-width: max-content;\n padding: 14px 0;\n font-family: var(--font-mono);\n font-size: var(--fv-code-fs, 12.5px);\n line-height: var(--fv-code-lh, 21px);\n}\n.cv__row {\n display: flex;\n align-items: flex-start;\n}\n/* Gutter (fold chevron + line number) sticks to the left so it stays put while long lines scroll. */\n.cv__gut {\n position: sticky;\n left: 0;\n z-index: 1;\n flex-shrink: 0;\n display: flex;\n align-items: flex-start;\n background: var(--code-bg);\n user-select: none;\n}\n.cv__fold {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 16px;\n height: var(--fv-code-lh, 21px);\n padding: 0;\n border: none;\n background: transparent;\n color: var(--faint);\n cursor: pointer;\n}\n.cv__fold--empty {\n cursor: default;\n}\n.cv__fold :deep(svg) {\n transition: transform 0.12s;\n}\n.cv__fold--open {\n transform: rotate(90deg);\n}\n.cv__fold:hover :deep(svg) {\n color: var(--accent);\n}\n.cv__ln {\n flex-shrink: 0;\n width: 48px;\n padding: 0 12px 0 4px;\n text-align: right;\n color: var(--faint);\n}\n.cv__code {\n flex: 1 1 auto;\n padding: 0 18px 0 14px;\n white-space: pre;\n color: var(--text);\n background: transparent;\n border: none;\n font-family: inherit;\n tab-size: 2;\n}\n.cv__ellipsis {\n align-self: center;\n margin: 0 0 0 2px;\n padding: 0 7px;\n font-family: inherit;\n line-height: 1.3;\n color: var(--muted);\n background: var(--surface-2);\n border: 1px solid var(--border-2);\n border-radius: 5px;\n cursor: pointer;\n}\n.cv__ellipsis:hover {\n border-color: var(--accent);\n color: var(--accent);\n}\n\n/* Huge-file blob fallback (mirrors the panel's original source layout) ----------------------------- */\n.cv__scroll--blob {\n overflow-x: hidden;\n overflow-y: auto;\n}\n.cv__codewrap {\n display: flex;\n align-items: stretch;\n min-height: 100%;\n padding: 14px 0;\n}\n.cv__gutter {\n flex-shrink: 0;\n margin: 0;\n padding: 0 12px 0 16px;\n border-right: 1px solid var(--code-border);\n text-align: right;\n font-family: var(--font-mono);\n font-size: var(--fv-code-fs, 12.5px);\n line-height: var(--fv-code-lh, 21px);\n color: var(--faint);\n user-select: none;\n white-space: pre;\n}\n.cv__codecol {\n flex: 1 1 auto;\n min-width: 0;\n overflow-x: auto;\n}\n.cv__pre {\n margin: 0;\n padding: 0 18px 0 14px;\n font-family: var(--font-mono);\n font-size: var(--fv-code-fs, 12.5px);\n line-height: var(--fv-code-lh, 21px);\n color: var(--text);\n white-space: pre;\n tab-size: 2;\n}\n.cv__pre code {\n font-family: inherit;\n background: transparent;\n border: none;\n padding: 0;\n}\n</style>\n"],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import e from "../_virtual/_plugin-vue_export-helper.js";
|
|
2
|
+
import t from "./DocxEmbeddedFiles.vue_vue_type_script_setup_true_lang.js";
|
|
3
|
+
/* empty css */
|
|
4
|
+
//#region src/components/DocxEmbeddedFiles.vue
|
|
5
|
+
var n = /*#__PURE__*/ e(t, [["__scopeId", "data-v-2106357b"]]);
|
|
6
|
+
//#endregion
|
|
7
|
+
export { n as default };
|
|
8
|
+
|
|
9
|
+
//# sourceMappingURL=DocxEmbeddedFiles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DocxEmbeddedFiles.js","names":[],"sources":["../../src/components/DocxEmbeddedFiles.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport Icon from '@/components/icons/Icon.vue'\nimport { formatBytes } from '@/lib/format'\nimport type { DocxEmbeddedFile } from '@/lib/docxEmbeddings'\n\ndefineProps<{\n files: readonly DocxEmbeddedFile[]\n downloadBusyId?: string\n error?: string\n}>()\n\nconst emit = defineEmits<{\n open: [file: DocxEmbeddedFile]\n download: [file: DocxEmbeddedFile]\n}>()\n\nfunction extension(name: string): string {\n const i = name.lastIndexOf('.')\n return i > 0 ? name.slice(i + 1).toUpperCase() : 'FILE'\n}\n</script>\n\n<template>\n <section class=\"def\" aria-label=\"Word 文档内嵌文件\">\n <div class=\"def__heading\">\n <Icon name=\"paperclip\" :size=\"14\" />\n <span>内嵌文件</span>\n <span class=\"def__count\">{{ files.length }}</span>\n </div>\n <div class=\"def__list\">\n <div v-for=\"file in files\" :key=\"file.id\" class=\"def__item\">\n <button\n type=\"button\"\n class=\"def__open\"\n :title=\"`预览 ${file.name}`\"\n @click=\"emit('open', file)\"\n >\n <span class=\"def__ext\">{{ extension(file.name) }}</span>\n <span class=\"def__name\">{{ file.label || file.name }}</span>\n <span class=\"def__size\">{{ formatBytes(file.size) }}</span>\n </button>\n <button\n type=\"button\"\n class=\"def__download\"\n :disabled=\"downloadBusyId === file.id\"\n :title=\"downloadBusyId === file.id ? '正在准备下载' : `下载 ${file.name}`\"\n @click=\"emit('download', file)\"\n >\n <Icon :name=\"downloadBusyId === file.id ? 'clock' : 'download'\" :size=\"14\" />\n </button>\n </div>\n </div>\n <span v-if=\"error\" class=\"def__error\" role=\"status\" :title=\"error\">{{ error }}</span>\n </section>\n</template>\n\n<style scoped>\n.def {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-shrink: 0;\n min-width: 0;\n padding: 7px 10px;\n border-bottom: 1px solid var(--border);\n background: var(--surface);\n}\n.def__heading {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n flex-shrink: 0;\n color: var(--muted);\n font-size: 11.5px;\n font-weight: 600;\n white-space: nowrap;\n}\n.def__count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n border-radius: 999px;\n color: var(--accent);\n background: var(--accent-soft);\n font-size: 10.5px;\n font-variant-numeric: tabular-nums;\n}\n.def__list {\n display: flex;\n align-items: center;\n gap: 6px;\n flex: 1 1 auto;\n min-width: 0;\n overflow-x: auto;\n overscroll-behavior-inline: contain;\n scrollbar-width: thin;\n}\n.def__item {\n display: flex;\n align-items: stretch;\n flex: 0 0 auto;\n min-width: 180px;\n max-width: 260px;\n height: 32px;\n border: 1px solid var(--border-2);\n border-radius: 8px;\n background: var(--surface-2);\n overflow: hidden;\n}\n.def__item:hover {\n border-color: var(--accent);\n}\n.def__open,\n.def__download {\n font-family: inherit;\n color: inherit;\n background: transparent;\n border: none;\n cursor: pointer;\n}\n.def__open {\n display: flex;\n align-items: center;\n gap: 7px;\n flex: 1 1 auto;\n min-width: 0;\n padding: 0 8px;\n text-align: left;\n}\n.def__ext {\n flex-shrink: 0;\n color: var(--accent);\n font-size: 9.5px;\n font-weight: 700;\n letter-spacing: 0.04em;\n}\n.def__name {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n color: var(--text);\n font-size: 11.5px;\n font-weight: 500;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.def__size {\n flex-shrink: 0;\n color: var(--faint);\n font-size: 10px;\n font-variant-numeric: tabular-nums;\n}\n.def__download {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 30px;\n border-left: 1px solid var(--border);\n color: var(--muted);\n}\n.def__download:hover:not(:disabled) {\n color: var(--accent);\n background: var(--surface);\n}\n.def__download:disabled {\n cursor: wait;\n opacity: 0.6;\n}\n.def__error {\n flex: 0 1 180px;\n min-width: 0;\n overflow: hidden;\n color: var(--danger);\n font-size: 10.5px;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n@container (max-width: 500px) {\n .def {\n align-items: stretch;\n flex-direction: column;\n gap: 6px;\n }\n .def__item {\n min-width: 170px;\n }\n .def__error {\n flex-basis: auto;\n }\n}\n</style>\n"],"mappings":""}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DocxEmbeddedFile } from '@/lib/docxEmbeddings';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
files: readonly DocxEmbeddedFile[];
|
|
4
|
+
downloadBusyId?: string;
|
|
5
|
+
error?: string;
|
|
6
|
+
};
|
|
7
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
8
|
+
download: (file: DocxEmbeddedFile) => any;
|
|
9
|
+
open: (file: DocxEmbeddedFile) => any;
|
|
10
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
11
|
+
onDownload?: ((file: DocxEmbeddedFile) => any) | undefined;
|
|
12
|
+
onOpen?: ((file: DocxEmbeddedFile) => any) | undefined;
|
|
13
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
14
|
+
declare const _default: typeof __VLS_export;
|
|
15
|
+
export default _default;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { formatBytes as e } from "../lib/format.js";
|
|
2
|
+
import t from "./icons/Icon.js";
|
|
3
|
+
import { Fragment as n, createCommentVNode as r, createElementBlock as i, createElementVNode as a, createVNode as o, defineComponent as s, openBlock as c, renderList as l, toDisplayString as u, unref as d } from "vue";
|
|
4
|
+
//#region src/components/DocxEmbeddedFiles.vue?vue&type=script&setup=true&lang.ts
|
|
5
|
+
var f = {
|
|
6
|
+
class: "def",
|
|
7
|
+
"aria-label": "Word 文档内嵌文件"
|
|
8
|
+
}, p = { class: "def__heading" }, m = { class: "def__count" }, h = { class: "def__list" }, g = ["title", "onClick"], _ = { class: "def__ext" }, v = { class: "def__name" }, y = { class: "def__size" }, b = [
|
|
9
|
+
"disabled",
|
|
10
|
+
"title",
|
|
11
|
+
"onClick"
|
|
12
|
+
], x = ["title"], S = /*@__PURE__*/ s({
|
|
13
|
+
__name: "DocxEmbeddedFiles",
|
|
14
|
+
props: {
|
|
15
|
+
files: {},
|
|
16
|
+
downloadBusyId: {},
|
|
17
|
+
error: {}
|
|
18
|
+
},
|
|
19
|
+
emits: ["open", "download"],
|
|
20
|
+
setup(s, { emit: S }) {
|
|
21
|
+
let C = S;
|
|
22
|
+
function w(e) {
|
|
23
|
+
let t = e.lastIndexOf(".");
|
|
24
|
+
return t > 0 ? e.slice(t + 1).toUpperCase() : "FILE";
|
|
25
|
+
}
|
|
26
|
+
return (S, T) => (c(), i("section", f, [
|
|
27
|
+
a("div", p, [
|
|
28
|
+
o(t, {
|
|
29
|
+
name: "paperclip",
|
|
30
|
+
size: 14
|
|
31
|
+
}),
|
|
32
|
+
T[0] ||= a("span", null, "内嵌文件", -1),
|
|
33
|
+
a("span", m, u(s.files.length), 1)
|
|
34
|
+
]),
|
|
35
|
+
a("div", h, [(c(!0), i(n, null, l(s.files, (n) => (c(), i("div", {
|
|
36
|
+
key: n.id,
|
|
37
|
+
class: "def__item"
|
|
38
|
+
}, [a("button", {
|
|
39
|
+
type: "button",
|
|
40
|
+
class: "def__open",
|
|
41
|
+
title: `预览 ${n.name}`,
|
|
42
|
+
onClick: (e) => C("open", n)
|
|
43
|
+
}, [
|
|
44
|
+
a("span", _, u(w(n.name)), 1),
|
|
45
|
+
a("span", v, u(n.label || n.name), 1),
|
|
46
|
+
a("span", y, u(d(e)(n.size)), 1)
|
|
47
|
+
], 8, g), a("button", {
|
|
48
|
+
type: "button",
|
|
49
|
+
class: "def__download",
|
|
50
|
+
disabled: s.downloadBusyId === n.id,
|
|
51
|
+
title: s.downloadBusyId === n.id ? "正在准备下载" : `下载 ${n.name}`,
|
|
52
|
+
onClick: (e) => C("download", n)
|
|
53
|
+
}, [o(t, {
|
|
54
|
+
name: s.downloadBusyId === n.id ? "clock" : "download",
|
|
55
|
+
size: 14
|
|
56
|
+
}, null, 8, ["name"])], 8, b)]))), 128))]),
|
|
57
|
+
s.error ? (c(), i("span", {
|
|
58
|
+
key: 0,
|
|
59
|
+
class: "def__error",
|
|
60
|
+
role: "status",
|
|
61
|
+
title: s.error
|
|
62
|
+
}, u(s.error), 9, x)) : r("", !0)
|
|
63
|
+
]));
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
//#endregion
|
|
67
|
+
export { S as default };
|
|
68
|
+
|
|
69
|
+
//# sourceMappingURL=DocxEmbeddedFiles.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DocxEmbeddedFiles.vue_vue_type_script_setup_true_lang.js","names":[],"sources":["../../src/components/DocxEmbeddedFiles.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport Icon from '@/components/icons/Icon.vue'\nimport { formatBytes } from '@/lib/format'\nimport type { DocxEmbeddedFile } from '@/lib/docxEmbeddings'\n\ndefineProps<{\n files: readonly DocxEmbeddedFile[]\n downloadBusyId?: string\n error?: string\n}>()\n\nconst emit = defineEmits<{\n open: [file: DocxEmbeddedFile]\n download: [file: DocxEmbeddedFile]\n}>()\n\nfunction extension(name: string): string {\n const i = name.lastIndexOf('.')\n return i > 0 ? name.slice(i + 1).toUpperCase() : 'FILE'\n}\n</script>\n\n<template>\n <section class=\"def\" aria-label=\"Word 文档内嵌文件\">\n <div class=\"def__heading\">\n <Icon name=\"paperclip\" :size=\"14\" />\n <span>内嵌文件</span>\n <span class=\"def__count\">{{ files.length }}</span>\n </div>\n <div class=\"def__list\">\n <div v-for=\"file in files\" :key=\"file.id\" class=\"def__item\">\n <button\n type=\"button\"\n class=\"def__open\"\n :title=\"`预览 ${file.name}`\"\n @click=\"emit('open', file)\"\n >\n <span class=\"def__ext\">{{ extension(file.name) }}</span>\n <span class=\"def__name\">{{ file.label || file.name }}</span>\n <span class=\"def__size\">{{ formatBytes(file.size) }}</span>\n </button>\n <button\n type=\"button\"\n class=\"def__download\"\n :disabled=\"downloadBusyId === file.id\"\n :title=\"downloadBusyId === file.id ? '正在准备下载' : `下载 ${file.name}`\"\n @click=\"emit('download', file)\"\n >\n <Icon :name=\"downloadBusyId === file.id ? 'clock' : 'download'\" :size=\"14\" />\n </button>\n </div>\n </div>\n <span v-if=\"error\" class=\"def__error\" role=\"status\" :title=\"error\">{{ error }}</span>\n </section>\n</template>\n\n<style scoped>\n.def {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-shrink: 0;\n min-width: 0;\n padding: 7px 10px;\n border-bottom: 1px solid var(--border);\n background: var(--surface);\n}\n.def__heading {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n flex-shrink: 0;\n color: var(--muted);\n font-size: 11.5px;\n font-weight: 600;\n white-space: nowrap;\n}\n.def__count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n border-radius: 999px;\n color: var(--accent);\n background: var(--accent-soft);\n font-size: 10.5px;\n font-variant-numeric: tabular-nums;\n}\n.def__list {\n display: flex;\n align-items: center;\n gap: 6px;\n flex: 1 1 auto;\n min-width: 0;\n overflow-x: auto;\n overscroll-behavior-inline: contain;\n scrollbar-width: thin;\n}\n.def__item {\n display: flex;\n align-items: stretch;\n flex: 0 0 auto;\n min-width: 180px;\n max-width: 260px;\n height: 32px;\n border: 1px solid var(--border-2);\n border-radius: 8px;\n background: var(--surface-2);\n overflow: hidden;\n}\n.def__item:hover {\n border-color: var(--accent);\n}\n.def__open,\n.def__download {\n font-family: inherit;\n color: inherit;\n background: transparent;\n border: none;\n cursor: pointer;\n}\n.def__open {\n display: flex;\n align-items: center;\n gap: 7px;\n flex: 1 1 auto;\n min-width: 0;\n padding: 0 8px;\n text-align: left;\n}\n.def__ext {\n flex-shrink: 0;\n color: var(--accent);\n font-size: 9.5px;\n font-weight: 700;\n letter-spacing: 0.04em;\n}\n.def__name {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n color: var(--text);\n font-size: 11.5px;\n font-weight: 500;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.def__size {\n flex-shrink: 0;\n color: var(--faint);\n font-size: 10px;\n font-variant-numeric: tabular-nums;\n}\n.def__download {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 30px;\n border-left: 1px solid var(--border);\n color: var(--muted);\n}\n.def__download:hover:not(:disabled) {\n color: var(--accent);\n background: var(--surface);\n}\n.def__download:disabled {\n cursor: wait;\n opacity: 0.6;\n}\n.def__error {\n flex: 0 1 180px;\n min-width: 0;\n overflow: hidden;\n color: var(--danger);\n font-size: 10.5px;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n@container (max-width: 500px) {\n .def {\n align-items: stretch;\n flex-direction: column;\n gap: 6px;\n }\n .def__item {\n min-width: 170px;\n }\n .def__error {\n flex-basis: auto;\n }\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;EAWA,IAAM,IAAO;EAKb,SAAS,EAAU,GAAsB;GACvC,IAAM,IAAI,EAAK,YAAY,GAAG;GAC9B,OAAO,IAAI,IAAI,EAAK,MAAM,IAAI,CAAC,CAAC,CAAC,YAAY,IAAI;EACnD;yBAIE,EA8BU,WA9BV,GA8BU;GA7BR,EAIM,OAJN,GAIM;IAHJ,EAAoC,GAAA;KAA9B,MAAK;KAAa,MAAM;;aAC9B,EAAiB,QAAA,MAAX,QAAI,EAAA;IACV,EAAkD,QAAlD,GAAkD,EAAtB,EAAA,MAAM,MAAM,GAAA,CAAA;;GAE1C,EAsBM,OAtBN,GAsBM,EAAA,EAAA,EAAA,GArBJ,EAoBM,GAAA,MAAA,EApBc,EAAA,QAAR,YAAZ,EAoBM,OAAA;IApBsB,KAAK,EAAK;IAAI,OAAM;OAC9C,EASS,UAAA;IARP,MAAK;IACL,OAAM;IACL,OAAK,MAAQ,EAAK;IAClB,UAAK,MAAE,EAAI,QAAS,CAAI;;IAEzB,EAAwD,QAAxD,GAAwD,EAA9B,EAAU,EAAK,IAAI,CAAA,GAAA,CAAA;IAC7C,EAA4D,QAA5D,GAA4D,EAAjC,EAAK,SAAS,EAAK,IAAI,GAAA,CAAA;IAClD,EAA2D,QAA3D,GAA2D,EAAhC,EAAA,CAAA,CAAW,CAAC,EAAK,IAAI,CAAA,GAAA,CAAA;aAElD,EAQS,UAAA;IAPP,MAAK;IACL,OAAM;IACL,UAAU,EAAA,mBAAmB,EAAK;IAClC,OAAO,EAAA,mBAAmB,EAAK,KAAE,WAAA,MAAoB,EAAK;IAC1D,UAAK,MAAE,EAAI,YAAa,CAAI;OAE7B,EAA6E,GAAA;IAAtE,MAAM,EAAA,mBAAmB,EAAK,KAAE,UAAA;IAA0B,MAAM;;GAIjE,EAAA,SAAA,EAAA,GAAZ,EAAqF,QAAA;;IAAlE,OAAM;IAAa,MAAK;IAAU,OAAO,EAAA;QAAU,EAAA,KAAK,GAAA,GAAA,CAAA,KAAA,EAAA,IAAA,EAAA"}
|
|
@@ -2,7 +2,7 @@ import e from "../_virtual/_plugin-vue_export-helper.js";
|
|
|
2
2
|
import t from "./DocxNavigationPane.vue_vue_type_script_setup_true_lang.js";
|
|
3
3
|
/* empty css */
|
|
4
4
|
//#region src/components/DocxNavigationPane.vue
|
|
5
|
-
var n = /*#__PURE__*/ e(t, [["__scopeId", "data-v-
|
|
5
|
+
var n = /*#__PURE__*/ e(t, [["__scopeId", "data-v-47c3c806"]]);
|
|
6
6
|
//#endregion
|
|
7
7
|
export { n as default };
|
|
8
8
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DocxNavigationPane.js","names":[],"sources":["../../src/components/DocxNavigationPane.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ElementNavigationItem } from '@/composables/useElementNavigation'\nimport Icon from '@/components/icons/Icon.vue'\n\nconst props = defineProps<{\n outlineItems: readonly ElementNavigationItem[]\n pageItems: readonly ElementNavigationItem[]\n activeOutlineId: string\n activePageId: string\n}>()\n\nconst emit = defineEmits<{ navigate: [item: ElementNavigationItem] }>()\nconst collapsed = defineModel<boolean>('collapsed', { default: false })\nconst view = defineModel<'outline' | 'pages'>('view', { default: 'outline' })\n\nfunction isActive(item: ElementNavigationItem): boolean {\n return (view.value === 'outline' ? props.activeOutlineId : props.activePageId) === item.id\n}\n</script>\n\n<template>\n <aside class=\"dn\" :class=\"{ 'dn--collapsed': collapsed }\" aria-label=\"文档导航\">\n <button\n v-if=\"collapsed\"\n type=\"button\"\n class=\"dn__reopen\"\n aria-label=\"展开文档导航\"\n title=\"展开文档导航\"\n @click=\"collapsed = false\"\n >\n <Icon name=\"chevronRight\" :size=\"15\" />\n </button>\n\n <template v-else>\n <header class=\"dn__header\">\n <div>\n <strong class=\"dn__title\">导航</strong>\n <span class=\"dn__count\">{{ pageItems.length }} 页</span>\n </div>\n <button\n type=\"button\"\n class=\"dn__collapse\"\n aria-label=\"收起文档导航\"\n title=\"收起文档导航\"\n @click=\"collapsed = true\"\n >\n <Icon name=\"chevronLeft\" :size=\"15\" />\n </button>\n </header>\n\n <div class=\"dn__tabs\" role=\"tablist\" aria-label=\"导航方式\">\n <button\n type=\"button\"\n role=\"tab\"\n class=\"dn__tab\"\n :class=\"{ 'dn__tab--active': view === 'outline' }\"\n :aria-selected=\"view === 'outline'\"\n @click=\"view = 'outline'\"\n >\n 目录\n </button>\n <button\n type=\"button\"\n role=\"tab\"\n class=\"dn__tab\"\n :class=\"{ 'dn__tab--active': view === 'pages' }\"\n :aria-selected=\"view === 'pages'\"\n @click=\"view = 'pages'\"\n >\n 页面\n </button>\n </div>\n\n <nav class=\"dn__list\" aria-label=\"文档目录\">\n <template v-if=\"view === 'outline'\">\n <button\n v-for=\"item in outlineItems\"\n :key=\"item.id\"\n type=\"button\"\n class=\"dn__outline-item\"\n :class=\"{ 'dn__item--active': isActive(item) }\"\n :style=\"{ paddingLeft: `${10 + item.level * 12}px` }\"\n :aria-current=\"isActive(item) ? 'location' : undefined\"\n :title=\"item.title\"\n @click=\"emit('navigate', item)\"\n >\n <span class=\"dn__marker\" />\n <span class=\"dn__label\">{{ item.title }}</span>\n </button>\n <p v-if=\"!outlineItems.length\" class=\"dn__empty\">\n 文档未设置标题层级,可切换到“页面”导航。\n </p>\n </template>\n\n <template v-else>\n <button\n v-for=\"(item, index) in pageItems\"\n :key=\"item.id\"\n type=\"button\"\n class=\"dn__page-item\"\n :class=\"{ 'dn__item--active': isActive(item) }\"\n :aria-current=\"isActive(item) ? 'page' : undefined\"\n @click=\"emit('navigate', item)\"\n >\n <span class=\"dn__page-sheet\">{{ index + 1 }}</span>\n <span class=\"dn__label\">{{ item.title }}</span>\n </button>\n </template>\n </nav>\n </template>\n </aside>\n</template>\n\n<style scoped>\n.dn {\n position: relative;\n flex: 0 0 166px;\n width: 166px;\n min-width: 0;\n display: flex;\n flex-direction: column;\n border-right: 1px solid var(--border);\n background: color-mix(in srgb, var(--surface) 94%, var(--surface-2));\n transition: flex-basis 160ms ease;\n}\n.dn--collapsed {\n flex-basis: 0;\n width: 0;\n border-right: 0;\n}\n.dn__header {\n min-height: 45px;\n padding: 9px 8px 8px 12px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 6px;\n border-bottom: 1px solid var(--border);\n}\n.dn__title {\n display: block;\n color: var(--text-strong);\n font-size: 12.5px;\n font-weight: 650;\n}\n.dn__count {\n display: block;\n margin-top: 1px;\n color: var(--faint);\n font-size: 10.5px;\n}\n.dn__collapse,\n.dn__reopen {\n border: 0;\n color: var(--muted);\n background: transparent;\n cursor: pointer;\n}\n.dn__collapse {\n width: 27px;\n height: 27px;\n display: grid;\n place-items: center;\n border-radius: 7px;\n}\n.dn__collapse:hover {\n color: var(--text-strong);\n background: var(--bubble);\n}\n.dn__reopen {\n position: absolute;\n z-index: 3;\n top: 12px;\n right: -28px;\n width: 28px;\n height: 36px;\n padding: 0;\n display: grid;\n place-items: center;\n border: 1px solid var(--border-2);\n border-radius: 0 9px 9px 0;\n background: var(--surface);\n box-shadow:
|
|
1
|
+
{"version":3,"file":"DocxNavigationPane.js","names":[],"sources":["../../src/components/DocxNavigationPane.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ElementNavigationItem } from '@/composables/useElementNavigation'\nimport Icon from '@/components/icons/Icon.vue'\n\nconst props = defineProps<{\n outlineItems: readonly ElementNavigationItem[]\n pageItems: readonly ElementNavigationItem[]\n activeOutlineId: string\n activePageId: string\n}>()\n\nconst emit = defineEmits<{ navigate: [item: ElementNavigationItem] }>()\nconst collapsed = defineModel<boolean>('collapsed', { default: false })\nconst view = defineModel<'outline' | 'pages'>('view', { default: 'outline' })\n\nfunction isActive(item: ElementNavigationItem): boolean {\n return (view.value === 'outline' ? props.activeOutlineId : props.activePageId) === item.id\n}\n</script>\n\n<template>\n <aside class=\"dn\" :class=\"{ 'dn--collapsed': collapsed }\" aria-label=\"文档导航\">\n <button\n v-if=\"collapsed\"\n type=\"button\"\n class=\"dn__reopen\"\n aria-label=\"展开文档导航\"\n title=\"展开文档导航\"\n @click=\"collapsed = false\"\n >\n <Icon name=\"chevronRight\" :size=\"15\" />\n </button>\n\n <template v-else>\n <header class=\"dn__header\">\n <div>\n <strong class=\"dn__title\">导航</strong>\n <span class=\"dn__count\">{{ pageItems.length }} 页</span>\n </div>\n <button\n type=\"button\"\n class=\"dn__collapse\"\n aria-label=\"收起文档导航\"\n title=\"收起文档导航\"\n @click=\"collapsed = true\"\n >\n <Icon name=\"chevronLeft\" :size=\"15\" />\n </button>\n </header>\n\n <div class=\"dn__tabs\" role=\"tablist\" aria-label=\"导航方式\">\n <button\n type=\"button\"\n role=\"tab\"\n class=\"dn__tab\"\n :class=\"{ 'dn__tab--active': view === 'outline' }\"\n :aria-selected=\"view === 'outline'\"\n @click=\"view = 'outline'\"\n >\n 目录\n </button>\n <button\n type=\"button\"\n role=\"tab\"\n class=\"dn__tab\"\n :class=\"{ 'dn__tab--active': view === 'pages' }\"\n :aria-selected=\"view === 'pages'\"\n @click=\"view = 'pages'\"\n >\n 页面\n </button>\n </div>\n\n <nav class=\"dn__list\" aria-label=\"文档目录\">\n <template v-if=\"view === 'outline'\">\n <button\n v-for=\"item in outlineItems\"\n :key=\"item.id\"\n type=\"button\"\n class=\"dn__outline-item\"\n :class=\"{ 'dn__item--active': isActive(item) }\"\n :style=\"{ paddingLeft: `${10 + item.level * 12}px` }\"\n :aria-current=\"isActive(item) ? 'location' : undefined\"\n :title=\"item.title\"\n @click=\"emit('navigate', item)\"\n >\n <span class=\"dn__marker\" />\n <span class=\"dn__label\">{{ item.title }}</span>\n </button>\n <p v-if=\"!outlineItems.length\" class=\"dn__empty\">\n 文档未设置标题层级,可切换到“页面”导航。\n </p>\n </template>\n\n <template v-else>\n <button\n v-for=\"(item, index) in pageItems\"\n :key=\"item.id\"\n type=\"button\"\n class=\"dn__page-item\"\n :class=\"{ 'dn__item--active': isActive(item) }\"\n :aria-current=\"isActive(item) ? 'page' : undefined\"\n @click=\"emit('navigate', item)\"\n >\n <span class=\"dn__page-sheet\">{{ index + 1 }}</span>\n <span class=\"dn__label\">{{ item.title }}</span>\n </button>\n </template>\n </nav>\n </template>\n </aside>\n</template>\n\n<style scoped>\n.dn {\n position: relative;\n flex: 0 0 166px;\n width: 166px;\n min-width: 0;\n display: flex;\n flex-direction: column;\n border-right: 1px solid var(--border);\n background: color-mix(in srgb, var(--surface) 94%, var(--surface-2));\n transition: flex-basis 160ms ease;\n}\n.dn--collapsed {\n flex-basis: 0;\n width: 0;\n border-right: 0;\n}\n.dn__header {\n min-height: 45px;\n padding: 9px 8px 8px 12px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 6px;\n border-bottom: 1px solid var(--border);\n}\n.dn__title {\n display: block;\n color: var(--text-strong);\n font-size: 12.5px;\n font-weight: 650;\n}\n.dn__count {\n display: block;\n margin-top: 1px;\n color: var(--faint);\n font-size: 10.5px;\n}\n.dn__collapse,\n.dn__reopen {\n border: 0;\n color: var(--muted);\n background: transparent;\n cursor: pointer;\n}\n.dn__collapse {\n width: 27px;\n height: 27px;\n display: grid;\n place-items: center;\n border-radius: 7px;\n}\n.dn__collapse:hover {\n color: var(--text-strong);\n background: var(--bubble);\n}\n.dn__reopen {\n position: absolute;\n z-index: 3;\n top: 12px;\n right: -28px;\n width: 28px;\n height: 36px;\n padding: 0;\n display: grid;\n place-items: center;\n border: 1px solid var(--border-2);\n border-radius: 0 9px 9px 0;\n background: var(--surface);\n box-shadow: var(--shadow);\n}\n.dn__reopen:hover {\n color: var(--text-strong);\n background: var(--bubble);\n}\n.dn__tabs {\n margin: 8px 8px 4px;\n padding: 2px;\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 2px;\n border-radius: 8px;\n background: var(--surface-2);\n}\n.dn__tab {\n min-width: 0;\n padding: 5px 4px;\n border: 0;\n border-radius: 6px;\n color: var(--muted);\n background: transparent;\n font: inherit;\n font-size: 11px;\n cursor: pointer;\n}\n.dn__tab--active {\n color: var(--text-strong);\n background: var(--surface);\n box-shadow: var(--shadow);\n}\n.dn__list {\n flex: 1 1 auto;\n min-height: 0;\n overflow: auto;\n padding: 4px 6px 18px;\n scrollbar-width: thin;\n}\n.dn__outline-item,\n.dn__page-item {\n position: relative;\n width: 100%;\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 7px;\n border: 0;\n border-radius: 7px;\n color: var(--muted);\n background: transparent;\n font: inherit;\n text-align: left;\n cursor: pointer;\n}\n.dn__outline-item {\n min-height: 31px;\n padding-top: 5px;\n padding-right: 7px;\n padding-bottom: 5px;\n}\n.dn__page-item {\n padding: 6px;\n}\n.dn__outline-item:hover,\n.dn__page-item:hover {\n color: var(--text-strong);\n background: var(--bubble);\n}\n.dn__item--active {\n color: var(--text-strong);\n background: var(--accent-soft);\n}\n.dn__marker {\n flex: 0 0 auto;\n width: 3px;\n height: 15px;\n border-radius: 999px;\n background: var(--border-2);\n}\n.dn__item--active .dn__marker {\n background: var(--accent);\n}\n.dn__page-sheet {\n flex: 0 0 auto;\n width: 26px;\n height: 34px;\n display: grid;\n place-items: center;\n border: 1px solid var(--border-2);\n border-radius: 3px;\n color: var(--muted);\n background: var(--surface);\n font-size: 9.5px;\n box-shadow: var(--shadow);\n}\n.dn__item--active .dn__page-sheet {\n border-color: var(--accent);\n color: var(--accent);\n}\n.dn__label {\n min-width: 0;\n overflow: hidden;\n display: -webkit-box;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 2;\n font-size: 11.5px;\n line-height: 1.35;\n}\n.dn__empty {\n margin: 10px 8px;\n color: var(--faint);\n font-size: 10.5px;\n line-height: 1.55;\n}\n\n@container (max-width: 500px) {\n .dn {\n flex-basis: 136px;\n width: 136px;\n }\n .dn--collapsed {\n flex-basis: 0;\n width: 0;\n }\n}\n</style>\n"],"mappings":""}
|