likec4 1.54.0 → 1.55.1
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/__app__/src/likec4.js +56 -27
- package/__app__/src/routes/index.js +2 -2
- package/__app__/src/routes/projects.js +7 -3
- package/__app__/src/routes/single.js +73 -14
- package/__app__/src/style.css +1 -1
- package/__app__/src/vendors.js +46 -35
- package/__app__/src/webcomponent.js +1 -1
- package/dist/THIRD-PARTY-LICENSES.md +3 -69
- package/dist/_chunks/index.d.mts +1 -1
- package/dist/_chunks/index2.d.mts +11 -21
- package/dist/_chunks/libs/@hono/mcp.mjs +1 -1
- package/dist/_chunks/libs/@modelcontextprotocol/sdk.mjs +8 -8
- package/dist/_chunks/libs/ajv.mjs +1 -1
- package/dist/_chunks/libs/atomically.mjs +1 -1
- package/dist/_chunks/libs/conf.mjs +1 -1
- package/dist/_chunks/libs/find-up-simple.mjs +1 -1
- package/dist/_chunks/libs/p-timeout.mjs +1 -0
- package/dist/_chunks/libs/package-manager-detector.mjs +1 -1
- package/dist/_chunks/libs/pathe.mjs +1 -1
- package/dist/_chunks/libs/tinyrainbow.mjs +1 -1
- package/dist/_chunks/libs/zod.d.mts +2091 -0
- package/dist/_chunks/node.mjs +76 -1
- package/dist/_chunks/src2.mjs +58 -58
- package/dist/cli/index.mjs +1242 -98
- package/dist/config/index.d.mts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/vite-plugin/index.d.mts +1 -1
- package/dist/vite-plugin/index.mjs +1 -1
- package/dist/vite-plugin/internal.mjs +1 -1
- package/package.json +25 -24
- package/react/index.mjs +87 -51
- package/dist/_chunks/filesystem.mjs +0 -1229
- package/dist/_chunks/libs/@modelcontextprotocol/sdk.d.mts +0 -9325
package/__app__/src/likec4.js
CHANGED
|
@@ -6049,8 +6049,8 @@ function EdgeLabelContainer({
|
|
|
6049
6049
|
},
|
|
6050
6050
|
labelPosition: labelXY,
|
|
6051
6051
|
className,
|
|
6052
|
-
style:
|
|
6053
|
-
//
|
|
6052
|
+
style: contentStyle,
|
|
6053
|
+
// applied to inner content div, not the positioned container
|
|
6054
6054
|
children,
|
|
6055
6055
|
...rest
|
|
6056
6056
|
}) {
|
|
@@ -6086,9 +6086,10 @@ function EdgeLabelContainer({
|
|
|
6086
6086
|
children: /* @__PURE__ */ jsx(
|
|
6087
6087
|
"div",
|
|
6088
6088
|
{
|
|
6089
|
-
style:
|
|
6090
|
-
|
|
6091
|
-
|
|
6089
|
+
style: {
|
|
6090
|
+
...contentStyle,
|
|
6091
|
+
...labelBBox && { maxWidth: labelBBox.width + 20 }
|
|
6092
|
+
},
|
|
6092
6093
|
children
|
|
6093
6094
|
}
|
|
6094
6095
|
)
|
|
@@ -9079,9 +9080,11 @@ const useElementDetailsActorRef = () => {
|
|
|
9079
9080
|
fontStyle: "normal",
|
|
9080
9081
|
fontWeight: "bold",
|
|
9081
9082
|
fontSize: "24px",
|
|
9082
|
-
|
|
9083
|
-
|
|
9084
|
-
|
|
9083
|
+
lineHeight: "xs",
|
|
9084
|
+
overflow: "hidden",
|
|
9085
|
+
textOverflow: "ellipsis",
|
|
9086
|
+
wordBreak: "break-word",
|
|
9087
|
+
lineClamp: 2
|
|
9085
9088
|
}), iconSize$1 = "40px", elementIcon$1 = css({
|
|
9086
9089
|
flex: `0 0 ${iconSize$1}`,
|
|
9087
9090
|
height: iconSize$1,
|
|
@@ -10888,20 +10891,29 @@ function ElementDetailsCard({
|
|
|
10888
10891
|
children: [
|
|
10889
10892
|
/* @__PURE__ */ jsxs("div", { className: cardHeader, onPointerDown: (e2) => controls.start(e2), children: [
|
|
10890
10893
|
/* @__PURE__ */ jsxs(HStack, { alignItems: "start", justify: "space-between", gap: "sm", mb: "sm", flexWrap: "nowrap", children: [
|
|
10891
|
-
/* @__PURE__ */ jsxs(
|
|
10892
|
-
|
|
10893
|
-
|
|
10894
|
-
|
|
10895
|
-
|
|
10896
|
-
|
|
10897
|
-
|
|
10898
|
-
|
|
10899
|
-
|
|
10900
|
-
}
|
|
10901
|
-
|
|
10902
|
-
|
|
10903
|
-
|
|
10904
|
-
|
|
10894
|
+
/* @__PURE__ */ jsxs(
|
|
10895
|
+
HStack,
|
|
10896
|
+
{
|
|
10897
|
+
alignItems: "start",
|
|
10898
|
+
gap: "sm",
|
|
10899
|
+
style: { cursor: "default", minWidth: 0, overflow: "hidden" },
|
|
10900
|
+
flexWrap: "nowrap",
|
|
10901
|
+
children: [
|
|
10902
|
+
elementIcon2,
|
|
10903
|
+
/* @__PURE__ */ jsxs("div", { style: { minWidth: 0, overflow: "hidden" }, children: [
|
|
10904
|
+
/* @__PURE__ */ jsx(Tooltip$2, { label: elementModel.title, openDelay: 600, position: "bottom-start", children: /* @__PURE__ */ jsx(
|
|
10905
|
+
Text,
|
|
10906
|
+
{
|
|
10907
|
+
component: "div",
|
|
10908
|
+
className: title$1,
|
|
10909
|
+
children: elementModel.title
|
|
10910
|
+
}
|
|
10911
|
+
) }),
|
|
10912
|
+
notation && /* @__PURE__ */ jsx(Text, { component: "div", c: "dimmed", fz: "sm", fw: 500, lh: 1.3, lineClamp: 1, children: notation })
|
|
10913
|
+
] })
|
|
10914
|
+
]
|
|
10915
|
+
}
|
|
10916
|
+
),
|
|
10905
10917
|
/* @__PURE__ */ jsx(CloseButton, { size: "lg", onClick: triggerClose })
|
|
10906
10918
|
] }),
|
|
10907
10919
|
/* @__PURE__ */ jsxs(HStack, { alignItems: "baseline", gap: "sm", flexWrap: "nowrap", children: [
|
|
@@ -10924,7 +10936,7 @@ function ElementDetailsCard({
|
|
|
10924
10936
|
}
|
|
10925
10937
|
)
|
|
10926
10938
|
] }),
|
|
10927
|
-
/* @__PURE__ */ jsxs("div", { style: { flex: 1 }, children: [
|
|
10939
|
+
/* @__PURE__ */ jsxs("div", { style: { flex: 1, minWidth: 0, overflow: "hidden" }, children: [
|
|
10928
10940
|
/* @__PURE__ */ jsx(SmallLabel, { children: "tags" }),
|
|
10929
10941
|
/* @__PURE__ */ jsx(
|
|
10930
10942
|
ElementTags$2,
|
|
@@ -11199,6 +11211,10 @@ const backdropBlur = "--_blur", backdropOpacity = "--_opacity", cssVarLevel = "-
|
|
|
11199
11211
|
);
|
|
11200
11212
|
useLayoutEffect(() => {
|
|
11201
11213
|
dialogRef.current?.open || dialogRef.current?.showModal();
|
|
11214
|
+
const dialog2 = dialogRef.current;
|
|
11215
|
+
return () => {
|
|
11216
|
+
dialog2?.open && (isClosingRef.current = !0, dialog2.close());
|
|
11217
|
+
};
|
|
11202
11218
|
}, []), useTimeoutEffect(() => {
|
|
11203
11219
|
setOpened(!0);
|
|
11204
11220
|
}, openDelay > 0 ? openDelay : void 0);
|
|
@@ -11564,7 +11580,7 @@ const Sizes = {
|
|
|
11564
11580
|
},
|
|
11565
11581
|
edgeLabel: {
|
|
11566
11582
|
width: 220,
|
|
11567
|
-
height:
|
|
11583
|
+
height: 55
|
|
11568
11584
|
// minlen: 1,
|
|
11569
11585
|
},
|
|
11570
11586
|
nodeWidth: 330,
|
|
@@ -13597,6 +13613,9 @@ const _actorLogic = setup({
|
|
|
13597
13613
|
size: "xxs",
|
|
13598
13614
|
fontWeight: "medium",
|
|
13599
13615
|
whiteSpace: "nowrap",
|
|
13616
|
+
overflow: "hidden",
|
|
13617
|
+
textOverflow: "ellipsis",
|
|
13618
|
+
maxWidth: "160px",
|
|
13600
13619
|
paddingX: "1",
|
|
13601
13620
|
paddingY: "0.5",
|
|
13602
13621
|
rounded: "xs",
|
|
@@ -13616,7 +13635,10 @@ const _actorLogic = setup({
|
|
|
13616
13635
|
whiteSpaceCollapse: "preserve-breaks",
|
|
13617
13636
|
fontSize: "sm",
|
|
13618
13637
|
lineHeight: "sm",
|
|
13619
|
-
userSelect: "all"
|
|
13638
|
+
userSelect: "all",
|
|
13639
|
+
overflowWrap: "anywhere",
|
|
13640
|
+
wordBreak: "break-word",
|
|
13641
|
+
minWidth: 0
|
|
13620
13642
|
}
|
|
13621
13643
|
});
|
|
13622
13644
|
function selectDiagramContext(c) {
|
|
@@ -14016,11 +14038,18 @@ const RelationshipPopover = memo$1(() => {
|
|
|
14016
14038
|
] }),
|
|
14017
14039
|
r2.kind && /* @__PURE__ */ jsxs(HStack, { gap: "2", children: [
|
|
14018
14040
|
/* @__PURE__ */ jsx(Label$2, { children: "kind" }),
|
|
14019
|
-
/* @__PURE__ */ jsx(Text, { size: "xs", className: css({ userSelect: "all" }), children: r2.kind })
|
|
14041
|
+
/* @__PURE__ */ jsx(Text, { size: "xs", className: css({ userSelect: "all", wordBreak: "break-word", minWidth: 0 }), children: r2.kind })
|
|
14020
14042
|
] }),
|
|
14021
14043
|
r2.technology && /* @__PURE__ */ jsxs(HStack, { gap: "2", children: [
|
|
14022
14044
|
/* @__PURE__ */ jsx(Label$2, { children: "technology" }),
|
|
14023
|
-
/* @__PURE__ */ jsx(
|
|
14045
|
+
/* @__PURE__ */ jsx(
|
|
14046
|
+
Text,
|
|
14047
|
+
{
|
|
14048
|
+
size: "xs",
|
|
14049
|
+
className: css({ userSelect: "all", wordBreak: "break-word", minWidth: 0 }),
|
|
14050
|
+
children: r2.technology
|
|
14051
|
+
}
|
|
14052
|
+
)
|
|
14024
14053
|
] }),
|
|
14025
14054
|
r2.summary.nonEmpty && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
14026
14055
|
/* @__PURE__ */ jsx(Label$2, { children: "description" }),
|
|
@@ -110,12 +110,12 @@ const theme = createTheme({
|
|
|
110
110
|
component: RootComponent
|
|
111
111
|
});
|
|
112
112
|
function RootComponent() {
|
|
113
|
-
const { theme: theme$1 } = Route$2.useSearch(), forceColorScheme = resolveForceColorScheme(theme$1);
|
|
113
|
+
const { theme: theme$1 } = Route$2.useSearch(), forceColorScheme = resolveForceColorScheme(theme$1), defaultColorScheme = theme$1 === "auto" ? "auto" : __DEFAULT_THEME__;
|
|
114
114
|
return /* @__PURE__ */ jsx(
|
|
115
115
|
MantineProvider,
|
|
116
116
|
{
|
|
117
117
|
theme,
|
|
118
|
-
defaultColorScheme
|
|
118
|
+
defaultColorScheme,
|
|
119
119
|
...forceColorScheme && { forceColorScheme },
|
|
120
120
|
children: /* @__PURE__ */ jsx(Outlet, {})
|
|
121
121
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { d1 as createFileRoute, db as Container, bp as Stack, bZ as Title, W as Button, df as Link,
|
|
2
|
+
import { d1 as createFileRoute, db as Container, bp as Stack, bZ as Title, W as Button, df as Link, dH as notFound, d2 as redirect, Q as m, d0 as Outlet, dI as Navigate, c$ as stripSearchParams, cZ as z } from "../vendors.js";
|
|
3
3
|
import { loadModel } from "likec4:model";
|
|
4
4
|
import { V as ViewOutlet, F as Fallback, L as LikeC4IconRendererContext, l as LikeC4ModelContext, A as AdHocViewEditor, H as Header, E as ExportPage, m as EmbedPage, n as ViewEditor, o as ViewReact, p as ViewAsPuml, q as ViewAsMmd, r as ViewAsDot, s as ViewAsD2 } from "./single.js";
|
|
5
5
|
import { isRpcAvailable } from "likec4:rpc";
|
|
@@ -84,12 +84,16 @@ function ViewLayout() {
|
|
|
84
84
|
}
|
|
85
85
|
const Route$6 = createFileRoute("/project/$projectId/export/$viewId")({
|
|
86
86
|
validateSearch: z.object({
|
|
87
|
-
download: z.boolean().optional().catch(!1)
|
|
87
|
+
download: z.boolean().optional().catch(!1),
|
|
88
|
+
format: z.enum(["png", "jpeg"]).optional().catch("png"),
|
|
89
|
+
quality: z.number().min(0).max(1).optional().catch(void 0)
|
|
88
90
|
}),
|
|
89
91
|
search: {
|
|
90
92
|
middlewares: [
|
|
91
93
|
stripSearchParams({
|
|
92
|
-
download: !1
|
|
94
|
+
download: !1,
|
|
95
|
+
format: "png",
|
|
96
|
+
quality: void 0
|
|
93
97
|
})
|
|
94
98
|
]
|
|
95
99
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { d8 as useRouter, d9 as useParams, da as isNotFound, db as Container, br as Alert, U as Text, dc as Code, W as Button, dd as e, de as e$1, as as e$2, bt as Group, bh as rem, df as Link, bZ as Title, d1 as createFileRoute, Q as m, d0 as Outlet, k as useMantineColorScheme, dg as useComputedColorScheme, cY as useNavigate, aA as ActionIcon, c9 as useHotkeys, aI as AnimatePresence, d as deepEqual, s as shallowEqual, dh as useMatches, di as useIsomorphicLayoutEffect, a9 as r, dj as onMount, v as useStore$1, r as atom, bq as useTree, bs as Tree, b6 as HoverCard, b7 as HoverCardTarget, b8 as HoverCardDropdown, R as ThemeIcon, ch as useLocalStorage, dk as Drawer, bP as ScrollArea, S as SegmentedControl, d3 as useDocumentTitle, dl as Burger, dm as SimpleGrid, dn as useInViewport, dp as e$3, ci as Card, aQ as Box$1, d2 as redirect, aF as MotionDiv, cN as isValidMotionProp, aD as Menu, bc as MenuTarget, bd as MenuDropdown, be as MenuItem, dq as MenuDivider, bp as Stack, b5 as CopyButton$1, dr as Select, ds as ModalRoot, dt as ModalOverlay, du as ModalContent, dv as ModalBody, bL as Tabs, bM as TabsList, bN as TabsTab, bO as TabsPanel, dw as useMantineTheme, dx as useMediaQuery, cq as useDisclosure, aG as Divider, dy as MenuLabel, dz as useSearch, dA as LoadingOverlay, dB as toBlob, c$ as stripSearchParams, cZ as z, bS as useCallbackRef, aL as useIsMounted, T as Tooltip,
|
|
2
|
+
import { d8 as useRouter, d9 as useParams, da as isNotFound, db as Container, br as Alert, U as Text, dc as Code, W as Button, dd as e, de as e$1, as as e$2, bt as Group, bh as rem, df as Link, bZ as Title, d1 as createFileRoute, Q as m, d0 as Outlet, k as useMantineColorScheme, dg as useComputedColorScheme, cY as useNavigate, aA as ActionIcon, c9 as useHotkeys, aI as AnimatePresence, d as deepEqual, s as shallowEqual, dh as useMatches, di as useIsomorphicLayoutEffect, a9 as r, dj as onMount, v as useStore$1, r as atom, bq as useTree, bs as Tree, b6 as HoverCard, b7 as HoverCardTarget, b8 as HoverCardDropdown, R as ThemeIcon, ch as useLocalStorage, dk as Drawer, bP as ScrollArea, S as SegmentedControl, d3 as useDocumentTitle, dl as Burger, dm as SimpleGrid, dn as useInViewport, dp as e$3, ci as Card, aQ as Box$1, d2 as redirect, aF as MotionDiv, cN as isValidMotionProp, aD as Menu, bc as MenuTarget, bd as MenuDropdown, be as MenuItem, dq as MenuDivider, bp as Stack, b5 as CopyButton$1, dr as Select, ds as ModalRoot, dt as ModalOverlay, du as ModalContent, dv as ModalBody, bL as Tabs, bM as TabsList, bN as TabsTab, bO as TabsPanel, dw as useMantineTheme, dx as useMediaQuery, cq as useDisclosure, aG as Divider, dy as MenuLabel, dz as useSearch, dA as LoadingOverlay, dB as toJpeg, dC as toBlob, c$ as stripSearchParams, cZ as z, bS as useCallbackRef, aL as useIsMounted, T as Tooltip, dD as useAsync, dE as Ut, dF as qt, dG as Zt, dH as notFound } from "../vendors.js";
|
|
3
3
|
import { loadModel } from "likec4:model";
|
|
4
4
|
import { c as css, s as styled, I as IconRendererProvider, a as LikeC4ModelProvider, b as IconMoonStars, d as IconSun, n as normalizeSearch, S as SearchContext, e as SearchControl, F as FramerMotionConfig, O as Overlay, f as bodyCss, g as dialogCss, h as SearchPanelContent, u as useUpdateEffect, i as useLikeC4Model, j as StaticLikeC4Diagram, B as Box, k as IconStarFilled, l as IconStack2, m as IconLayoutDashboard, o as IconFileCode, p as IconFolderOpen, q as IconFolderFilled, r as IconArrowLeft, N as NavigationPanel$1, M as Markdown, t as LikeC4AdHocViewEditor, v as createStyleContext, w as navigationPanel, x as isCssProperty, y as useLikeC4Projects$1, z as IconChevronDown, A as IconAlertTriangle, C as IconCheck, D as IconCopy, E as IconExternalLink, G as IconShare, H as pickViewBounds, J as LikeC4Diagram, K as useDiagramContext, P as useDiagram, Q as useOnDiagramEvent, R as LikeC4EditorProvider } from "../likec4.js";
|
|
5
5
|
import { getProjectIcons } from "likec4:icons";
|
|
@@ -262,14 +262,19 @@ function OverviewSearchAdapter({
|
|
|
262
262
|
return /* @__PURE__ */ jsx(SearchContext.Provider, { value, children });
|
|
263
263
|
}
|
|
264
264
|
const OverviewSearch = memo(() => {
|
|
265
|
-
const [isOpened, setIsOpened] = useState(!1), open = useCallback(() => setIsOpened(!0), []), close = useCallback(() => setIsOpened(!1), [])
|
|
265
|
+
const [isOpened, setIsOpened] = useState(!1), dialogElRef = useRef(null), open = useCallback(() => setIsOpened(!0), []), close = useCallback(() => setIsOpened(!1), []), captureDialogRef = useCallback((node) => {
|
|
266
|
+
node && (dialogElRef.current = node);
|
|
267
|
+
}, []), handleExitComplete = useCallback(() => {
|
|
268
|
+
dialogElRef.current?.open && dialogElRef.current.close(), dialogElRef.current = null;
|
|
269
|
+
}, []);
|
|
266
270
|
return useHotkeys([
|
|
267
271
|
["mod+k", open, { preventDefault: !0 }]
|
|
268
272
|
]), /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
269
273
|
/* @__PURE__ */ jsx(SearchControl, { onClick: open }),
|
|
270
|
-
/* @__PURE__ */ jsx(FramerMotionConfig, { children: /* @__PURE__ */ jsx(AnimatePresence, { children: isOpened && /* @__PURE__ */ jsx(
|
|
274
|
+
/* @__PURE__ */ jsx(FramerMotionConfig, { children: /* @__PURE__ */ jsx(AnimatePresence, { onExitComplete: handleExitComplete, children: isOpened && /* @__PURE__ */ jsx(
|
|
271
275
|
Overlay,
|
|
272
276
|
{
|
|
277
|
+
ref: captureDialogRef,
|
|
273
278
|
fullscreen: !0,
|
|
274
279
|
withBackdrop: !1,
|
|
275
280
|
backdrop: {
|
|
@@ -1102,6 +1107,10 @@ const Header = memo(() => {
|
|
|
1102
1107
|
}), enableDownload = (params) => ({
|
|
1103
1108
|
...params,
|
|
1104
1109
|
download: !0
|
|
1110
|
+
}), enableJpegDownload = (params) => ({
|
|
1111
|
+
...params,
|
|
1112
|
+
download: !0,
|
|
1113
|
+
format: "jpeg"
|
|
1105
1114
|
});
|
|
1106
1115
|
function ExportButton() {
|
|
1107
1116
|
const isInsideProject = useMatches({
|
|
@@ -1144,6 +1153,21 @@ function ExportButton() {
|
|
|
1144
1153
|
children: "Export as .png"
|
|
1145
1154
|
}
|
|
1146
1155
|
),
|
|
1156
|
+
/* @__PURE__ */ jsx(
|
|
1157
|
+
MenuItem,
|
|
1158
|
+
{
|
|
1159
|
+
renderRoot: (props) => /* @__PURE__ */ jsx(
|
|
1160
|
+
Link,
|
|
1161
|
+
{
|
|
1162
|
+
target: "_blank",
|
|
1163
|
+
to: isInsideProject ? "/project/$projectId/export/$viewId/" : "/export/$viewId/",
|
|
1164
|
+
search: enableJpegDownload,
|
|
1165
|
+
...props
|
|
1166
|
+
}
|
|
1167
|
+
),
|
|
1168
|
+
children: "Export as .jpg"
|
|
1169
|
+
}
|
|
1170
|
+
),
|
|
1147
1171
|
/* @__PURE__ */ jsx(
|
|
1148
1172
|
MenuItem,
|
|
1149
1173
|
{
|
|
@@ -1216,6 +1240,14 @@ function ViewLayout() {
|
|
|
1216
1240
|
/* @__PURE__ */ jsx(Header, {})
|
|
1217
1241
|
] });
|
|
1218
1242
|
}
|
|
1243
|
+
function triggerDownload(url, filename) {
|
|
1244
|
+
const link = document.createElement("a");
|
|
1245
|
+
return link.setAttribute("download", filename), link.href = url, document.body.appendChild(link), link.click(), new Promise(
|
|
1246
|
+
(resolve) => setTimeout(() => {
|
|
1247
|
+
document.body.removeChild(link), URL.revokeObjectURL(url), resolve();
|
|
1248
|
+
}, 1e3)
|
|
1249
|
+
);
|
|
1250
|
+
}
|
|
1219
1251
|
async function downloadAsPng({
|
|
1220
1252
|
pngFilename,
|
|
1221
1253
|
viewport
|
|
@@ -1228,20 +1260,39 @@ async function downloadAsPng({
|
|
|
1228
1260
|
});
|
|
1229
1261
|
if (!blob)
|
|
1230
1262
|
throw new Error("Failed to create PNG blob");
|
|
1231
|
-
|
|
1232
|
-
|
|
1263
|
+
const url = URL.createObjectURL(blob);
|
|
1264
|
+
await triggerDownload(url, `${pngFilename}.png`), window.close();
|
|
1233
1265
|
} catch (err) {
|
|
1234
1266
|
console.error(err), window.alert("Failed to export to PNG, check the console for more details.");
|
|
1235
1267
|
}
|
|
1236
1268
|
}
|
|
1269
|
+
async function downloadAsJpeg({
|
|
1270
|
+
filename,
|
|
1271
|
+
viewport,
|
|
1272
|
+
quality = 0.8
|
|
1273
|
+
}) {
|
|
1274
|
+
try {
|
|
1275
|
+
const backgroundColor = getComputedStyle(document.documentElement).getPropertyValue("--mantine-color-body"), dataUrl = await toJpeg(viewport, {
|
|
1276
|
+
backgroundColor,
|
|
1277
|
+
quality,
|
|
1278
|
+
cacheBust: !0,
|
|
1279
|
+
// 1x1 transparent GIF used as fallback when remote images fail to load
|
|
1280
|
+
imagePlaceholder: "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="
|
|
1281
|
+
});
|
|
1282
|
+
await triggerDownload(dataUrl, `${filename}.jpg`), window.close();
|
|
1283
|
+
} catch (err) {
|
|
1284
|
+
console.error(err), window.alert("Failed to export to JPEG, check the console for more details.");
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1237
1287
|
function ExportPage() {
|
|
1238
|
-
const [diagram] = useCurrentView();
|
|
1239
|
-
return useTransparentBackground(), diagram ? /* @__PURE__ */ jsx(GuardedExportPage, { diagram }) : /* @__PURE__ */ jsx("div", { children: "Loading..." });
|
|
1288
|
+
const [diagram] = useCurrentView(), { format } = useSearch({ strict: !1 }), isJpeg = format === "jpeg";
|
|
1289
|
+
return useTransparentBackground(!isJpeg), diagram ? /* @__PURE__ */ jsx(GuardedExportPage, { diagram, isJpeg }) : /* @__PURE__ */ jsx("div", { children: "Loading..." });
|
|
1240
1290
|
}
|
|
1241
|
-
function GuardedExportPage({ diagram }) {
|
|
1291
|
+
function GuardedExportPage({ diagram, isJpeg }) {
|
|
1242
1292
|
const {
|
|
1243
1293
|
padding = 20,
|
|
1244
1294
|
download = !1,
|
|
1295
|
+
quality,
|
|
1245
1296
|
dynamic
|
|
1246
1297
|
} = useSearch({
|
|
1247
1298
|
strict: !1
|
|
@@ -1250,7 +1301,11 @@ function GuardedExportPage({ diagram }) {
|
|
|
1250
1301
|
if (!download || !viewport || !diagram || downloadedRef.current)
|
|
1251
1302
|
return;
|
|
1252
1303
|
const loadingOverlay = loadingOverlayRef.current;
|
|
1253
|
-
loadingOverlay && (loadingOverlay.style.display = "none"), downloadedRef.current = !0,
|
|
1304
|
+
loadingOverlay && (loadingOverlay.style.display = "none"), downloadedRef.current = !0, isJpeg ? downloadAsJpeg({
|
|
1305
|
+
filename: diagram.id,
|
|
1306
|
+
viewport,
|
|
1307
|
+
quality: quality ?? 0.8
|
|
1308
|
+
}) : downloadAsPng({
|
|
1254
1309
|
pngFilename: diagram.id,
|
|
1255
1310
|
viewport
|
|
1256
1311
|
});
|
|
@@ -1266,7 +1321,6 @@ function GuardedExportPage({ diagram }) {
|
|
|
1266
1321
|
left: "0",
|
|
1267
1322
|
padding: "0",
|
|
1268
1323
|
margin: "0",
|
|
1269
|
-
background: "transparent",
|
|
1270
1324
|
overflow: "hidden",
|
|
1271
1325
|
zIndex: 2
|
|
1272
1326
|
},
|
|
@@ -1276,7 +1330,8 @@ function GuardedExportPage({ diagram }) {
|
|
|
1276
1330
|
minWidth: width,
|
|
1277
1331
|
width,
|
|
1278
1332
|
minHeight: height,
|
|
1279
|
-
height
|
|
1333
|
+
height,
|
|
1334
|
+
background: isJpeg ? "var(--mantine-color-body)" : "transparent"
|
|
1280
1335
|
},
|
|
1281
1336
|
children: [
|
|
1282
1337
|
download && /* @__PURE__ */ jsx(LoadingOverlay, { ref: loadingOverlayRef, visible: !0 }),
|
|
@@ -1291,7 +1346,7 @@ function GuardedExportPage({ diagram }) {
|
|
|
1291
1346
|
left: "0px",
|
|
1292
1347
|
right: "0px"
|
|
1293
1348
|
},
|
|
1294
|
-
background: "transparent",
|
|
1349
|
+
background: isJpeg ? "solid" : "transparent",
|
|
1295
1350
|
reduceGraphics: !1,
|
|
1296
1351
|
dynamicViewVariant: dynamic,
|
|
1297
1352
|
className: "likec4-static-view",
|
|
@@ -1325,12 +1380,16 @@ function GuardedExportPage({ diagram }) {
|
|
|
1325
1380
|
}
|
|
1326
1381
|
const Route$6 = createFileRoute("/_single/export/$viewId")({
|
|
1327
1382
|
validateSearch: z.object({
|
|
1328
|
-
download: z.boolean().optional().catch(!1)
|
|
1383
|
+
download: z.boolean().optional().catch(!1),
|
|
1384
|
+
format: z.enum(["png", "jpeg"]).optional().catch("png"),
|
|
1385
|
+
quality: z.number().min(0).max(1).optional().catch(void 0)
|
|
1329
1386
|
}),
|
|
1330
1387
|
search: {
|
|
1331
1388
|
middlewares: [
|
|
1332
1389
|
stripSearchParams({
|
|
1333
|
-
download: !1
|
|
1390
|
+
download: !1,
|
|
1391
|
+
format: "png",
|
|
1392
|
+
quality: void 0
|
|
1334
1393
|
})
|
|
1335
1394
|
]
|
|
1336
1395
|
},
|