@braincrew-lab/langchain-canvas 0.1.12 → 0.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{ChartRenderer-CWV2OX3S.js → ChartRenderer-FX6ZN4NC.js} +24 -5
- package/dist/{SlidesRenderer-7ICJQHYT.js → SlidesRenderer-SK5VQDIL.js} +11 -6
- package/dist/{TableRenderer-ZF7MVA7I.js → TableRenderer-Y4JFRSLU.js} +55 -4
- package/dist/index.d.ts +3 -0
- package/dist/index.js +9 -5
- package/dist/styles.css +14 -0
- package/package.json +1 -1
|
@@ -1,30 +1,32 @@
|
|
|
1
1
|
import { useArtifactPatch } from './chunk-TERWLUW3.js';
|
|
2
2
|
import './chunk-KKLWKR5G.js';
|
|
3
|
-
import { useState,
|
|
3
|
+
import { useState, useRef, useMemo, useEffect } from 'react';
|
|
4
4
|
import * as echarts from 'echarts/core';
|
|
5
5
|
import { BarChart, LineChart, PieChart } from 'echarts/charts';
|
|
6
6
|
import { GridComponent, TooltipComponent, LegendComponent } from 'echarts/components';
|
|
7
7
|
import { CanvasRenderer } from 'echarts/renderers';
|
|
8
|
-
import {
|
|
8
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
9
9
|
|
|
10
10
|
echarts.use([BarChart, LineChart, PieChart, GridComponent, TooltipComponent, LegendComponent, CanvasRenderer]);
|
|
11
11
|
var PALETTE = ["#6366f1", "#10b981", "#f59e0b", "#ef4444", "#0ea5e9", "#a855f7"];
|
|
12
12
|
var seriesColor = (series, index) => series.color ?? PALETTE[index % PALETTE.length];
|
|
13
13
|
var sliceColor = (options, index) => options?.colors?.[index] ?? PALETTE[index % PALETTE.length];
|
|
14
14
|
var CHART_TYPES = ["bar", "line", "area", "pie"];
|
|
15
|
-
function EChart({ option, height }) {
|
|
15
|
+
function EChart({ option, height, onInst }) {
|
|
16
16
|
const boxRef = useRef(null);
|
|
17
17
|
const instRef = useRef(null);
|
|
18
18
|
useEffect(() => {
|
|
19
19
|
if (!boxRef.current) return;
|
|
20
20
|
const inst = echarts.init(boxRef.current, void 0, { renderer: "canvas" });
|
|
21
21
|
instRef.current = inst;
|
|
22
|
+
onInst?.(inst);
|
|
22
23
|
const ro = new ResizeObserver(() => inst.resize());
|
|
23
24
|
ro.observe(boxRef.current);
|
|
24
25
|
return () => {
|
|
25
26
|
ro.disconnect();
|
|
26
27
|
inst.dispose();
|
|
27
28
|
instRef.current = null;
|
|
29
|
+
onInst?.(null);
|
|
28
30
|
};
|
|
29
31
|
}, []);
|
|
30
32
|
useEffect(() => {
|
|
@@ -36,12 +38,28 @@ function ChartRenderer({ artifact }) {
|
|
|
36
38
|
const { chart, rows, xKey, series, options, echartsOption } = artifact.data;
|
|
37
39
|
const patch = useArtifactPatch(artifact.id);
|
|
38
40
|
const [editing, setEditing] = useState(false);
|
|
41
|
+
const instRef = useRef(null);
|
|
42
|
+
const downloadPng = () => {
|
|
43
|
+
const inst = instRef.current;
|
|
44
|
+
if (!inst) return;
|
|
45
|
+
const url = inst.getDataURL({ type: "png", pixelRatio: 2, backgroundColor: "#ffffff" });
|
|
46
|
+
const a = document.createElement("a");
|
|
47
|
+
a.href = url;
|
|
48
|
+
a.download = `${(artifact.title || "chart").replace(/[^a-z0-9가-힣]+/gi, "-").replace(/^-+|-+$/g, "") || "chart"}.png`;
|
|
49
|
+
a.click();
|
|
50
|
+
};
|
|
39
51
|
const option = useMemo(
|
|
40
52
|
() => echartsOption ?? toEChartsOption(chart, rows, xKey, series, options),
|
|
41
53
|
[echartsOption, chart, rows, xKey, series, options]
|
|
42
54
|
);
|
|
43
55
|
if (echartsOption) {
|
|
44
|
-
return /* @__PURE__ */
|
|
56
|
+
return /* @__PURE__ */ jsxs("div", { className: "cv-chart", children: [
|
|
57
|
+
/* @__PURE__ */ jsxs("div", { className: "cv-chart__toolbar cv-chrome", children: [
|
|
58
|
+
/* @__PURE__ */ jsx("span", { className: "cv-chart__spacer" }),
|
|
59
|
+
/* @__PURE__ */ jsx("button", { className: "cv-edit-btn", onClick: downloadPng, title: "Download as PNG", children: "\u2913 PNG" })
|
|
60
|
+
] }),
|
|
61
|
+
/* @__PURE__ */ jsx(EChart, { option, height: 320, onInst: (i) => instRef.current = i })
|
|
62
|
+
] });
|
|
45
63
|
}
|
|
46
64
|
if (rows.length === 0) {
|
|
47
65
|
return /* @__PURE__ */ jsx("div", { className: "cv-chart cv-chart--empty", children: "Waiting for data\u2026" });
|
|
@@ -78,6 +96,7 @@ function ChartRenderer({ artifact }) {
|
|
|
78
96
|
}
|
|
79
97
|
),
|
|
80
98
|
/* @__PURE__ */ jsx("span", { className: "cv-chart__spacer" }),
|
|
99
|
+
/* @__PURE__ */ jsx("button", { className: "cv-edit-btn", onClick: downloadPng, title: "Download as PNG", children: "\u2913 PNG" }),
|
|
81
100
|
/* @__PURE__ */ jsx("button", { className: `cv-edit-btn ${editing ? "is-primary" : ""}`, onClick: () => setEditing((v) => !v), children: editing ? "Done" : "Edit data" })
|
|
82
101
|
] }),
|
|
83
102
|
editing && /* @__PURE__ */ jsxs("div", { className: "cv-chart__editor cv-chrome", children: [
|
|
@@ -102,7 +121,7 @@ function ChartRenderer({ artifact }) {
|
|
|
102
121
|
] }),
|
|
103
122
|
/* @__PURE__ */ jsx(DataGrid, { rows, xKey, series, onCell: setCell, onAddRow: addRow, onRemoveRow: removeRow })
|
|
104
123
|
] }),
|
|
105
|
-
/* @__PURE__ */ jsx(EChart, { option, height: editing ? 260 : 340 })
|
|
124
|
+
/* @__PURE__ */ jsx(EChart, { option, height: editing ? 260 : 340, onInst: (i) => instRef.current = i })
|
|
106
125
|
] });
|
|
107
126
|
}
|
|
108
127
|
function DataGrid({
|
|
@@ -27,7 +27,7 @@ function snapAxis(pos, size, targets) {
|
|
|
27
27
|
}
|
|
28
28
|
return best ? { pos: pos + best.delta, guide: best.guide } : { pos, guide: null };
|
|
29
29
|
}
|
|
30
|
-
function FreeSlide({ elements, onChange }) {
|
|
30
|
+
function FreeSlide({ elements, onChange, padding }) {
|
|
31
31
|
const slideRef = useRef(null);
|
|
32
32
|
const [els, setEls] = useState(elements);
|
|
33
33
|
const [selected, setSelected] = useState(null);
|
|
@@ -136,6 +136,7 @@ function FreeSlide({ elements, onChange }) {
|
|
|
136
136
|
{
|
|
137
137
|
className: "cv-free",
|
|
138
138
|
ref: slideRef,
|
|
139
|
+
style: padding ? { inset: `${padding}%` } : void 0,
|
|
139
140
|
onPointerMove: onMove,
|
|
140
141
|
onPointerUp: onUp,
|
|
141
142
|
onPointerLeave: onUp,
|
|
@@ -200,10 +201,10 @@ function FreeSlide({ elements, onChange }) {
|
|
|
200
201
|
/* @__PURE__ */ jsx("button", { onClick: () => updateEl(el.id, { align: "center" }), title: "Align center", children: "\u2261" }),
|
|
201
202
|
/* @__PURE__ */ jsx("button", { onClick: () => updateEl(el.id, { align: "right" }), title: "Align right", children: "\u27F9" })
|
|
202
203
|
] }),
|
|
203
|
-
selected === el.id && el.type === "shape" && /* @__PURE__ */ jsx("div", { className: `cv-free__fmt ${el.y < 16 ? "cv-free__fmt--below" : ""}`, onPointerDown: (e) => e.stopPropagation(), onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx("input", { type: "color", value: el.fill ?? "#5b5bd6", onChange: (e) => updateEl(el.id, { fill: e.target.value }), title: "Fill color" }) }),
|
|
204
204
|
selected === el.id && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
205
205
|
/* @__PURE__ */ jsx("span", { className: "cv-free__resize", onPointerDown: (e) => onDown(e, el, "resize") }),
|
|
206
206
|
/* @__PURE__ */ jsxs("div", { className: `cv-free__ctl ${el.y < 16 ? "cv-free__ctl--below" : ""}`, onPointerDown: (e) => e.stopPropagation(), children: [
|
|
207
|
+
el.type === "shape" && /* @__PURE__ */ jsx("input", { className: "cv-free__ctl-fill", type: "color", value: el.fill ?? "#5b5bd6", onChange: (e) => updateEl(el.id, { fill: e.target.value }), onClick: (e) => e.stopPropagation(), title: "Fill color" }),
|
|
207
208
|
/* @__PURE__ */ jsx("button", { onClick: (e) => {
|
|
208
209
|
e.stopPropagation();
|
|
209
210
|
duplicate(el);
|
|
@@ -369,7 +370,7 @@ function SlidesRenderer({ artifact }) {
|
|
|
369
370
|
onDragEnd: () => setDragIndex(null),
|
|
370
371
|
children: /* @__PURE__ */ jsxs("button", { className: "cv-deck__thumb", onClick: () => setIndex(i), children: [
|
|
371
372
|
/* @__PURE__ */ jsx("span", { className: "cv-deck__thumb-n", children: i + 1 }),
|
|
372
|
-
/* @__PURE__ */ jsx("div", { className: "cv-deck__thumb-slide", style: s.background ? { background: s.background } : void 0, children: resolveElements(s).map(
|
|
373
|
+
/* @__PURE__ */ jsx("div", { className: "cv-deck__thumb-slide", style: s.background ? { background: s.background } : void 0, children: /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: `${s.padding ?? 0}%` }, children: resolveElements(s).map(
|
|
373
374
|
(el) => el.type === "text" ? /* @__PURE__ */ jsx(
|
|
374
375
|
"span",
|
|
375
376
|
{
|
|
@@ -378,7 +379,7 @@ function SlidesRenderer({ artifact }) {
|
|
|
378
379
|
},
|
|
379
380
|
el.id
|
|
380
381
|
) : el.type === "shape" ? /* @__PURE__ */ jsx("div", { style: { position: "absolute", left: `${el.x}%`, top: `${el.y}%`, width: `${el.w}%`, height: `${el.h}%`, color: s.textColor, ...shapeStyle(el) } }, el.id) : /* @__PURE__ */ jsx("img", { src: el.src, alt: "", style: { position: "absolute", left: `${el.x}%`, top: `${el.y}%`, width: `${el.w}%`, height: `${el.h}%`, objectFit: "contain" } }, el.id)
|
|
381
|
-
) })
|
|
382
|
+
) }) })
|
|
382
383
|
] })
|
|
383
384
|
},
|
|
384
385
|
i
|
|
@@ -442,6 +443,10 @@ function SlidesRenderer({ artifact }) {
|
|
|
442
443
|
),
|
|
443
444
|
/* @__PURE__ */ jsx("label", { className: "cv-deck__bg", title: "Background color", children: /* @__PURE__ */ jsx("input", { type: "color", value: /^#/.test(slide.background ?? "") ? slide.background : "#ffffff", onChange: (e) => update({ background: e.target.value }) }) }),
|
|
444
445
|
/* @__PURE__ */ jsx("button", { onClick: () => bgRef.current?.click(), title: "Background image", children: "\u{1F5BC} BG" }),
|
|
446
|
+
/* @__PURE__ */ jsxs("label", { className: "cv-deck__pad", title: "Content padding (% of slide)", children: [
|
|
447
|
+
"Pad",
|
|
448
|
+
/* @__PURE__ */ jsx("input", { type: "number", min: 0, max: 20, value: slide.padding ?? 0, onChange: (e) => update({ padding: Number(e.target.value) || void 0 }) })
|
|
449
|
+
] }),
|
|
445
450
|
/* @__PURE__ */ jsx("span", { className: "cv-deck__spacer" }),
|
|
446
451
|
/* @__PURE__ */ jsx("button", { className: "cv-deck__present", onClick: () => setPresenting(true), title: "Present (full screen)", children: "\u25B6 Present" }),
|
|
447
452
|
/* @__PURE__ */ jsx("button", { onClick: () => moveSlide(-1), title: "Move up", disabled: at === 0, children: "\u25B2" }),
|
|
@@ -449,7 +454,7 @@ function SlidesRenderer({ artifact }) {
|
|
|
449
454
|
/* @__PURE__ */ jsx("button", { onClick: duplicateSlide, title: "Duplicate slide", children: "\u29C9" }),
|
|
450
455
|
/* @__PURE__ */ jsx("button", { onClick: deleteSlide, title: "Delete slide", disabled: slides.length === 1, children: "\u{1F5D1}" })
|
|
451
456
|
] }),
|
|
452
|
-
/* @__PURE__ */ jsx("div", { className: "cv-slide cv-slide--blank", style: slideStyle, children: /* @__PURE__ */ jsx(FreeSlide, { elements: resolveElements(slide), onChange: (elements) => update({ elements }) }) }),
|
|
457
|
+
/* @__PURE__ */ jsx("div", { className: "cv-slide cv-slide--blank", style: slideStyle, children: /* @__PURE__ */ jsx(FreeSlide, { elements: resolveElements(slide), onChange: (elements) => update({ elements }), padding: slide.padding }) }),
|
|
453
458
|
/* @__PURE__ */ jsxs("div", { className: "cv-deck__nav cv-chrome", children: [
|
|
454
459
|
/* @__PURE__ */ jsx("button", { disabled: at === 0, onClick: () => setIndex(at - 1), "aria-label": "Previous slide", children: "\u2039" }),
|
|
455
460
|
/* @__PURE__ */ jsxs("span", { children: [
|
|
@@ -470,7 +475,7 @@ function SlidesRenderer({ artifact }) {
|
|
|
470
475
|
)
|
|
471
476
|
] }),
|
|
472
477
|
presenting && /* @__PURE__ */ jsxs("div", { className: "cv-present", onClick: () => setIndex(Math.min(at + 1, slides.length - 1)), children: [
|
|
473
|
-
/* @__PURE__ */ jsx("div", { className: "cv-present__slide cv-present__fade cv-slide cv-slide--blank", style: slideStyle, children: /* @__PURE__ */ jsx("div", { className: "cv-free", children: resolveElements(slide).map(
|
|
478
|
+
/* @__PURE__ */ jsx("div", { className: "cv-present__slide cv-present__fade cv-slide cv-slide--blank", style: slideStyle, children: /* @__PURE__ */ jsx("div", { className: "cv-free", style: slide.padding ? { inset: `${slide.padding}%` } : void 0, children: resolveElements(slide).map(
|
|
474
479
|
(el) => el.type === "text" ? /* @__PURE__ */ jsx("div", { className: "cv-free__el", style: { left: `${el.x}%`, top: `${el.y}%`, width: `${el.w}%`, height: `${el.h}%` }, children: /* @__PURE__ */ jsx("div", { className: "cv-free__text", style: { fontSize: el.fontSize ?? 24, fontWeight: el.bold ? 700 : 400, color: el.color, textAlign: el.align ?? "left", whiteSpace: "pre-wrap" }, children: el.text }) }, el.id) : el.type === "shape" ? /* @__PURE__ */ jsx("div", { className: "cv-free__el", style: { left: `${el.x}%`, top: `${el.y}%`, width: `${el.w}%`, height: `${el.h}%`, color: slide.textColor }, children: /* @__PURE__ */ jsx("div", { style: shapeStyle(el) }) }, el.id) : /* @__PURE__ */ jsx("div", { className: "cv-free__el", style: { left: `${el.x}%`, top: `${el.y}%`, width: `${el.w}%`, height: `${el.h}%` }, children: /* @__PURE__ */ jsx("img", { className: "cv-free__img", src: el.src, alt: "" }) }, el.id)
|
|
475
480
|
) }) }, at),
|
|
476
481
|
slide.notes ? /* @__PURE__ */ jsx("div", { className: "cv-present__notes", onClick: (e) => e.stopPropagation(), children: slide.notes }) : null,
|
|
@@ -2,7 +2,7 @@ import { loadOptional } from './chunk-YZZSJJMQ.js';
|
|
|
2
2
|
import { useCanvasStore } from './chunk-KKLWKR5G.js';
|
|
3
3
|
import { lazy, useMemo, useState, useRef, useEffect, useCallback, Suspense } from 'react';
|
|
4
4
|
import '@fortune-sheet/react/dist/index.css';
|
|
5
|
-
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
5
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
6
6
|
|
|
7
7
|
// src/io/formula.ts
|
|
8
8
|
var EMPTY = /* @__PURE__ */ new Map();
|
|
@@ -203,10 +203,34 @@ function TableRenderer({ artifact }) {
|
|
|
203
203
|
};
|
|
204
204
|
}, [dataKey, hasFormulas]);
|
|
205
205
|
const hasSheet = !!artifact.data.sheet?.length;
|
|
206
|
+
const [sortCol, setSortCol] = useState("");
|
|
207
|
+
const [sortDir, setSortDir] = useState(1);
|
|
208
|
+
const [filter, setFilter] = useState("");
|
|
209
|
+
const [appliedFilter, setAppliedFilter] = useState("");
|
|
210
|
+
useEffect(() => {
|
|
211
|
+
const t = setTimeout(() => setAppliedFilter(filter), 300);
|
|
212
|
+
return () => clearTimeout(t);
|
|
213
|
+
}, [filter]);
|
|
214
|
+
const viewRows = useMemo(() => {
|
|
215
|
+
let r = rows;
|
|
216
|
+
const q = appliedFilter.trim().toLowerCase();
|
|
217
|
+
if (q) r = r.filter((row) => columns.some((c) => String(row[c.key] ?? "").toLowerCase().includes(q)));
|
|
218
|
+
if (sortCol) {
|
|
219
|
+
r = [...r].sort((a, b) => {
|
|
220
|
+
const av = a[sortCol];
|
|
221
|
+
const bv = b[sortCol];
|
|
222
|
+
const cmp = typeof av === "number" && typeof bv === "number" ? av - bv : String(av ?? "").localeCompare(String(bv ?? ""));
|
|
223
|
+
return cmp * sortDir;
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
return r;
|
|
227
|
+
}, [rows, columns, appliedFilter, sortCol, sortDir]);
|
|
228
|
+
const viewActive = !!appliedFilter.trim() || !!sortCol;
|
|
229
|
+
const wbKey = `${dataKey}:${viewActive ? `view-s${sortCol}${sortDir}-f${appliedFilter}` : hasSheet ? "sheet" : "rows"}`;
|
|
206
230
|
const initialData = useMemo(
|
|
207
|
-
() =>
|
|
231
|
+
() => viewActive ? toWorkbook(columns, viewRows, formulas) : hasSheet ? artifact.data.sheet : toWorkbook(columns, rows, formulas),
|
|
208
232
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
209
|
-
[
|
|
233
|
+
[wbKey, formulasReady]
|
|
210
234
|
);
|
|
211
235
|
const applyEvent = useCanvasStore((s) => s.applyUserEvent);
|
|
212
236
|
const persistTimer = useRef(null);
|
|
@@ -241,9 +265,36 @@ function TableRenderer({ artifact }) {
|
|
|
241
265
|
/* @__PURE__ */ jsxs("div", { className: "cv-sheet-tools", children: [
|
|
242
266
|
/* @__PURE__ */ jsx("button", { type: "button", onClick: () => insert("column"), children: "\uFF0B Column" }),
|
|
243
267
|
/* @__PURE__ */ jsx("button", { type: "button", onClick: () => insert("row"), children: "\uFF0B Row" }),
|
|
268
|
+
columns.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
269
|
+
/* @__PURE__ */ jsx("span", { className: "cv-sheet-tools__sep" }),
|
|
270
|
+
/* @__PURE__ */ jsxs(
|
|
271
|
+
"select",
|
|
272
|
+
{
|
|
273
|
+
className: "cv-sheet-tools__sort",
|
|
274
|
+
value: sortCol,
|
|
275
|
+
title: "Sort by column",
|
|
276
|
+
onChange: (e) => setSortCol(e.target.value),
|
|
277
|
+
children: [
|
|
278
|
+
/* @__PURE__ */ jsx("option", { value: "", children: "Sort\u2026" }),
|
|
279
|
+
columns.map((c) => /* @__PURE__ */ jsx("option", { value: c.key, children: c.label ?? c.key }, c.key))
|
|
280
|
+
]
|
|
281
|
+
}
|
|
282
|
+
),
|
|
283
|
+
sortCol && /* @__PURE__ */ jsx("button", { type: "button", title: sortDir === 1 ? "Ascending" : "Descending", onClick: () => setSortDir((d) => d === 1 ? -1 : 1), children: sortDir === 1 ? "\u25B2" : "\u25BC" }),
|
|
284
|
+
/* @__PURE__ */ jsx(
|
|
285
|
+
"input",
|
|
286
|
+
{
|
|
287
|
+
className: "cv-sheet-tools__filter",
|
|
288
|
+
value: filter,
|
|
289
|
+
placeholder: "Filter\u2026",
|
|
290
|
+
onChange: (e) => setFilter(e.target.value),
|
|
291
|
+
title: "Filter rows"
|
|
292
|
+
}
|
|
293
|
+
)
|
|
294
|
+
] }),
|
|
244
295
|
/* @__PURE__ */ jsx("span", { className: "cv-sheet-tools__hint", children: "Right-click a header for more, or drag to edit" })
|
|
245
296
|
] }),
|
|
246
|
-
/* @__PURE__ */ jsx("div", { className: "cv-sheet", ref: rootRef, children: /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx("div", { className: "cv-sheet--empty", children: "Loading\u2026" }), children: /* @__PURE__ */ jsx(Workbook, { ref: wbRef, data: initialData, onChange: handleChange },
|
|
297
|
+
/* @__PURE__ */ jsx("div", { className: "cv-sheet", ref: rootRef, children: /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx("div", { className: "cv-sheet--empty", children: "Loading\u2026" }), children: /* @__PURE__ */ jsx(Workbook, { ref: wbRef, data: initialData, onChange: handleChange }, wbKey) }) })
|
|
247
298
|
] });
|
|
248
299
|
}
|
|
249
300
|
|
package/dist/index.d.ts
CHANGED
|
@@ -119,6 +119,9 @@ interface Slide {
|
|
|
119
119
|
textColor?: string;
|
|
120
120
|
/** Speaker notes (not shown on the slide; exported to the .pptx notes pane). */
|
|
121
121
|
notes?: string;
|
|
122
|
+
/** Content padding as a percent of the slide width (a safe margin around the
|
|
123
|
+
* free canvas). Applied in the editor, present view, thumbnails, and export. */
|
|
124
|
+
padding?: number;
|
|
122
125
|
}
|
|
123
126
|
interface SlidesData {
|
|
124
127
|
slides: Slide[];
|
package/dist/index.js
CHANGED
|
@@ -2111,10 +2111,10 @@ function HtmlRenderer({ artifact: artifact2 }) {
|
|
|
2111
2111
|
}
|
|
2112
2112
|
|
|
2113
2113
|
// src/components/renderers/index.ts
|
|
2114
|
-
var ChartRenderer = lazy(() => import('./ChartRenderer-
|
|
2114
|
+
var ChartRenderer = lazy(() => import('./ChartRenderer-FX6ZN4NC.js').then((m) => ({ default: m.ChartRenderer })));
|
|
2115
2115
|
var DocumentRenderer = lazy(() => import('./DocumentRenderer-KJ6FTGKH.js').then((m) => ({ default: m.DocumentRenderer })));
|
|
2116
|
-
var TableRenderer = lazy(() => import('./TableRenderer-
|
|
2117
|
-
var SlidesRenderer = lazy(() => import('./SlidesRenderer-
|
|
2116
|
+
var TableRenderer = lazy(() => import('./TableRenderer-Y4JFRSLU.js').then((m) => ({ default: m.TableRenderer })));
|
|
2117
|
+
var SlidesRenderer = lazy(() => import('./SlidesRenderer-SK5VQDIL.js').then((m) => ({ default: m.SlidesRenderer })));
|
|
2118
2118
|
var builtinRenderers = {
|
|
2119
2119
|
html: HtmlRenderer,
|
|
2120
2120
|
document: DocumentRenderer,
|
|
@@ -2255,8 +2255,10 @@ async function slidesToPptx(data, _title) {
|
|
|
2255
2255
|
const s = pptx.addSlide();
|
|
2256
2256
|
if (slide.background && /^#[0-9a-f]{3,8}$/i.test(slide.background)) s.background = { color: slide.background.replace("#", "") };
|
|
2257
2257
|
const tc = slide.textColor ? slide.textColor.replace("#", "") : void 0;
|
|
2258
|
+
const pad = (slide.padding ?? 0) / 100;
|
|
2259
|
+
const inset = (v) => pad + v / 100 * (1 - 2 * pad);
|
|
2258
2260
|
for (const el of resolveElements(slide)) {
|
|
2259
|
-
const box = { x: el.x
|
|
2261
|
+
const box = { x: inset(el.x) * W, y: inset(el.y) * H, w: el.w / 100 * (1 - 2 * pad) * W, h: el.h / 100 * (1 - 2 * pad) * H };
|
|
2260
2262
|
if (el.type === "text") {
|
|
2261
2263
|
const color = el.color ? el.color.replace("#", "") : tc;
|
|
2262
2264
|
s.addText(el.text ?? "", { ...box, fontSize: (el.fontSize ?? 24) * 0.75, bold: !!el.bold, align: el.align ?? "left", ...color ? { color } : {} });
|
|
@@ -2294,7 +2296,9 @@ function slidesToPrintHtml(data, title) {
|
|
|
2294
2296
|
const src = safeSrc(el.src);
|
|
2295
2297
|
return src ? `<img class="el" style="${box}" src="${escapeAttr(src)}"/>` : "";
|
|
2296
2298
|
}).join("");
|
|
2297
|
-
|
|
2299
|
+
const pad = slide.padding ?? 0;
|
|
2300
|
+
const inner = pad ? `<div style="position:absolute;inset:${pad}%">${els}</div>` : els;
|
|
2301
|
+
return `<section class="slide" style="background:${escapeAttr(bg)}">${inner}</section>`;
|
|
2298
2302
|
}).join("");
|
|
2299
2303
|
return `<!doctype html><html><head><meta charset="utf-8"><title>${escapeXml(title)}</title><style>
|
|
2300
2304
|
@page { size: 1280px 720px; margin: 0; }
|
package/dist/styles.css
CHANGED
|
@@ -396,6 +396,13 @@
|
|
|
396
396
|
border-radius: 6px; background: var(--cv-bg); color: var(--cv-text); cursor: pointer;
|
|
397
397
|
}
|
|
398
398
|
.cv-sheet-tools button:hover { border-color: var(--cv-accent, #6366f1); color: var(--cv-accent, #6366f1); }
|
|
399
|
+
.cv-sheet-tools__sep { width: 1px; height: 18px; background: var(--cv-border); margin: 0 2px; }
|
|
400
|
+
.cv-sheet-tools__sort, .cv-sheet-tools__filter {
|
|
401
|
+
font: inherit; font-size: 12.5px; padding: 4px 8px; border-radius: 6px;
|
|
402
|
+
border: 1px solid var(--cv-border); background: var(--cv-bg); color: var(--cv-text);
|
|
403
|
+
}
|
|
404
|
+
.cv-sheet-tools__filter { min-width: 96px; max-width: 160px; }
|
|
405
|
+
.cv-sheet-tools__sort:focus, .cv-sheet-tools__filter:focus { outline: none; border-color: var(--cv-accent); }
|
|
399
406
|
.cv-sheet-tools__hint { margin-left: auto; font-size: 11px; color: var(--cv-muted); }
|
|
400
407
|
.cv-sheet { position: relative; width: 100%; flex: 1; height: auto; min-height: 0; }
|
|
401
408
|
.cv-sheet .fortune-container { height: 100% !important; width: 100% !important; }
|
|
@@ -611,6 +618,13 @@
|
|
|
611
618
|
width: 30px; height: 30px; padding: 0;
|
|
612
619
|
border: 1px solid var(--cv-border); border-radius: 7px; background: none; cursor: pointer;
|
|
613
620
|
}
|
|
621
|
+
.cv-deck__pad {
|
|
622
|
+
display: inline-flex; align-items: center; gap: 5px; font-size: 12px; color: var(--cv-muted);
|
|
623
|
+
}
|
|
624
|
+
.cv-deck__pad input {
|
|
625
|
+
width: 48px; font: inherit; font-size: 12.5px; padding: 4px 6px;
|
|
626
|
+
border: 1px solid var(--cv-border); border-radius: 6px; background: var(--cv-bg); color: var(--cv-text);
|
|
627
|
+
}
|
|
614
628
|
.cv-deck__present {
|
|
615
629
|
width: auto !important; padding: 0 12px !important;
|
|
616
630
|
background: var(--cv-accent) !important; color: #fff !important;
|
package/package.json
CHANGED