foss-design 0.3.1 → 0.3.3
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 +1 -1
- package/dist/cli.js +119 -28
- package/dist/viewer/assets/index-B33q8dee.js +157 -0
- package/dist/viewer/assets/index-Y9E03U3m.css +2 -0
- package/dist/viewer/index.html +2 -2
- package/dist/viewer-lib/index.js +305 -113
- package/dist/viewer-lib/styles.css +63 -4
- package/dist/viewer-lib/types/viewer/src/lib/viewer.d.ts +4 -0
- package/dist/viewer-lib/types/viewer/src/library.d.ts +1 -0
- package/dist/viewer-lib/types/viewer/src/pages/canvas/full-page.d.ts +15 -0
- package/dist/viewer-lib/types/viewer/src/pages/home.d.ts +1 -1
- package/dist/viewer-lib/types/viewer/src/ui/dialog.d.ts +3 -1
- package/dist/viewer-lib/types/viewer/src/ui/menu.d.ts +2 -1
- package/dist/viewer-lib/types/viewer/src/ui/skeleton.d.ts +15 -0
- package/package.json +1 -1
- package/dist/viewer/assets/index-ChcZNlVM.css +0 -2
- package/dist/viewer/assets/index-nWUkiwia.js +0 -157
package/dist/viewer-lib/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { QueryClient, QueryClientProvider, useQuery } from "@tanstack/react-quer
|
|
|
2
2
|
import { AnimatePresence, MotionConfig, motion } from "motion/react";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { Children, createContext, forwardRef, memo, useCallback, useContext, useEffect, useId, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
5
|
-
import { Link, Redirect, Route, Router, Switch as Switch$1, useLocation } from "wouter";
|
|
5
|
+
import { Link, Redirect, Route, Router, Switch as Switch$1, useLocation, useRouter } from "wouter";
|
|
6
6
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
import * as ReactDOM from "react-dom";
|
|
8
8
|
//#region \0rolldown/runtime.js
|
|
@@ -6507,11 +6507,11 @@ function Menu({ trigger, children, width = 220, align = "start", side = "bottom"
|
|
|
6507
6507
|
});
|
|
6508
6508
|
}
|
|
6509
6509
|
var menuItemClass = (danger, active) => cn("flex min-h-9 w-full cursor-pointer items-center gap-2.5 border-0 px-3 py-1.5 text-left text-[13.5px] outline-none select-none", "data-[highlighted]:bg-soft data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50", active ? "bg-soft" : "bg-transparent", danger ? "text-danger-text" : "text-ink");
|
|
6510
|
-
function MenuItem({ children, onSelect, danger, active, disabled, hint }) {
|
|
6510
|
+
function MenuItem({ children, onSelect, danger, active, disabled, hint, className }) {
|
|
6511
6511
|
return /* @__PURE__ */ jsxs(Item2, {
|
|
6512
6512
|
disabled,
|
|
6513
6513
|
onSelect,
|
|
6514
|
-
className: menuItemClass(danger, active),
|
|
6514
|
+
className: cn(menuItemClass(danger, active), className),
|
|
6515
6515
|
children: [children, hint ? /* @__PURE__ */ jsx("span", {
|
|
6516
6516
|
className: "ml-auto pl-3 text-[12px] text-muted",
|
|
6517
6517
|
children: hint
|
|
@@ -6969,48 +6969,52 @@ function Toaster() {
|
|
|
6969
6969
|
if (!shown) return null;
|
|
6970
6970
|
return /* @__PURE__ */ jsx("div", {
|
|
6971
6971
|
className: "pointer-events-none fixed bottom-5 left-1/2 z-[60] flex -translate-x-1/2 flex-col items-center gap-2",
|
|
6972
|
-
children: /* @__PURE__ */ jsx(AnimatePresence, {
|
|
6973
|
-
|
|
6974
|
-
|
|
6975
|
-
|
|
6976
|
-
|
|
6977
|
-
|
|
6978
|
-
|
|
6979
|
-
|
|
6980
|
-
|
|
6981
|
-
|
|
6982
|
-
|
|
6983
|
-
|
|
6984
|
-
|
|
6985
|
-
|
|
6986
|
-
|
|
6987
|
-
|
|
6988
|
-
|
|
6989
|
-
|
|
6990
|
-
|
|
6991
|
-
|
|
6992
|
-
|
|
6993
|
-
|
|
6994
|
-
|
|
6995
|
-
|
|
6996
|
-
|
|
6997
|
-
|
|
6998
|
-
|
|
6999
|
-
|
|
7000
|
-
|
|
7001
|
-
|
|
7002
|
-
|
|
7003
|
-
|
|
7004
|
-
|
|
7005
|
-
|
|
7006
|
-
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
6972
|
+
children: /* @__PURE__ */ jsx(AnimatePresence, {
|
|
6973
|
+
mode: "popLayout",
|
|
6974
|
+
children: list.map((item) => /* @__PURE__ */ jsxs(motion.div, {
|
|
6975
|
+
layout: true,
|
|
6976
|
+
initial: {
|
|
6977
|
+
opacity: 0,
|
|
6978
|
+
y: 8,
|
|
6979
|
+
scale: .98
|
|
6980
|
+
},
|
|
6981
|
+
animate: {
|
|
6982
|
+
opacity: 1,
|
|
6983
|
+
y: 0,
|
|
6984
|
+
scale: 1
|
|
6985
|
+
},
|
|
6986
|
+
exit: {
|
|
6987
|
+
opacity: 0,
|
|
6988
|
+
y: 4,
|
|
6989
|
+
transition: { duration: .12 }
|
|
6990
|
+
},
|
|
6991
|
+
transition: {
|
|
6992
|
+
type: "spring",
|
|
6993
|
+
stiffness: 520,
|
|
6994
|
+
damping: 40
|
|
6995
|
+
},
|
|
6996
|
+
className: "flex max-w-[min(420px,calc(100vw-32px))] min-w-0 items-center gap-2.5 rounded-[8px] border border-rule bg-surface px-3 py-2 text-[13px] text-ink shadow-pop",
|
|
6997
|
+
children: [
|
|
6998
|
+
item.tone === "error" ? /* @__PURE__ */ jsx(Icon, {
|
|
6999
|
+
name: "alert",
|
|
7000
|
+
size: 15,
|
|
7001
|
+
className: "text-danger-text"
|
|
7002
|
+
}) : /* @__PURE__ */ jsx(Icon, {
|
|
7003
|
+
name: "check",
|
|
7004
|
+
size: 15,
|
|
7005
|
+
className: "text-ok-text"
|
|
7006
|
+
}),
|
|
7007
|
+
/* @__PURE__ */ jsx("span", {
|
|
7008
|
+
className: "shrink-0 font-medium whitespace-nowrap",
|
|
7009
|
+
children: item.title
|
|
7010
|
+
}),
|
|
7011
|
+
item.text ? /* @__PURE__ */ jsx("span", {
|
|
7012
|
+
className: "min-w-0 truncate font-mono text-[12px] text-muted",
|
|
7013
|
+
children: item.text
|
|
7014
|
+
}) : null
|
|
7015
|
+
]
|
|
7016
|
+
}, item.id))
|
|
7017
|
+
})
|
|
7014
7018
|
});
|
|
7015
7019
|
}
|
|
7016
7020
|
//#endregion
|
|
@@ -7673,7 +7677,7 @@ var BADGE = {
|
|
|
7673
7677
|
};
|
|
7674
7678
|
function Badge({ tone = "neutral", children, className }) {
|
|
7675
7679
|
return /* @__PURE__ */ jsx("span", {
|
|
7676
|
-
className: cn("inline-flex h-[22px] shrink-0 items-center whitespace-nowrap rounded-[6px] px-2 text-[12px] font-medium", BADGE[tone], className),
|
|
7680
|
+
className: cn("inline-flex h-[22px] shrink-0 items-center gap-1 whitespace-nowrap rounded-[6px] px-2 text-[12px] font-medium", BADGE[tone], className),
|
|
7677
7681
|
children
|
|
7678
7682
|
});
|
|
7679
7683
|
}
|
|
@@ -8729,6 +8733,94 @@ function Tooltip({ content, children, side = "top", align = "center", className
|
|
|
8729
8733
|
}) })] });
|
|
8730
8734
|
}
|
|
8731
8735
|
//#endregion
|
|
8736
|
+
//#region viewer/src/pages/canvas/full-page.tsx
|
|
8737
|
+
/** The full-window page of one screen, relative to the viewer's base. */
|
|
8738
|
+
var fullHref = (canvas, item, theme) => `/c/${encodeURIComponent(canvas)}/full/${encodeURIComponent(item)}?theme=${theme}`;
|
|
8739
|
+
/**
|
|
8740
|
+
* "Open in a new tab" for a screen. A sandboxed viewer serves screens to its frames only, so the
|
|
8741
|
+
* tab gets the full-window page of the viewer; otherwise the screen's own URL.
|
|
8742
|
+
*/
|
|
8743
|
+
function useOpenUrl(canvasId, item, theme) {
|
|
8744
|
+
const { frameSandbox } = useViewer();
|
|
8745
|
+
const { base } = useRouter();
|
|
8746
|
+
if (!item) return null;
|
|
8747
|
+
if (item.kind === "url") return item.url;
|
|
8748
|
+
if (!frameSandbox) return absoluteUrl(frameSrc(item.url, item.theme ?? theme));
|
|
8749
|
+
return absoluteUrl(`${base}${fullHref(canvasId, item.id, item.theme ?? theme)}`);
|
|
8750
|
+
}
|
|
8751
|
+
/** `/c/:canvas/full/:item`: one screen filling the window, a way out on hover and Esc. */
|
|
8752
|
+
function FullPage({ canvasId, itemId }) {
|
|
8753
|
+
const { data: canvas, error, isLoading } = useCanvas(canvasId);
|
|
8754
|
+
const [, navigate] = useLocation();
|
|
8755
|
+
const { frameSandbox } = useViewer();
|
|
8756
|
+
const appTheme = useTheme();
|
|
8757
|
+
const frame = useRef(null);
|
|
8758
|
+
const param = new URLSearchParams(window.location.search).get("theme");
|
|
8759
|
+
const items = canvas ? canvas.pages.flatMap((page) => page.sections.flatMap((section) => section.items.filter((item) => item.kind === "screen" || item.kind === "url"))) : [];
|
|
8760
|
+
const item = items.find((entry) => entry.id === itemId);
|
|
8761
|
+
const theme = (item?.kind === "screen" ? item.theme : void 0) ?? (param === "light" || param === "dark" ? param : canvas?.theme ?? appTheme);
|
|
8762
|
+
const url = item ? item.kind === "screen" ? frameSrc(item.url, theme) : item.url : "";
|
|
8763
|
+
const back = `/c/${encodeURIComponent(canvasId)}`;
|
|
8764
|
+
useEffect(() => {
|
|
8765
|
+
if (item) document.title = `${item.title} · ${canvas?.title ?? ""}`;
|
|
8766
|
+
}, [item, canvas?.title]);
|
|
8767
|
+
useEffect(() => {
|
|
8768
|
+
const onKey = (event) => {
|
|
8769
|
+
if (event.key === "Escape") navigate(back);
|
|
8770
|
+
};
|
|
8771
|
+
window.addEventListener("keydown", onKey);
|
|
8772
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
8773
|
+
}, [navigate, back]);
|
|
8774
|
+
useEffect(() => {
|
|
8775
|
+
const el = frame.current;
|
|
8776
|
+
if (!el || item?.kind !== "screen") return;
|
|
8777
|
+
return listenToFrame(el, (message) => {
|
|
8778
|
+
if (message.type === "keydown" && message.code === "Escape") navigate(back);
|
|
8779
|
+
else if (message.type === "go") {
|
|
8780
|
+
const id = message.target.includes("/") ? message.target.split("/")[1] : message.target;
|
|
8781
|
+
if (items.some((entry) => entry.id === id)) navigate(fullHref(canvasId, id, theme), { replace: true });
|
|
8782
|
+
}
|
|
8783
|
+
});
|
|
8784
|
+
}, [url, item?.kind]);
|
|
8785
|
+
if (error) return /* @__PURE__ */ jsx(NotFound, {
|
|
8786
|
+
title: "Canvas not found",
|
|
8787
|
+
text: error.message
|
|
8788
|
+
});
|
|
8789
|
+
if (isLoading || !canvas) return /* @__PURE__ */ jsx("div", { className: "h-dvh bg-surface" });
|
|
8790
|
+
if (!item) return /* @__PURE__ */ jsx(NotFound, {
|
|
8791
|
+
title: "Screen not found",
|
|
8792
|
+
text: `No screen "${itemId}" on this canvas.`
|
|
8793
|
+
});
|
|
8794
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
8795
|
+
className: "group fixed inset-0 bg-surface",
|
|
8796
|
+
children: [/* @__PURE__ */ jsx("iframe", {
|
|
8797
|
+
ref: frame,
|
|
8798
|
+
src: url,
|
|
8799
|
+
title: item.title,
|
|
8800
|
+
allow: "clipboard-read; clipboard-write; fullscreen",
|
|
8801
|
+
sandbox: frameSandbox,
|
|
8802
|
+
className: "block h-full w-full border-0",
|
|
8803
|
+
style: { colorScheme: theme },
|
|
8804
|
+
onLoad: () => item.kind === "screen" && sendTheme(frame.current, theme)
|
|
8805
|
+
}, `${item.id}:${item.kind === "screen" ? item.rev : item.url}`), /* @__PURE__ */ jsx("div", {
|
|
8806
|
+
className: "pointer-events-none absolute inset-x-0 top-0 flex justify-end p-3 opacity-0 transition-opacity duration-200 group-hover:opacity-100 focus-within:opacity-100",
|
|
8807
|
+
children: /* @__PURE__ */ jsxs(Link, {
|
|
8808
|
+
href: back,
|
|
8809
|
+
className: "pointer-events-auto flex h-8 items-center gap-2 rounded-[8px] border border-rule bg-surface px-3 text-[12.5px] text-ink2 no-underline shadow-pop hover:text-ink",
|
|
8810
|
+
children: [
|
|
8811
|
+
/* @__PURE__ */ jsx(Icon, {
|
|
8812
|
+
name: "x",
|
|
8813
|
+
size: 14
|
|
8814
|
+
}),
|
|
8815
|
+
"Back to ",
|
|
8816
|
+
canvas.title,
|
|
8817
|
+
/* @__PURE__ */ jsx(Kbd, { children: "esc" })
|
|
8818
|
+
]
|
|
8819
|
+
})
|
|
8820
|
+
})]
|
|
8821
|
+
});
|
|
8822
|
+
}
|
|
8823
|
+
//#endregion
|
|
8732
8824
|
//#region viewer/src/pages/canvas/sidebar.tsx
|
|
8733
8825
|
function itemIcon(item) {
|
|
8734
8826
|
if (item.kind === "note") return "note";
|
|
@@ -8931,11 +9023,10 @@ function SelectionBar({ canvas, store, layoutItems, theme, onPlay, inspect }) {
|
|
|
8931
9023
|
const selected = useStore(store, (state) => state.selected);
|
|
8932
9024
|
const active = useStore(store, (state) => state.active);
|
|
8933
9025
|
const status = useStore(store, (state) => selected ? state.frames[selected] : void 0);
|
|
8934
|
-
const { frameSandbox } = useViewer();
|
|
8935
9026
|
const item = layoutItems.find((i) => i.id === selected);
|
|
9027
|
+
const openUrl = useOpenUrl(canvas.id, item?.kind === "screen" || item?.kind === "url" ? item : void 0, theme);
|
|
8936
9028
|
if (!item) return null;
|
|
8937
9029
|
const frame = item.kind === "screen" || item.kind === "url";
|
|
8938
|
-
const openUrl = item.kind === "screen" && !frameSandbox ? absoluteUrl(frameSrc(item.url, item.theme ?? theme)) : item.kind === "url" ? item.url : null;
|
|
8939
9030
|
const reload = () => reloadFrame(document.querySelector(`[data-item="${CSS.escape(item.id)}"] iframe`));
|
|
8940
9031
|
const errors = status?.errors ?? [];
|
|
8941
9032
|
return /* @__PURE__ */ jsx("div", {
|
|
@@ -12396,6 +12487,7 @@ function Player({ canvas, itemId }) {
|
|
|
12396
12487
|
const entry = list[index];
|
|
12397
12488
|
const item = entry?.item;
|
|
12398
12489
|
const frameTheme = item?.kind === "screen" ? item.theme ?? theme : theme;
|
|
12490
|
+
const openUrl = useOpenUrl(canvas.id, item, frameTheme);
|
|
12399
12491
|
const [openTheme] = useState(frameTheme);
|
|
12400
12492
|
const src = item ? item.kind === "screen" ? frameSrc(item.url, openTheme) : item.url : "";
|
|
12401
12493
|
const frames = useMemo(() => frameEl && item?.kind === "screen" ? [frameEl] : [], [frameEl, item?.kind]);
|
|
@@ -12438,7 +12530,6 @@ function Player({ canvas, itemId }) {
|
|
|
12438
12530
|
const height = item.frame.height === "auto" ? Math.max(area.h - 48, 400) : item.frame.height;
|
|
12439
12531
|
const scale = fit === "fit" ? Math.min(1, (area.w - 48) / width, (area.h - 48) / height) : 1;
|
|
12440
12532
|
const fits = width <= area.w - 48 && height <= area.h - 48;
|
|
12441
|
-
const openUrl = item.kind === "url" ? item.url : frameSandbox ? null : absoluteUrl(frameSrc(item.url, frameTheme));
|
|
12442
12533
|
return /* @__PURE__ */ jsxs("div", {
|
|
12443
12534
|
className: "flex h-dvh flex-col",
|
|
12444
12535
|
children: [
|
|
@@ -12639,6 +12730,44 @@ function plural(count, one, many = `${one}s`) {
|
|
|
12639
12730
|
return `${count} ${count === 1 ? one : many}`;
|
|
12640
12731
|
}
|
|
12641
12732
|
//#endregion
|
|
12733
|
+
//#region viewer/src/ui/skeleton.tsx
|
|
12734
|
+
/** A placeholder block that pulses while its content loads. */
|
|
12735
|
+
function Skeleton({ className, style }) {
|
|
12736
|
+
return /* @__PURE__ */ jsx("span", {
|
|
12737
|
+
"aria-hidden": "true",
|
|
12738
|
+
className: cn("block animate-pulse rounded-[6px] bg-soft2", className),
|
|
12739
|
+
style
|
|
12740
|
+
});
|
|
12741
|
+
}
|
|
12742
|
+
/**
|
|
12743
|
+
* Rows of a loading panel: a leading block, two lines of text and a trailing block, with the
|
|
12744
|
+
* panel's row borders, so the real rows replace them without a jump.
|
|
12745
|
+
*/
|
|
12746
|
+
function SkeletonRows({ rows = 3, lead = 28, minH = 56 }) {
|
|
12747
|
+
return /* @__PURE__ */ jsx("div", {
|
|
12748
|
+
role: "status",
|
|
12749
|
+
"aria-label": "Loading",
|
|
12750
|
+
children: Array.from({ length: rows }, (_, index) => /* @__PURE__ */ jsxs("div", {
|
|
12751
|
+
className: "flex items-center gap-3 border-t border-rule px-4",
|
|
12752
|
+
style: {
|
|
12753
|
+
minHeight: minH,
|
|
12754
|
+
opacity: 1 - index * .18
|
|
12755
|
+
},
|
|
12756
|
+
children: [
|
|
12757
|
+
lead ? /* @__PURE__ */ jsx(Skeleton, { style: {
|
|
12758
|
+
width: lead,
|
|
12759
|
+
height: Math.min(lead, minH - 20)
|
|
12760
|
+
} }) : null,
|
|
12761
|
+
/* @__PURE__ */ jsxs("span", {
|
|
12762
|
+
className: "flex min-w-0 grow flex-col gap-1.5",
|
|
12763
|
+
children: [/* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-[38%]" }), /* @__PURE__ */ jsx(Skeleton, { className: "h-2.5 w-[62%]" })]
|
|
12764
|
+
}),
|
|
12765
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-14" })
|
|
12766
|
+
]
|
|
12767
|
+
}, index))
|
|
12768
|
+
});
|
|
12769
|
+
}
|
|
12770
|
+
//#endregion
|
|
12642
12771
|
//#region viewer/src/pages/home.tsx
|
|
12643
12772
|
function Cover({ canvas }) {
|
|
12644
12773
|
return /* @__PURE__ */ jsx("div", {
|
|
@@ -12666,68 +12795,84 @@ function WithActions({ actions, children }) {
|
|
|
12666
12795
|
})]
|
|
12667
12796
|
});
|
|
12668
12797
|
}
|
|
12798
|
+
/** The embedding app's strip under the canvas list. */
|
|
12799
|
+
function Foot({ children }) {
|
|
12800
|
+
if (!children) return null;
|
|
12801
|
+
return /* @__PURE__ */ jsx("div", {
|
|
12802
|
+
className: "flex items-center gap-2.5 border-t border-rule bg-soft px-4 py-3 text-[12.5px] text-muted",
|
|
12803
|
+
children
|
|
12804
|
+
});
|
|
12805
|
+
}
|
|
12669
12806
|
function CanvasList({ project }) {
|
|
12670
|
-
const rowActions = useViewer().slots
|
|
12671
|
-
if (!project.canvases.length) return /* @__PURE__ */ jsxs(Panel, { children: [
|
|
12672
|
-
|
|
12673
|
-
|
|
12674
|
-
|
|
12675
|
-
|
|
12676
|
-
children:
|
|
12677
|
-
className: "
|
|
12678
|
-
children:
|
|
12679
|
-
|
|
12680
|
-
|
|
12681
|
-
|
|
12682
|
-
"
|
|
12683
|
-
/* @__PURE__ */ jsx(Mono, { children: "design new <name>" }),
|
|
12684
|
-
" in the project."
|
|
12685
|
-
]
|
|
12686
|
-
})]
|
|
12687
|
-
}) })] });
|
|
12688
|
-
return /* @__PURE__ */ jsxs(Panel, { children: [/* @__PURE__ */ jsx(PanelHead, {
|
|
12689
|
-
title: "Canvases",
|
|
12690
|
-
count: project.canvases.length
|
|
12691
|
-
}), project.canvases.map((canvas) => {
|
|
12692
|
-
const actions = rowActions?.(canvas.id);
|
|
12693
|
-
return /* @__PURE__ */ jsx(WithActions, {
|
|
12694
|
-
actions,
|
|
12695
|
-
children: /* @__PURE__ */ jsxs(RowLink, {
|
|
12696
|
-
to: `/c/${encodeURIComponent(canvas.id)}`,
|
|
12697
|
-
cols: "86px minmax(0,1fr) auto auto",
|
|
12698
|
-
align: "llrr",
|
|
12699
|
-
pad: "10px 16px",
|
|
12700
|
-
minH: 74,
|
|
12701
|
-
first: !!actions,
|
|
12807
|
+
const { canvasRowActions: rowActions, canvasesFoot } = useViewer().slots;
|
|
12808
|
+
if (!project.canvases.length) return /* @__PURE__ */ jsxs(Panel, { children: [
|
|
12809
|
+
/* @__PURE__ */ jsx(PanelHead, {
|
|
12810
|
+
title: "Canvases",
|
|
12811
|
+
count: 0
|
|
12812
|
+
}),
|
|
12813
|
+
/* @__PURE__ */ jsx(PanelBody, { children: /* @__PURE__ */ jsxs("div", {
|
|
12814
|
+
className: "flex flex-col gap-2 py-6 text-center",
|
|
12815
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
12816
|
+
className: "text-[14px] text-ink2",
|
|
12817
|
+
children: "No canvases yet."
|
|
12818
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
12819
|
+
className: "text-[13px] text-muted",
|
|
12702
12820
|
children: [
|
|
12703
|
-
|
|
12704
|
-
/* @__PURE__ */ jsx(
|
|
12705
|
-
|
|
12706
|
-
bottom: /* @__PURE__ */ jsx("span", {
|
|
12707
|
-
className: "truncate",
|
|
12708
|
-
children: canvas.description ?? canvas.id
|
|
12709
|
-
})
|
|
12710
|
-
}),
|
|
12711
|
-
/* @__PURE__ */ jsxs("span", {
|
|
12712
|
-
className: "flex items-center gap-2 text-[12.5px] whitespace-nowrap text-muted",
|
|
12713
|
-
children: [
|
|
12714
|
-
canvas.issues ? /* @__PURE__ */ jsx(Badge, {
|
|
12715
|
-
tone: "danger",
|
|
12716
|
-
children: plural(canvas.issues, "problem")
|
|
12717
|
-
}) : null,
|
|
12718
|
-
plural(canvas.screens, "screen"),
|
|
12719
|
-
" · ",
|
|
12720
|
-
plural(canvas.pages, "page")
|
|
12721
|
-
]
|
|
12722
|
-
}),
|
|
12723
|
-
/* @__PURE__ */ jsx("span", {
|
|
12724
|
-
className: "w-[92px] text-[12.5px] whitespace-nowrap text-muted",
|
|
12725
|
-
children: relativeTime(canvas.updatedAt)
|
|
12726
|
-
})
|
|
12821
|
+
"Ask your agent to design something, or run ",
|
|
12822
|
+
/* @__PURE__ */ jsx(Mono, { children: "design new <name>" }),
|
|
12823
|
+
" in the project."
|
|
12727
12824
|
]
|
|
12728
|
-
})
|
|
12729
|
-
}
|
|
12730
|
-
|
|
12825
|
+
})]
|
|
12826
|
+
}) }),
|
|
12827
|
+
/* @__PURE__ */ jsx(Foot, { children: canvasesFoot })
|
|
12828
|
+
] });
|
|
12829
|
+
return /* @__PURE__ */ jsxs(Panel, { children: [
|
|
12830
|
+
/* @__PURE__ */ jsx(PanelHead, {
|
|
12831
|
+
title: "Canvases",
|
|
12832
|
+
count: project.canvases.length
|
|
12833
|
+
}),
|
|
12834
|
+
project.canvases.map((canvas) => {
|
|
12835
|
+
const actions = rowActions?.(canvas.id);
|
|
12836
|
+
return /* @__PURE__ */ jsx(WithActions, {
|
|
12837
|
+
actions,
|
|
12838
|
+
children: /* @__PURE__ */ jsxs(RowLink, {
|
|
12839
|
+
to: `/c/${encodeURIComponent(canvas.id)}`,
|
|
12840
|
+
cols: "86px minmax(0,1fr) auto auto",
|
|
12841
|
+
align: "llrr",
|
|
12842
|
+
pad: "10px 16px",
|
|
12843
|
+
minH: 74,
|
|
12844
|
+
first: !!actions,
|
|
12845
|
+
children: [
|
|
12846
|
+
/* @__PURE__ */ jsx(Cover, { canvas }),
|
|
12847
|
+
/* @__PURE__ */ jsx(Two, {
|
|
12848
|
+
top: canvas.title,
|
|
12849
|
+
bottom: /* @__PURE__ */ jsx("span", {
|
|
12850
|
+
className: "truncate",
|
|
12851
|
+
children: canvas.description ?? canvas.id
|
|
12852
|
+
})
|
|
12853
|
+
}),
|
|
12854
|
+
/* @__PURE__ */ jsxs("span", {
|
|
12855
|
+
className: "flex items-center gap-2 text-[12.5px] whitespace-nowrap text-muted",
|
|
12856
|
+
children: [
|
|
12857
|
+
canvas.issues ? /* @__PURE__ */ jsx(Badge, {
|
|
12858
|
+
tone: "danger",
|
|
12859
|
+
children: plural(canvas.issues, "problem")
|
|
12860
|
+
}) : null,
|
|
12861
|
+
plural(canvas.screens, "screen"),
|
|
12862
|
+
" · ",
|
|
12863
|
+
plural(canvas.pages, "page")
|
|
12864
|
+
]
|
|
12865
|
+
}),
|
|
12866
|
+
/* @__PURE__ */ jsx("span", {
|
|
12867
|
+
className: "w-[92px] text-[12.5px] whitespace-nowrap text-muted",
|
|
12868
|
+
children: relativeTime(canvas.updatedAt)
|
|
12869
|
+
})
|
|
12870
|
+
]
|
|
12871
|
+
})
|
|
12872
|
+
}, canvas.id);
|
|
12873
|
+
}),
|
|
12874
|
+
/* @__PURE__ */ jsx(Foot, { children: canvasesFoot })
|
|
12875
|
+
] });
|
|
12731
12876
|
}
|
|
12732
12877
|
function SystemCard({ project }) {
|
|
12733
12878
|
const system = project.system;
|
|
@@ -12760,21 +12905,25 @@ function SystemCard({ project }) {
|
|
|
12760
12905
|
/* @__PURE__ */ jsx(KV, {
|
|
12761
12906
|
label: "Tokens",
|
|
12762
12907
|
labelWidth: 120,
|
|
12908
|
+
end: true,
|
|
12763
12909
|
children: /* @__PURE__ */ jsx(Count, { value: system.tokens })
|
|
12764
12910
|
}),
|
|
12765
12911
|
/* @__PURE__ */ jsx(KV, {
|
|
12766
12912
|
label: "Components",
|
|
12767
12913
|
labelWidth: 120,
|
|
12914
|
+
end: true,
|
|
12768
12915
|
children: /* @__PURE__ */ jsx(Count, { value: system.components })
|
|
12769
12916
|
}),
|
|
12770
12917
|
/* @__PURE__ */ jsx(KV, {
|
|
12771
12918
|
label: "Guidelines",
|
|
12772
12919
|
labelWidth: 120,
|
|
12920
|
+
end: true,
|
|
12773
12921
|
children: /* @__PURE__ */ jsx(Count, { value: system.guidelines })
|
|
12774
12922
|
}),
|
|
12775
12923
|
system.issues ? /* @__PURE__ */ jsx(KV, {
|
|
12776
12924
|
label: "Problems",
|
|
12777
12925
|
labelWidth: 120,
|
|
12926
|
+
end: true,
|
|
12778
12927
|
children: /* @__PURE__ */ jsx(Badge, {
|
|
12779
12928
|
tone: "danger",
|
|
12780
12929
|
children: system.issues
|
|
@@ -12782,6 +12931,25 @@ function SystemCard({ project }) {
|
|
|
12782
12931
|
}) : null
|
|
12783
12932
|
] });
|
|
12784
12933
|
}
|
|
12934
|
+
/** The home page's shape while the project loads, so it fills in instead of popping in. */
|
|
12935
|
+
function HomeSkeleton() {
|
|
12936
|
+
return /* @__PURE__ */ jsxs(Content, { children: [/* @__PURE__ */ jsxs("div", {
|
|
12937
|
+
className: "flex flex-col gap-2.5 pt-1 pb-1",
|
|
12938
|
+
children: [/* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-[220px]" }), /* @__PURE__ */ jsx(Skeleton, { className: "h-3.5 w-[300px]" })]
|
|
12939
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
12940
|
+
className: "grid items-start gap-5 max-lg:grid-cols-1!",
|
|
12941
|
+
style: { gridTemplateColumns: "minmax(0,1fr) 340px" },
|
|
12942
|
+
children: [/* @__PURE__ */ jsxs(Panel, { children: [/* @__PURE__ */ jsx(PanelHead, { title: "Canvases" }), /* @__PURE__ */ jsx(SkeletonRows, {
|
|
12943
|
+
rows: 3,
|
|
12944
|
+
lead: 86,
|
|
12945
|
+
minH: 74
|
|
12946
|
+
})] }), /* @__PURE__ */ jsxs(Panel, { children: [/* @__PURE__ */ jsx(PanelHead, { title: "Design system" }), /* @__PURE__ */ jsx(SkeletonRows, {
|
|
12947
|
+
rows: 3,
|
|
12948
|
+
lead: 0,
|
|
12949
|
+
minH: 40
|
|
12950
|
+
})] })]
|
|
12951
|
+
})] });
|
|
12952
|
+
}
|
|
12785
12953
|
function HomePage() {
|
|
12786
12954
|
const { data: project, error, isLoading } = useProject();
|
|
12787
12955
|
const { slots } = useViewer();
|
|
@@ -12789,12 +12957,12 @@ function HomePage() {
|
|
|
12789
12957
|
title: "Could not load the project",
|
|
12790
12958
|
text: error.message
|
|
12791
12959
|
});
|
|
12792
|
-
if (isLoading || !project) return
|
|
12960
|
+
if (isLoading || !project) return /* @__PURE__ */ jsx(HomeSkeleton, {});
|
|
12793
12961
|
return /* @__PURE__ */ jsxs(Content, { children: [
|
|
12794
12962
|
/* @__PURE__ */ jsx(PageHead, {
|
|
12795
12963
|
title: project.name,
|
|
12796
12964
|
right: slots.homeActions,
|
|
12797
|
-
sub: project.static ? `Snapshot built with foss-design ${project.version}` : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
12965
|
+
sub: slots.homeSub ? slots.homeSub : project.static ? `Snapshot built with foss-design ${project.version}` : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
12798
12966
|
/* @__PURE__ */ jsxs(Mono, {
|
|
12799
12967
|
size: 12.5,
|
|
12800
12968
|
children: [project.root, "/.design"]
|
|
@@ -17233,6 +17401,13 @@ function Title() {
|
|
|
17233
17401
|
}
|
|
17234
17402
|
function Routes() {
|
|
17235
17403
|
return /* @__PURE__ */ jsxs(Switch$1, { children: [
|
|
17404
|
+
/* @__PURE__ */ jsx(Route, {
|
|
17405
|
+
path: "/c/:canvas/full/:item",
|
|
17406
|
+
children: (params) => /* @__PURE__ */ jsx(FullPage, {
|
|
17407
|
+
canvasId: params.canvas,
|
|
17408
|
+
itemId: params.item
|
|
17409
|
+
})
|
|
17410
|
+
}),
|
|
17236
17411
|
/* @__PURE__ */ jsx(Route, {
|
|
17237
17412
|
path: "/c/:canvas/play/:item",
|
|
17238
17413
|
children: (params) => /* @__PURE__ */ jsx(PlayPage, {
|
|
@@ -17270,6 +17445,13 @@ function ScopedRoutes({ canvas }) {
|
|
|
17270
17445
|
replace: true
|
|
17271
17446
|
});
|
|
17272
17447
|
return /* @__PURE__ */ jsxs(Switch$1, { children: [
|
|
17448
|
+
/* @__PURE__ */ jsx(Route, {
|
|
17449
|
+
path: "/c/:canvas/full/:item",
|
|
17450
|
+
children: (params) => guard(params.canvas, /* @__PURE__ */ jsx(FullPage, {
|
|
17451
|
+
canvasId: canvas,
|
|
17452
|
+
itemId: params.item
|
|
17453
|
+
}))
|
|
17454
|
+
}),
|
|
17273
17455
|
/* @__PURE__ */ jsx(Route, {
|
|
17274
17456
|
path: "/c/:canvas/play/:item",
|
|
17275
17457
|
children: (params) => guard(params.canvas, /* @__PURE__ */ jsx(PlayPage, {
|
|
@@ -17387,7 +17569,7 @@ function Avatar({ src, name, size = 28, shape = "circle", className }) {
|
|
|
17387
17569
|
* A modal over a dimmed page: focus stays inside until it closes, Escape and a
|
|
17388
17570
|
* click outside close it. Head and foot are a panel's; `actions` go to the foot.
|
|
17389
17571
|
*/
|
|
17390
|
-
function Dialog({ open, onOpenChange, title, description, children, actions, footNote, width = 440 }) {
|
|
17572
|
+
function Dialog({ open, onOpenChange, title, description, children, actions, footNote, below, width = 440 }) {
|
|
17391
17573
|
return /* @__PURE__ */ jsx(Dialog$1, {
|
|
17392
17574
|
open,
|
|
17393
17575
|
onOpenChange,
|
|
@@ -17405,6 +17587,11 @@ function Dialog({ open, onOpenChange, title, description, children, actions, foo
|
|
|
17405
17587
|
children: /* @__PURE__ */ jsx(DialogContent, {
|
|
17406
17588
|
asChild: true,
|
|
17407
17589
|
forceMount: true,
|
|
17590
|
+
onOpenAutoFocus: (event) => {
|
|
17591
|
+
event.preventDefault();
|
|
17592
|
+
const content = event.currentTarget;
|
|
17593
|
+
(content.querySelector("input:not([type=\"hidden\"]), textarea, [data-autofocus]") ?? content).focus({ preventScroll: true });
|
|
17594
|
+
},
|
|
17408
17595
|
...description ? {} : { "aria-describedby": void 0 },
|
|
17409
17596
|
children: /* @__PURE__ */ jsxs(motion.div, {
|
|
17410
17597
|
initial: {
|
|
@@ -17427,7 +17614,8 @@ function Dialog({ open, onOpenChange, title, description, children, actions, foo
|
|
|
17427
17614
|
stiffness: 560,
|
|
17428
17615
|
damping: 40
|
|
17429
17616
|
},
|
|
17430
|
-
|
|
17617
|
+
tabIndex: -1,
|
|
17618
|
+
className: cn(floatingSurface, "flex max-w-full flex-col outline-none"),
|
|
17431
17619
|
style: { width },
|
|
17432
17620
|
children: [
|
|
17433
17621
|
/* @__PURE__ */ jsx(PanelHead, {
|
|
@@ -17450,6 +17638,10 @@ function Dialog({ open, onOpenChange, title, description, children, actions, foo
|
|
|
17450
17638
|
className: "m-0 text-[13.5px] text-ink2",
|
|
17451
17639
|
children: description
|
|
17452
17640
|
}) : null, children] }) : null,
|
|
17641
|
+
below ? /* @__PURE__ */ jsx("div", {
|
|
17642
|
+
className: "max-h-[min(56vh,520px)] min-h-0 overflow-y-auto border-t border-rule",
|
|
17643
|
+
children: below
|
|
17644
|
+
}) : null,
|
|
17453
17645
|
actions || footNote ? /* @__PURE__ */ jsx(PanelFoot, {
|
|
17454
17646
|
left: footNote,
|
|
17455
17647
|
right: actions
|
|
@@ -17578,4 +17770,4 @@ function TextArea({ label, hint, error, className, id, disabled, rows = 4, ...re
|
|
|
17578
17770
|
});
|
|
17579
17771
|
}
|
|
17580
17772
|
//#endregion
|
|
17581
|
-
export { ApiError, Avatar, Badge, Bar, Button, ButtonAnchor, ButtonLink, Content, Count, DesignViewer, Dialog, GroupRow, Icon, IconButton, KV, Kbd, Mark, Menu, MenuItem, MenuLabel, MenuSeparator, Meter, Mono, Muted, NavLabel, Notice, NoticeCard, PageHead, Panel, PanelBody, PanelFoot, PanelHead, PanelTabs, Row, RowLink, Segmented, SlidePanel, Strip, SubNav, Switch, THead, TextArea, TextField, ThemeMenu, Toaster, Tooltip, TooltipProvider, Two, Wordmark, buttonClass, cn, copyText, floatingSurface, iconButtonClass, initials, localSource, menuItemClass, menuSurface, resolveUrl, setThemePref, staticSource, toast, useTheme, useThemePref };
|
|
17773
|
+
export { ApiError, Avatar, Badge, Bar, Button, ButtonAnchor, ButtonLink, Content, Count, DesignViewer, Dialog, GroupRow, Icon, IconButton, KV, Kbd, Mark, Menu, MenuItem, MenuLabel, MenuSeparator, Meter, Mono, Muted, NavLabel, Notice, NoticeCard, PageHead, Panel, PanelBody, PanelFoot, PanelHead, PanelTabs, Row, RowLink, Segmented, Skeleton, SkeletonRows, SlidePanel, Strip, SubNav, Switch, THead, TextArea, TextField, ThemeMenu, Toaster, Tooltip, TooltipProvider, Two, Wordmark, buttonClass, cn, copyText, floatingSurface, iconButtonClass, initials, localSource, menuItemClass, menuSurface, resolveUrl, setThemePref, staticSource, toast, useTheme, useThemePref };
|