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 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
- isAnnotationMode && showAnnotationPanel ? "right-[21rem]" : "right-4"
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" : "p-2 text-neutral-400 hover:bg-neutral-800 hover:text-white"
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-4 w-4" }),
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__ */ jsx12(
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: /* @__PURE__ */ jsxs6(
2250
- "div",
2251
- {
2252
- ref: slideContainerRef,
2253
- className: "absolute top-0 left-0 overflow-hidden",
2254
- style: {
2255
- width: SLIDE_DIMENSIONS.width,
2256
- height: SLIDE_DIMENSIONS.height,
2257
- transformOrigin: "top left"
2258
- },
2259
- children: [
2260
- /* @__PURE__ */ jsx12(
2261
- SlideRenderer,
2262
- {
2263
- slides,
2264
- currentSlide,
2265
- animationStep,
2266
- totalSteps,
2267
- direction,
2268
- showAllAnimations,
2269
- transition,
2270
- directionalTransition,
2271
- onTransitionComplete
2272
- }
2273
- ),
2274
- isAnnotationMode && /* @__PURE__ */ jsx12(
2275
- AnnotationOverlay,
2276
- {
2277
- slides,
2278
- currentSlide,
2279
- slideContainerRef,
2280
- selectedId: selectedAnnotationId,
2281
- hoveredId: hoveredAnnotationId,
2282
- onSelectId: setSelectedAnnotationId,
2283
- onShowPanel: () => setShowAnnotationPanel(true),
2284
- slideAnnotations: getSlideAnnotations(currentSlide),
2285
- addAnnotation: effectiveAdd ?? (() => {
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
  {