promptslide 0.3.17 → 0.3.18
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/CHANGELOG.md +7 -0
- package/dist/index.js +134 -63
- package/dist/index.js.map +1 -1
- package/package.json +31 -31
- package/src/commands/studio.mjs +4 -3
- package/src/core/slide-deck.tsx +88 -6
- package/src/core/slide-renderer.tsx +3 -8
- package/src/editor/README.md +35 -0
- package/src/editor/geometry.ts +76 -0
- package/src/editor/mount.ts +24 -0
- package/src/editor/plugin.mjs +189 -0
- package/src/editor/source.mjs +363 -0
- package/src/editor/studio.css +1004 -0
- package/src/editor/studio.tsx +1948 -0
- package/src/vite/config.mjs +23 -2
- package/src/vite/plugin.mjs +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.3.18](https://github.com/prompticeu/promptslide/compare/promptslide-v0.3.17...promptslide-v0.3.18) (2026-10-23)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add visual slide editing in studio ([#107](https://github.com/prompticeu/promptslide/issues/107)) ([4dd6651](https://github.com/prompticeu/promptslide/commit/4dd6651269687c6a0d219c8e3b261a9ac11b7876))
|
|
9
|
+
|
|
3
10
|
## [0.3.17](https://github.com/prompticeu/promptslide/compare/promptslide-v0.3.16...promptslide-v0.3.17) (2026-09-26)
|
|
4
11
|
|
|
5
12
|
|
package/dist/index.js
CHANGED
|
@@ -616,6 +616,7 @@ function SlideRenderer({
|
|
|
616
616
|
return /* @__PURE__ */ jsx6(AnimatePresence, { initial: false, children: /* @__PURE__ */ jsx6(
|
|
617
617
|
motion3.div,
|
|
618
618
|
{
|
|
619
|
+
"data-slide-render-index": currentSlide,
|
|
619
620
|
variants: slideVariants,
|
|
620
621
|
initial: "enter",
|
|
621
622
|
animate: "center",
|
|
@@ -633,20 +634,7 @@ function SlideRenderer({
|
|
|
633
634
|
currentStep: animationStep,
|
|
634
635
|
totalSteps,
|
|
635
636
|
showAllAnimations,
|
|
636
|
-
children: /* @__PURE__ */ jsx6(
|
|
637
|
-
SlideErrorBoundary,
|
|
638
|
-
{
|
|
639
|
-
slideIndex: currentSlide,
|
|
640
|
-
slideTitle: slides[currentSlide]?.title,
|
|
641
|
-
children: /* @__PURE__ */ jsx6(
|
|
642
|
-
CurrentSlideComponent,
|
|
643
|
-
{
|
|
644
|
-
slideNumber: currentSlide + 1,
|
|
645
|
-
totalSlides: slides.length
|
|
646
|
-
}
|
|
647
|
-
)
|
|
648
|
-
}
|
|
649
|
-
)
|
|
637
|
+
children: /* @__PURE__ */ jsx6(SlideErrorBoundary, { slideIndex: currentSlide, slideTitle: slides[currentSlide]?.title, children: /* @__PURE__ */ jsx6(CurrentSlideComponent, { slideNumber: currentSlide + 1, totalSlides: slides.length }) })
|
|
650
638
|
}
|
|
651
639
|
)
|
|
652
640
|
},
|
|
@@ -1641,6 +1629,26 @@ function SlideDeck({
|
|
|
1641
1629
|
[effectiveAnnotations, slides]
|
|
1642
1630
|
);
|
|
1643
1631
|
const [viewMode, setViewMode] = useState7("slide");
|
|
1632
|
+
const [isEditorOpen, setIsEditorOpen] = useState7(false);
|
|
1633
|
+
const [editorRevision, setEditorRevision] = useState7(0);
|
|
1634
|
+
useEffect7(() => {
|
|
1635
|
+
const onEditorState = (event) => {
|
|
1636
|
+
const open = Boolean(event.detail?.open);
|
|
1637
|
+
setIsEditorOpen(open);
|
|
1638
|
+
if (open) {
|
|
1639
|
+
setViewMode("slide");
|
|
1640
|
+
setIsAnnotationMode(false);
|
|
1641
|
+
setShowAnnotationPanel(false);
|
|
1642
|
+
}
|
|
1643
|
+
};
|
|
1644
|
+
const refreshEditor = () => setEditorRevision((value) => value + 1);
|
|
1645
|
+
window.addEventListener("promptslide:editor-state", onEditorState);
|
|
1646
|
+
window.addEventListener("promptslide:editor-refresh", refreshEditor);
|
|
1647
|
+
return () => {
|
|
1648
|
+
window.removeEventListener("promptslide:editor-state", onEditorState);
|
|
1649
|
+
window.removeEventListener("promptslide:editor-refresh", refreshEditor);
|
|
1650
|
+
};
|
|
1651
|
+
}, []);
|
|
1644
1652
|
const [isPresentationMode, setIsPresentationMode] = useState7(false);
|
|
1645
1653
|
const [viewportWidth, setViewportWidth] = useState7(
|
|
1646
1654
|
() => typeof window === "undefined" ? 1280 : window.innerWidth
|
|
@@ -1878,6 +1886,7 @@ function SlideDeck({
|
|
|
1878
1886
|
if (e.altKey || e.ctrlKey || e.metaKey) return;
|
|
1879
1887
|
const key = e.key.toLowerCase();
|
|
1880
1888
|
if (e.repeat && "fvglcdt".includes(key)) return;
|
|
1889
|
+
if (isEditorOpen && ["f", "v", "g", "l", "c", "d"].includes(key)) return;
|
|
1881
1890
|
if (key === "f") {
|
|
1882
1891
|
e.preventDefault();
|
|
1883
1892
|
void togglePresentationMode();
|
|
@@ -1930,14 +1939,38 @@ function SlideDeck({
|
|
|
1930
1939
|
viewMode,
|
|
1931
1940
|
togglePresentationMode,
|
|
1932
1941
|
isAnnotationMode,
|
|
1942
|
+
isEditorOpen,
|
|
1933
1943
|
isPresentationMode,
|
|
1934
1944
|
setThumbnailRailOpen,
|
|
1935
1945
|
showThumbnailRail,
|
|
1936
1946
|
toggleCommentMode,
|
|
1937
1947
|
handleExportPdf
|
|
1938
1948
|
]);
|
|
1949
|
+
const editorPanelWidth = viewportWidth <= 850 ? 280 : 320;
|
|
1939
1950
|
return /* @__PURE__ */ jsxs6("div", { className: "min-h-screen w-full bg-neutral-950 text-foreground", children: [
|
|
1940
1951
|
/* @__PURE__ */ jsx12("style", { children: `
|
|
1952
|
+
.slide-thumbnail-scroll-area {
|
|
1953
|
+
scrollbar-width: thin;
|
|
1954
|
+
scrollbar-color: #404040 transparent;
|
|
1955
|
+
}
|
|
1956
|
+
.slide-thumbnail-scroll-area::-webkit-scrollbar {
|
|
1957
|
+
width: 10px;
|
|
1958
|
+
}
|
|
1959
|
+
.slide-thumbnail-scroll-area::-webkit-scrollbar-track {
|
|
1960
|
+
background: transparent;
|
|
1961
|
+
}
|
|
1962
|
+
.slide-thumbnail-scroll-area::-webkit-scrollbar-thumb {
|
|
1963
|
+
background-color: #404040;
|
|
1964
|
+
border: 3px solid transparent;
|
|
1965
|
+
border-radius: 9999px;
|
|
1966
|
+
background-clip: padding-box;
|
|
1967
|
+
}
|
|
1968
|
+
.slide-thumbnail-scroll-area::-webkit-scrollbar-thumb:hover {
|
|
1969
|
+
background-color: #525252;
|
|
1970
|
+
}
|
|
1971
|
+
.slide-thumbnail-scroll-area::-webkit-scrollbar-corner {
|
|
1972
|
+
background: transparent;
|
|
1973
|
+
}
|
|
1941
1974
|
@media print {
|
|
1942
1975
|
.list-slide-canvas {
|
|
1943
1976
|
transform: scale(1.5) !important;
|
|
@@ -1964,10 +1997,14 @@ function SlideDeck({
|
|
|
1964
1997
|
/* @__PURE__ */ jsxs6(
|
|
1965
1998
|
"div",
|
|
1966
1999
|
{
|
|
2000
|
+
"data-ps-viewer-toolbar": true,
|
|
2001
|
+
style: isEditorOpen ? { right: editorPanelWidth + 16, maxWidth: `calc(100vw - ${editorPanelWidth + 32}px)` } : void 0,
|
|
1967
2002
|
className: cn(
|
|
1968
2003
|
"fixed top-4 z-50 flex gap-1 rounded-lg border border-neutral-800 bg-neutral-950/90 p-1 backdrop-blur-sm transition-[right] duration-200 ease-out print:hidden",
|
|
1969
2004
|
(isPresentationMode || isNarrowViewport && isAnnotationMode && showAnnotationPanel) && "hidden",
|
|
1970
|
-
|
|
2005
|
+
isEditorOpen && "flex-wrap",
|
|
2006
|
+
isEditorOpen && viewportWidth <= 850 && "[&_button:disabled]:hidden [&>div]:hidden",
|
|
2007
|
+
!isEditorOpen && (isAnnotationMode && showAnnotationPanel ? "right-[21rem]" : "right-4")
|
|
1971
2008
|
),
|
|
1972
2009
|
children: [
|
|
1973
2010
|
/* @__PURE__ */ jsx12(
|
|
@@ -1978,6 +2015,7 @@ function SlideDeck({
|
|
|
1978
2015
|
"rounded-md p-2 text-neutral-400 transition-colors hover:bg-neutral-800 hover:text-white",
|
|
1979
2016
|
viewMode === "slide" && "bg-neutral-800 text-white"
|
|
1980
2017
|
),
|
|
2018
|
+
disabled: isEditorOpen,
|
|
1981
2019
|
title: "Presentation View (V)",
|
|
1982
2020
|
children: /* @__PURE__ */ jsx12(Monitor, { className: "h-4 w-4" })
|
|
1983
2021
|
}
|
|
@@ -1990,6 +2028,7 @@ function SlideDeck({
|
|
|
1990
2028
|
"rounded-md p-2 text-neutral-400 transition-colors hover:bg-neutral-800 hover:text-white",
|
|
1991
2029
|
viewMode === "list" && "bg-neutral-800 text-white"
|
|
1992
2030
|
),
|
|
2031
|
+
disabled: isEditorOpen,
|
|
1993
2032
|
title: "List View (L)",
|
|
1994
2033
|
children: /* @__PURE__ */ jsx12(List, { className: "h-4 w-4" })
|
|
1995
2034
|
}
|
|
@@ -2002,6 +2041,7 @@ function SlideDeck({
|
|
|
2002
2041
|
"rounded-md p-2 text-neutral-400 transition-colors hover:bg-neutral-800 hover:text-white",
|
|
2003
2042
|
viewMode === "grid" && "bg-neutral-800 text-white"
|
|
2004
2043
|
),
|
|
2044
|
+
disabled: isEditorOpen,
|
|
2005
2045
|
title: "Grid View (G)",
|
|
2006
2046
|
children: /* @__PURE__ */ jsx12(Grid3X3, { className: "h-4 w-4" })
|
|
2007
2047
|
}
|
|
@@ -2012,22 +2052,28 @@ function SlideDeck({
|
|
|
2012
2052
|
{
|
|
2013
2053
|
onClick: toggleCommentMode,
|
|
2014
2054
|
className: cn(
|
|
2015
|
-
"relative inline-flex h-8 items-center justify-center rounded-md transition-colors",
|
|
2016
|
-
isAnnotationMode ? "border border-[#FF6B35]/50 bg-[#FF6B35]/15 p-[7px] text-[#FF6B35] hover:border-[#FF6B35] hover:bg-[#FF6B35]/25" : "
|
|
2055
|
+
"relative inline-flex h-8 items-center justify-center gap-1.5 rounded-md font-[family-name:system-ui] text-[13px] leading-none font-medium transition-colors",
|
|
2056
|
+
isAnnotationMode ? "border border-[#FF6B35]/50 bg-[#FF6B35]/15 p-[7px] text-[#FF6B35] hover:border-[#FF6B35] hover:bg-[#FF6B35]/25" : "px-2.5 text-neutral-400 hover:bg-neutral-800 hover:text-white"
|
|
2017
2057
|
),
|
|
2058
|
+
disabled: isEditorOpen,
|
|
2059
|
+
"aria-label": "Comment",
|
|
2060
|
+
"aria-pressed": isAnnotationMode,
|
|
2018
2061
|
title: "Comment (C)",
|
|
2019
2062
|
children: [
|
|
2020
|
-
/* @__PURE__ */ jsx12(MessageCircle, { className: "h-
|
|
2063
|
+
/* @__PURE__ */ jsx12(MessageCircle, { className: "h-[15px] w-[15px] shrink-0" }),
|
|
2064
|
+
!isAnnotationMode && /* @__PURE__ */ jsx12("span", { children: "Comment" }),
|
|
2021
2065
|
openCount > 0 && /* @__PURE__ */ jsx12("span", { className: "absolute -top-1 -right-1 flex h-4 w-4 items-center justify-center rounded-full bg-[#FF6B35] text-[10px] font-bold text-white", children: openCount })
|
|
2022
2066
|
]
|
|
2023
2067
|
}
|
|
2024
2068
|
),
|
|
2069
|
+
/* @__PURE__ */ jsx12("span", { "data-ps-editor-toolbar": true, className: "contents" }),
|
|
2025
2070
|
/* @__PURE__ */ jsx12("div", { className: "mx-1 w-px bg-neutral-800" }),
|
|
2026
2071
|
/* @__PURE__ */ jsx12(
|
|
2027
2072
|
"button",
|
|
2028
2073
|
{
|
|
2029
2074
|
onClick: handleExportPdf,
|
|
2030
2075
|
className: "rounded-md p-2 text-neutral-400 transition-colors hover:bg-neutral-800 hover:text-white",
|
|
2076
|
+
disabled: isEditorOpen,
|
|
2031
2077
|
title: "Download PDF (D)",
|
|
2032
2078
|
children: /* @__PURE__ */ jsx12(Download, { className: "h-4 w-4" })
|
|
2033
2079
|
}
|
|
@@ -2037,6 +2083,7 @@ function SlideDeck({
|
|
|
2037
2083
|
{
|
|
2038
2084
|
onClick: togglePresentationMode,
|
|
2039
2085
|
className: "inline-flex h-8 items-center justify-center gap-1.5 rounded-md border border-[#FF6B35]/50 bg-[#FF6B35]/15 px-3 text-sm font-semibold text-[#FF6B35] transition-colors hover:border-[#FF6B35] hover:bg-[#FF6B35]/25",
|
|
2086
|
+
disabled: isEditorOpen,
|
|
2040
2087
|
title: "Present (F)",
|
|
2041
2088
|
children: [
|
|
2042
2089
|
/* @__PURE__ */ jsx12(Play, { className: "h-3.5 w-3.5 fill-current" }),
|
|
@@ -2094,7 +2141,7 @@ function SlideDeck({
|
|
|
2094
2141
|
}
|
|
2095
2142
|
)
|
|
2096
2143
|
] }),
|
|
2097
|
-
/* @__PURE__ */ jsx12("div", { className: "min-h-0 flex-1 space-y-3 overflow-y-auto p-3", children: slides.map((slideConfig, index) => /* @__PURE__ */ jsxs6(
|
|
2144
|
+
/* @__PURE__ */ jsx12("div", { className: "slide-thumbnail-scroll-area min-h-0 flex-1 space-y-3 overflow-y-auto p-3", children: slides.map((slideConfig, index) => /* @__PURE__ */ jsxs6(
|
|
2098
2145
|
"button",
|
|
2099
2146
|
{
|
|
2100
2147
|
ref: index === currentSlide ? activeThumbnailRef : void 0,
|
|
@@ -2241,54 +2288,67 @@ function SlideDeck({
|
|
|
2241
2288
|
}
|
|
2242
2289
|
)
|
|
2243
2290
|
}
|
|
2244
|
-
) : /* @__PURE__ */
|
|
2291
|
+
) : /* @__PURE__ */ jsxs6(
|
|
2245
2292
|
"div",
|
|
2246
2293
|
{
|
|
2247
2294
|
ref: previewViewportRef,
|
|
2248
2295
|
className: "relative aspect-video w-full max-w-7xl overflow-hidden rounded-xl border border-neutral-800 bg-black shadow-2xl",
|
|
2249
|
-
children:
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2296
|
+
children: [
|
|
2297
|
+
/* @__PURE__ */ jsxs6(
|
|
2298
|
+
"div",
|
|
2299
|
+
{
|
|
2300
|
+
ref: slideContainerRef,
|
|
2301
|
+
"data-ps-editor-canvas": true,
|
|
2302
|
+
tabIndex: -1,
|
|
2303
|
+
"data-slide-index": currentSlide,
|
|
2304
|
+
className: "absolute top-0 left-0 overflow-hidden outline-none",
|
|
2305
|
+
style: {
|
|
2306
|
+
width: SLIDE_DIMENSIONS.width,
|
|
2307
|
+
height: SLIDE_DIMENSIONS.height,
|
|
2308
|
+
transformOrigin: "top left"
|
|
2309
|
+
},
|
|
2310
|
+
children: [
|
|
2311
|
+
/* @__PURE__ */ jsx12(
|
|
2312
|
+
SlideRenderer,
|
|
2313
|
+
{
|
|
2314
|
+
slides,
|
|
2315
|
+
currentSlide,
|
|
2316
|
+
animationStep,
|
|
2317
|
+
totalSteps,
|
|
2318
|
+
direction,
|
|
2319
|
+
showAllAnimations,
|
|
2320
|
+
transition,
|
|
2321
|
+
directionalTransition,
|
|
2322
|
+
onTransitionComplete
|
|
2323
|
+
},
|
|
2324
|
+
editorRevision
|
|
2325
|
+
),
|
|
2326
|
+
isAnnotationMode && /* @__PURE__ */ jsx12(
|
|
2327
|
+
AnnotationOverlay,
|
|
2328
|
+
{
|
|
2329
|
+
slides,
|
|
2330
|
+
currentSlide,
|
|
2331
|
+
slideContainerRef,
|
|
2332
|
+
selectedId: selectedAnnotationId,
|
|
2333
|
+
hoveredId: hoveredAnnotationId,
|
|
2334
|
+
onSelectId: setSelectedAnnotationId,
|
|
2335
|
+
onShowPanel: () => setShowAnnotationPanel(true),
|
|
2336
|
+
slideAnnotations: getSlideAnnotations(currentSlide),
|
|
2337
|
+
addAnnotation: effectiveAdd ?? (() => {
|
|
2338
|
+
})
|
|
2339
|
+
}
|
|
2340
|
+
)
|
|
2341
|
+
]
|
|
2342
|
+
}
|
|
2343
|
+
),
|
|
2344
|
+
/* @__PURE__ */ jsx12(
|
|
2345
|
+
"div",
|
|
2346
|
+
{
|
|
2347
|
+
"data-ps-editor-overlay": true,
|
|
2348
|
+
className: "pointer-events-none absolute inset-0 z-20"
|
|
2349
|
+
}
|
|
2350
|
+
)
|
|
2351
|
+
]
|
|
2292
2352
|
}
|
|
2293
2353
|
) }),
|
|
2294
2354
|
!isPresentationMode && /* @__PURE__ */ jsxs6("div", { className: "mt-6 flex items-center gap-4", children: [
|
|
@@ -2319,6 +2379,17 @@ function SlideDeck({
|
|
|
2319
2379
|
]
|
|
2320
2380
|
}
|
|
2321
2381
|
),
|
|
2382
|
+
/* @__PURE__ */ jsx12(
|
|
2383
|
+
"div",
|
|
2384
|
+
{
|
|
2385
|
+
"data-ps-editor-panel": true,
|
|
2386
|
+
"data-open": isEditorOpen,
|
|
2387
|
+
"aria-hidden": !isEditorOpen,
|
|
2388
|
+
inert: !isEditorOpen,
|
|
2389
|
+
className: "h-full shrink-0 overflow-hidden transition-[width] duration-200 ease-out motion-reduce:transition-none",
|
|
2390
|
+
style: { width: isEditorOpen ? editorPanelWidth : 0 }
|
|
2391
|
+
}
|
|
2392
|
+
),
|
|
2322
2393
|
!isPresentationMode && /* @__PURE__ */ jsx12(
|
|
2323
2394
|
"div",
|
|
2324
2395
|
{
|