@open-aippt/core 1.13.2

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.
Files changed (142) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +98 -0
  3. package/bin.js +2 -0
  4. package/dist/build-DxTqmvsO.js +17 -0
  5. package/dist/cli/bin.d.ts +1 -0
  6. package/dist/cli/bin.js +86 -0
  7. package/dist/config-CjzqjrEA.js +4280 -0
  8. package/dist/config-DIC-yVPp.d.ts +23 -0
  9. package/dist/design-cpzS8aud.js +35 -0
  10. package/dist/dev-BYuTeJbA.js +20 -0
  11. package/dist/format-BCeKbTOM.js +1605 -0
  12. package/dist/index.d.ts +134 -0
  13. package/dist/index.js +467 -0
  14. package/dist/locale/index.d.ts +24 -0
  15. package/dist/locale/index.js +3 -0
  16. package/dist/preview-DlQvnJPq.js +18 -0
  17. package/dist/sync-BPZ0m27m.js +139 -0
  18. package/dist/sync-EsYusbbL.js +3 -0
  19. package/dist/types-CHmFPIG_.d.ts +430 -0
  20. package/dist/vite/index.d.ts +14 -0
  21. package/dist/vite/index.js +4 -0
  22. package/env.d.ts +59 -0
  23. package/package.json +103 -0
  24. package/skills/apply-comments/SKILL.md +83 -0
  25. package/skills/create-slide/SKILL.md +91 -0
  26. package/skills/create-theme/SKILL.md +250 -0
  27. package/skills/current-slide/SKILL.md +110 -0
  28. package/skills/slide-authoring/SKILL.md +625 -0
  29. package/src/app/app.tsx +47 -0
  30. package/src/app/components/asset-view.tsx +966 -0
  31. package/src/app/components/history-provider.tsx +120 -0
  32. package/src/app/components/image-placeholder.tsx +243 -0
  33. package/src/app/components/inspector/asset-picker-dialog.tsx +196 -0
  34. package/src/app/components/inspector/comment-widget.tsx +93 -0
  35. package/src/app/components/inspector/image-crop-dialog.tsx +212 -0
  36. package/src/app/components/inspector/inspect-overlay.tsx +387 -0
  37. package/src/app/components/inspector/inspector-panel.tsx +1115 -0
  38. package/src/app/components/inspector/inspector-provider.tsx +1218 -0
  39. package/src/app/components/inspector/save-bar.tsx +48 -0
  40. package/src/app/components/language-toggle.tsx +39 -0
  41. package/src/app/components/notes-drawer.tsx +120 -0
  42. package/src/app/components/overview-grid.tsx +363 -0
  43. package/src/app/components/panel/panel-fields.tsx +60 -0
  44. package/src/app/components/panel/panel-shell.tsx +80 -0
  45. package/src/app/components/panel/save-card.tsx +142 -0
  46. package/src/app/components/pdf-progress-toast.tsx +32 -0
  47. package/src/app/components/player.tsx +466 -0
  48. package/src/app/components/pptx-progress-toast.tsx +32 -0
  49. package/src/app/components/present/blackout-overlay.tsx +18 -0
  50. package/src/app/components/present/control-bar.tsx +315 -0
  51. package/src/app/components/present/help-overlay.tsx +57 -0
  52. package/src/app/components/present/jump-input.tsx +74 -0
  53. package/src/app/components/present/laser-pointer.tsx +39 -0
  54. package/src/app/components/present/progress-bar.tsx +26 -0
  55. package/src/app/components/present/use-idle.ts +46 -0
  56. package/src/app/components/present/use-pointer-near-bottom.ts +34 -0
  57. package/src/app/components/present/use-presenter-channel.ts +66 -0
  58. package/src/app/components/present/use-touch-swipe.ts +66 -0
  59. package/src/app/components/shared-element.tsx +48 -0
  60. package/src/app/components/sidebar/folder-item.tsx +258 -0
  61. package/src/app/components/sidebar/icon-picker.tsx +61 -0
  62. package/src/app/components/sidebar/mobile-pill.tsx +34 -0
  63. package/src/app/components/sidebar/sidebar-footer.tsx +105 -0
  64. package/src/app/components/sidebar/sidebar.tsx +284 -0
  65. package/src/app/components/slide-canvas.tsx +102 -0
  66. package/src/app/components/slide-transition-layer.tsx +844 -0
  67. package/src/app/components/style-panel/design-provider.tsx +148 -0
  68. package/src/app/components/style-panel/style-panel.tsx +349 -0
  69. package/src/app/components/style-panel/use-design.ts +112 -0
  70. package/src/app/components/theme-toggle.tsx +59 -0
  71. package/src/app/components/themes/theme-detail.tsx +305 -0
  72. package/src/app/components/themes/themes-gallery.tsx +149 -0
  73. package/src/app/components/thumbnail-rail.tsx +805 -0
  74. package/src/app/components/ui/badge.tsx +45 -0
  75. package/src/app/components/ui/button.tsx +99 -0
  76. package/src/app/components/ui/card.tsx +92 -0
  77. package/src/app/components/ui/context-menu.tsx +237 -0
  78. package/src/app/components/ui/dialog.tsx +157 -0
  79. package/src/app/components/ui/dropdown-menu.tsx +245 -0
  80. package/src/app/components/ui/input.tsx +25 -0
  81. package/src/app/components/ui/label.tsx +24 -0
  82. package/src/app/components/ui/popover.tsx +75 -0
  83. package/src/app/components/ui/progress.tsx +31 -0
  84. package/src/app/components/ui/scroll-area.tsx +53 -0
  85. package/src/app/components/ui/select.tsx +196 -0
  86. package/src/app/components/ui/separator.tsx +28 -0
  87. package/src/app/components/ui/slider.tsx +61 -0
  88. package/src/app/components/ui/sonner.tsx +48 -0
  89. package/src/app/components/ui/tabs.tsx +79 -0
  90. package/src/app/components/ui/textarea.tsx +22 -0
  91. package/src/app/components/ui/toggle-group.tsx +83 -0
  92. package/src/app/components/ui/toggle.tsx +45 -0
  93. package/src/app/components/ui/tooltip.tsx +58 -0
  94. package/src/app/favicon.ico +0 -0
  95. package/src/app/index.html +13 -0
  96. package/src/app/lib/assets.ts +242 -0
  97. package/src/app/lib/design-presets.ts +94 -0
  98. package/src/app/lib/design.ts +58 -0
  99. package/src/app/lib/export-html.ts +326 -0
  100. package/src/app/lib/export-pdf.ts +298 -0
  101. package/src/app/lib/export-pptx.ts +284 -0
  102. package/src/app/lib/folders.ts +239 -0
  103. package/src/app/lib/inspector/fiber.test.ts +154 -0
  104. package/src/app/lib/inspector/fiber.ts +85 -0
  105. package/src/app/lib/inspector/use-comments.ts +74 -0
  106. package/src/app/lib/inspector/use-editor.ts +73 -0
  107. package/src/app/lib/inspector/use-notes.ts +134 -0
  108. package/src/app/lib/locale-store.ts +67 -0
  109. package/src/app/lib/page-context.tsx +38 -0
  110. package/src/app/lib/print-ready.test.ts +32 -0
  111. package/src/app/lib/print-ready.ts +51 -0
  112. package/src/app/lib/sdk.test.ts +13 -0
  113. package/src/app/lib/sdk.ts +37 -0
  114. package/src/app/lib/slides.ts +26 -0
  115. package/src/app/lib/step-context.tsx +261 -0
  116. package/src/app/lib/themes.ts +22 -0
  117. package/src/app/lib/transition.ts +30 -0
  118. package/src/app/lib/use-agent-socket.ts +18 -0
  119. package/src/app/lib/use-click-page-navigation.ts +60 -0
  120. package/src/app/lib/use-is-mobile.ts +21 -0
  121. package/src/app/lib/use-locale.ts +8 -0
  122. package/src/app/lib/use-prefers-reduced-motion.ts +19 -0
  123. package/src/app/lib/use-slide-module.ts +48 -0
  124. package/src/app/lib/use-wheel-page-navigation.ts +99 -0
  125. package/src/app/lib/utils.test.ts +25 -0
  126. package/src/app/lib/utils.ts +6 -0
  127. package/src/app/main.tsx +14 -0
  128. package/src/app/routes/assets.tsx +9 -0
  129. package/src/app/routes/home-shell.tsx +213 -0
  130. package/src/app/routes/home.tsx +807 -0
  131. package/src/app/routes/presenter.tsx +418 -0
  132. package/src/app/routes/slide.tsx +1108 -0
  133. package/src/app/routes/themes.tsx +34 -0
  134. package/src/app/styles.css +429 -0
  135. package/src/app/virtual.d.ts +51 -0
  136. package/src/locale/en.ts +416 -0
  137. package/src/locale/format.ts +12 -0
  138. package/src/locale/index.ts +6 -0
  139. package/src/locale/ja.ts +422 -0
  140. package/src/locale/types.ts +443 -0
  141. package/src/locale/zh-cn.ts +414 -0
  142. package/src/locale/zh-tw.ts +414 -0
@@ -0,0 +1,134 @@
1
+ import { Locale, Plural } from "./types-CHmFPIG_.js";
2
+ import { OpenAipptConfig } from "./config-DIC-yVPp.js";
3
+ import { CSSProperties, ComponentType, HTMLAttributes, PropsWithChildren, ReactNode } from "react";
4
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
5
+ import * as react_jsx_runtime4 from "react/jsx-runtime";
6
+ import * as react_jsx_runtime2 from "react/jsx-runtime";
7
+ import * as react_jsx_runtime3 from "react/jsx-runtime";
8
+
9
+ //#region src/app/components/image-placeholder.d.ts
10
+ type ImagePlaceholderProps = {
11
+ hint: string;
12
+ width?: number;
13
+ height?: number;
14
+ style?: CSSProperties;
15
+ className?: string;
16
+ } & Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'style' | 'className'>;
17
+ declare function ImagePlaceholder({
18
+ hint,
19
+ width,
20
+ height,
21
+ style,
22
+ className,
23
+ ...rest
24
+ }: ImagePlaceholderProps): react_jsx_runtime0.JSX.Element;
25
+
26
+ //#endregion
27
+ //#region src/app/components/shared-element.d.ts
28
+ type unstable_SharedElementProps = {
29
+ id: string;
30
+ children: ReactNode;
31
+ className?: string;
32
+ style?: CSSProperties;
33
+ };
34
+ declare function unstable_SharedElement({
35
+ id,
36
+ children,
37
+ className,
38
+ style
39
+ }: unstable_SharedElementProps): react_jsx_runtime4.JSX.Element;
40
+
41
+ //#endregion
42
+ //#region src/app/lib/design.d.ts
43
+ type DesignPalette = {
44
+ bg: string;
45
+ text: string;
46
+ accent: string;
47
+ };
48
+ type DesignFonts = {
49
+ display: string;
50
+ body: string;
51
+ };
52
+ type DesignTypeScale = {
53
+ hero: number;
54
+ body: number;
55
+ };
56
+ type DesignSystem = {
57
+ palette: DesignPalette;
58
+ fonts: DesignFonts;
59
+ typeScale: DesignTypeScale;
60
+ radius: number;
61
+ };
62
+ declare function designToCssVars(d: DesignSystem): Record<string, string>;
63
+ declare function cssVarsToString(vars: Record<string, string>): string;
64
+ declare const defaultDesign: DesignSystem;
65
+
66
+ //#endregion
67
+ //#region src/app/lib/page-context.d.ts
68
+ declare function useSlidePageNumber(): {
69
+ current: number;
70
+ total: number;
71
+ };
72
+
73
+ //#endregion
74
+ //#region src/app/lib/transition.d.ts
75
+ type TransitionPhase = {
76
+ keyframes: Keyframe[] | PropertyIndexedKeyframes;
77
+ easing?: string;
78
+ duration?: number;
79
+ delay?: number;
80
+ };
81
+ type SlideTransition = {
82
+ duration: number;
83
+ easing?: string;
84
+ enter?: TransitionPhase;
85
+ exit?: TransitionPhase;
86
+ sharedElements?: boolean | SharedElementTransition;
87
+ };
88
+ type SharedElementTransition = {
89
+ duration?: number;
90
+ easing?: string;
91
+ delay?: number;
92
+ };
93
+
94
+ //#endregion
95
+ //#region src/app/lib/sdk.d.ts
96
+ type Page = ComponentType & {
97
+ transition?: SlideTransition;
98
+ };
99
+ type SlideMeta = {
100
+ title?: string;
101
+ theme?: string;
102
+ /** ISO 8601 timestamp. Set once at scaffold time; used to sort the slide list. */
103
+ createdAt?: string;
104
+ };
105
+ type SlideModule = {
106
+ default: Page[];
107
+ meta?: SlideMeta;
108
+ design?: DesignSystem;
109
+ notes?: (string | undefined)[];
110
+ transition?: SlideTransition;
111
+ };
112
+ declare const CANVAS_WIDTH = 1920;
113
+ declare const CANVAS_HEIGHT = 1080;
114
+
115
+ //#endregion
116
+ //#region src/app/lib/step-context.d.ts
117
+ type StepsProps = PropsWithChildren;
118
+ declare function Steps({
119
+ children
120
+ }: StepsProps): react_jsx_runtime2.JSX.Element;
121
+ type StepProps = PropsWithChildren<{
122
+ duration?: number;
123
+ }>;
124
+ type InternalStepProps = StepProps & {
125
+ _revealed?: boolean;
126
+ };
127
+ declare function Step({
128
+ children,
129
+ duration,
130
+ _revealed
131
+ }: InternalStepProps): react_jsx_runtime3.JSX.Element;
132
+
133
+ //#endregion
134
+ export { CANVAS_HEIGHT, CANVAS_WIDTH, DesignFonts, DesignPalette, DesignSystem, DesignTypeScale, ImagePlaceholder, ImagePlaceholderProps, Locale, OpenAipptConfig, Page, Plural, SharedElementTransition, SlideMeta, SlideModule, SlideTransition, Step, StepProps, Steps, StepsProps, TransitionPhase, cssVarsToString, defaultDesign, designToCssVars, unstable_SharedElement, unstable_SharedElementProps, useSlidePageNumber };
package/dist/index.js ADDED
@@ -0,0 +1,467 @@
1
+ import { en, ja, zhCN, zhTW } from "./format-BCeKbTOM.js";
2
+ import { cssVarsToString, defaultDesign, designToCssVars } from "./design-cpzS8aud.js";
3
+ import { Children, cloneElement, createContext, isValidElement, useCallback, useContext, useEffect, useLayoutEffect, useRef, useState, useSyncExternalStore } from "react";
4
+ import { toast } from "sonner";
5
+ import config from "virtual:open-aippt/config";
6
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
+
8
+ //#region src/app/lib/assets.ts
9
+ async function listAssets(slideId) {
10
+ const res = await fetch(`/__assets/${slideId}`);
11
+ if (!res.ok) throw new Error(`GET /__assets/${slideId} ${res.status}`);
12
+ const data = await res.json();
13
+ return data.assets ?? [];
14
+ }
15
+ async function uploadAsset(slideId, file, opts = {}) {
16
+ const qs = opts.overwrite ? "?overwrite=1" : "";
17
+ return fetch(`/__assets/${slideId}/${encodeURIComponent(file.name)}${qs}`, {
18
+ method: "POST",
19
+ headers: {
20
+ "content-type": file.type || "application/octet-stream",
21
+ "content-length": String(file.size)
22
+ },
23
+ body: file
24
+ });
25
+ }
26
+ async function uploadWithAutoRename(slideId, file) {
27
+ let uploaded = lowercaseExtension(file);
28
+ let res = await uploadAsset(slideId, uploaded);
29
+ if (res.status === 409) {
30
+ const list = await listAssets(slideId);
31
+ const taken = new Set(list.map((a) => a.name));
32
+ uploaded = renamedCopy(uploaded, taken);
33
+ res = await uploadAsset(slideId, uploaded);
34
+ }
35
+ if (!res.ok) return {
36
+ ok: false,
37
+ status: res.status,
38
+ entry: null
39
+ };
40
+ const body = await res.json().catch(() => null);
41
+ const entry = {
42
+ name: body?.name ?? uploaded.name,
43
+ size: body?.size ?? uploaded.size,
44
+ mtime: body?.mtime ?? Date.now(),
45
+ mime: body?.mime ?? uploaded.type ?? "application/octet-stream",
46
+ url: body?.url ?? `/__assets/${slideId}/${encodeURIComponent(uploaded.name)}`,
47
+ unused: body?.unused ?? false
48
+ };
49
+ return {
50
+ ok: true,
51
+ status: res.status,
52
+ entry
53
+ };
54
+ }
55
+ function lowercaseExtension(file) {
56
+ const dot = file.name.lastIndexOf(".");
57
+ if (dot <= 0) return file;
58
+ const ext = file.name.slice(dot);
59
+ const lower = ext.toLowerCase();
60
+ if (ext === lower) return file;
61
+ return new File([file], file.name.slice(0, dot) + lower, {
62
+ type: file.type,
63
+ lastModified: file.lastModified
64
+ });
65
+ }
66
+ function renamedCopy(file, taken) {
67
+ const dot = file.name.lastIndexOf(".");
68
+ const stem = dot > 0 ? file.name.slice(0, dot) : file.name;
69
+ const ext = dot > 0 ? file.name.slice(dot) : "";
70
+ let i = 1;
71
+ let next = `${stem}-${i}${ext}`;
72
+ while (taken.has(next)) {
73
+ i += 1;
74
+ next = `${stem}-${i}${ext}`;
75
+ }
76
+ return new File([file], next, {
77
+ type: file.type,
78
+ lastModified: file.lastModified
79
+ });
80
+ }
81
+
82
+ //#endregion
83
+ //#region src/app/lib/locale-store.ts
84
+ const LOCALES = {
85
+ en,
86
+ "zh-TW": zhTW,
87
+ "zh-CN": zhCN,
88
+ ja
89
+ };
90
+ const STORAGE_KEY = "open-aippt:locale";
91
+ const configLocale = config.locale;
92
+ function isLocaleId(value) {
93
+ return value === "en" || value === "zh-TW" || value === "zh-CN" || value === "ja";
94
+ }
95
+ function readStored() {
96
+ try {
97
+ const stored = localStorage.getItem(STORAGE_KEY);
98
+ if (isLocaleId(stored)) return LOCALES[stored];
99
+ } catch {}
100
+ return configLocale ?? en;
101
+ }
102
+ let current = readStored();
103
+ const listeners = new Set();
104
+ function subscribe(listener) {
105
+ listeners.add(listener);
106
+ return () => {
107
+ listeners.delete(listener);
108
+ };
109
+ }
110
+ function getSnapshot() {
111
+ return current;
112
+ }
113
+ function useLocaleValue() {
114
+ return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
115
+ }
116
+
117
+ //#endregion
118
+ //#region src/app/lib/use-locale.ts
119
+ function useLocale() {
120
+ return useLocaleValue();
121
+ }
122
+
123
+ //#endregion
124
+ //#region src/app/components/image-placeholder.tsx
125
+ function ImagePlaceholder({ hint, width, height, style, className,...rest }) {
126
+ const dims = width && height ? `${width} × ${height}` : null;
127
+ const [dragActive, setDragActive] = useState(false);
128
+ const [uploading, setUploading] = useState(false);
129
+ const dragDepth = useRef(0);
130
+ const t = useLocale();
131
+ const dndProps = import.meta.env.DEV ? {
132
+ onDragEnter: (e) => {
133
+ if (uploading || !hasImageFile(e)) return;
134
+ e.preventDefault();
135
+ dragDepth.current += 1;
136
+ setDragActive(true);
137
+ },
138
+ onDragOver: (e) => {
139
+ if (uploading || !hasImageFile(e)) return;
140
+ e.preventDefault();
141
+ e.dataTransfer.dropEffect = "copy";
142
+ },
143
+ onDragLeave: () => {
144
+ dragDepth.current = Math.max(0, dragDepth.current - 1);
145
+ if (dragDepth.current === 0) setDragActive(false);
146
+ },
147
+ onDrop: (e) => {
148
+ if (uploading || !hasImageFile(e)) return;
149
+ e.preventDefault();
150
+ dragDepth.current = 0;
151
+ setDragActive(false);
152
+ const file = pickImageFile(e.dataTransfer.files);
153
+ if (!file) return;
154
+ const root = e.currentTarget;
155
+ const slideId = root.closest("[data-slide-id]")?.dataset.slideId;
156
+ const loc = root.dataset.slideLoc;
157
+ if (!slideId || !loc) return;
158
+ const idx = loc.indexOf(":");
159
+ if (idx <= 0) return;
160
+ const line = Number(loc.slice(0, idx));
161
+ const column = Number(loc.slice(idx + 1));
162
+ if (!Number.isFinite(line) || !Number.isFinite(column)) return;
163
+ setUploading(true);
164
+ handleDrop(slideId, file, line, column).catch(() => toast.error(t.imagePlaceholder.uploadFailed)).finally(() => setUploading(false));
165
+ }
166
+ } : null;
167
+ return /* @__PURE__ */ jsxs("div", {
168
+ ...rest,
169
+ ...dndProps,
170
+ "data-slide-placeholder": hint,
171
+ "data-placeholder-w": width,
172
+ "data-placeholder-h": height,
173
+ role: "img",
174
+ "aria-label": hint,
175
+ style: {
176
+ position: "relative",
177
+ width: width ?? "100%",
178
+ height: height ?? "100%",
179
+ display: "flex",
180
+ alignItems: "center",
181
+ justifyContent: "center",
182
+ flexDirection: "column",
183
+ gap: 14,
184
+ border: "1px dashed rgba(120, 120, 130, 0.35)",
185
+ borderRadius: 12,
186
+ background: "linear-gradient(135deg, rgba(120,120,130,0.06) 0%, rgba(120,120,130,0.02) 50%, rgba(120,120,130,0.06) 100%)",
187
+ color: "rgba(90, 90, 100, 0.7)",
188
+ fontFamily: "-apple-system, BlinkMacSystemFont, \"Inter\", \"Segoe UI\", system-ui, sans-serif",
189
+ textAlign: "center",
190
+ padding: 24,
191
+ boxSizing: "border-box",
192
+ overflow: "hidden",
193
+ ...style
194
+ },
195
+ className,
196
+ children: [
197
+ /* @__PURE__ */ jsx(PlaceholderIcon, {}),
198
+ /* @__PURE__ */ jsxs("div", {
199
+ style: {
200
+ display: "flex",
201
+ flexDirection: "column",
202
+ alignItems: "center",
203
+ gap: 6,
204
+ maxWidth: "85%"
205
+ },
206
+ children: [
207
+ /* @__PURE__ */ jsx("span", {
208
+ style: {
209
+ fontSize: 11,
210
+ fontWeight: 600,
211
+ letterSpacing: "0.14em",
212
+ textTransform: "uppercase",
213
+ opacity: .55
214
+ },
215
+ children: "Image"
216
+ }),
217
+ /* @__PURE__ */ jsx("span", {
218
+ style: {
219
+ fontSize: 16,
220
+ fontWeight: 500,
221
+ lineHeight: 1.4,
222
+ color: "rgba(60, 60, 70, 0.85)"
223
+ },
224
+ children: hint
225
+ }),
226
+ dims && /* @__PURE__ */ jsx("span", {
227
+ style: {
228
+ fontSize: 11,
229
+ fontVariantNumeric: "tabular-nums",
230
+ fontFamily: "ui-monospace, \"SF Mono\", Menlo, Consolas, monospace",
231
+ opacity: .5,
232
+ marginTop: 2
233
+ },
234
+ children: dims
235
+ })
236
+ ]
237
+ }),
238
+ import.meta.env.DEV && (dragActive || uploading) && /* @__PURE__ */ jsx(DropOverlay, { label: uploading ? t.imagePlaceholder.uploading : t.imagePlaceholder.dropOverlay })
239
+ ]
240
+ });
241
+ }
242
+ function DropOverlay({ label }) {
243
+ return /* @__PURE__ */ jsx("div", {
244
+ "aria-hidden": true,
245
+ style: {
246
+ position: "absolute",
247
+ inset: 0,
248
+ pointerEvents: "none",
249
+ borderRadius: 12,
250
+ border: "2px dashed oklch(0.62 0.18 250)",
251
+ background: "oklch(0.62 0.18 250 / 0.08)",
252
+ display: "flex",
253
+ alignItems: "center",
254
+ justifyContent: "center"
255
+ },
256
+ children: /* @__PURE__ */ jsx("span", {
257
+ style: {
258
+ fontSize: 12,
259
+ fontWeight: 600,
260
+ letterSpacing: "0.02em",
261
+ color: "oklch(0.45 0.16 250)",
262
+ background: "rgba(255,255,255,0.92)",
263
+ padding: "6px 10px",
264
+ borderRadius: 6,
265
+ boxShadow: "0 1px 2px rgba(0,0,0,0.08)"
266
+ },
267
+ children: label
268
+ })
269
+ });
270
+ }
271
+ function hasImageFile(e) {
272
+ const types = e.dataTransfer?.types;
273
+ if (!types) return false;
274
+ for (let i = 0; i < types.length; i++) if (types[i] === "Files") return true;
275
+ return false;
276
+ }
277
+ function pickImageFile(files) {
278
+ for (let i = 0; i < files.length; i++) {
279
+ const f = files[i];
280
+ if (f.type.startsWith("image/")) return f;
281
+ }
282
+ return null;
283
+ }
284
+ async function handleDrop(slideId, file, line, column) {
285
+ const { ok, entry } = await uploadWithAutoRename(slideId, file);
286
+ if (!ok || !entry) throw new Error("upload failed");
287
+ const res = await fetch("/__edit", {
288
+ method: "POST",
289
+ headers: { "content-type": "application/json" },
290
+ body: JSON.stringify({
291
+ slideId,
292
+ line,
293
+ column,
294
+ ops: [{
295
+ kind: "replace-placeholder-with-image",
296
+ assetPath: `./assets/${entry.name}`
297
+ }]
298
+ })
299
+ });
300
+ if (!res.ok) throw new Error(`edit failed (${res.status})`);
301
+ }
302
+ function PlaceholderIcon() {
303
+ return /* @__PURE__ */ jsxs("svg", {
304
+ width: "32",
305
+ height: "32",
306
+ viewBox: "0 0 32 32",
307
+ fill: "none",
308
+ stroke: "currentColor",
309
+ strokeWidth: "1.5",
310
+ strokeLinecap: "round",
311
+ strokeLinejoin: "round",
312
+ style: { opacity: .55 },
313
+ role: "img",
314
+ "aria-label": "image placeholder",
315
+ children: [
316
+ /* @__PURE__ */ jsx("title", { children: "image placeholder" }),
317
+ /* @__PURE__ */ jsx("rect", {
318
+ x: "4",
319
+ y: "6",
320
+ width: "24",
321
+ height: "20",
322
+ rx: "2.5"
323
+ }),
324
+ /* @__PURE__ */ jsx("circle", {
325
+ cx: "11",
326
+ cy: "13",
327
+ r: "2"
328
+ }),
329
+ /* @__PURE__ */ jsx("path", { d: "M4 22l7-7 6 6 4-4 7 7" })
330
+ ]
331
+ });
332
+ }
333
+
334
+ //#endregion
335
+ //#region src/app/components/shared-element.tsx
336
+ function unstable_SharedElement({ id, children, className, style }) {
337
+ const child = Children.toArray(children)[0] ?? null;
338
+ if (Children.count(children) === 1 && isValidElement(child) && typeof child.type === "string") return cloneElement(child, {
339
+ "data-osd-shared-element": id,
340
+ className: [child.props.className, className].filter(Boolean).join(" ") || void 0,
341
+ style: style ? {
342
+ ...child.props.style,
343
+ ...style
344
+ } : child.props.style
345
+ });
346
+ return /* @__PURE__ */ jsx("div", {
347
+ className,
348
+ style,
349
+ "data-osd-shared-element": id,
350
+ children
351
+ });
352
+ }
353
+
354
+ //#endregion
355
+ //#region src/app/lib/page-context.tsx
356
+ const GLOBAL_KEY$1 = "__open_aippt_page_context__";
357
+ const g$1 = globalThis;
358
+ if (!g$1[GLOBAL_KEY$1]) g$1[GLOBAL_KEY$1] = createContext(null);
359
+ const SlidePageContext = g$1[GLOBAL_KEY$1];
360
+ function useSlidePageNumber() {
361
+ const ctx = useContext(SlidePageContext);
362
+ if (!ctx) throw new Error("useSlidePageNumber must be called from a slide page rendered by @open-aippt/core");
363
+ return {
364
+ current: ctx.index + 1,
365
+ total: ctx.total
366
+ };
367
+ }
368
+
369
+ //#endregion
370
+ //#region src/app/lib/sdk.ts
371
+ const CANVAS_WIDTH = 1920;
372
+ const CANVAS_HEIGHT = 1080;
373
+
374
+ //#endregion
375
+ //#region src/app/lib/use-prefers-reduced-motion.ts
376
+ const QUERY = "(prefers-reduced-motion: reduce)";
377
+ function usePrefersReducedMotion() {
378
+ const [reduce, setReduce] = useState(() => {
379
+ if (typeof window === "undefined") return false;
380
+ return window.matchMedia(QUERY).matches;
381
+ });
382
+ useEffect(() => {
383
+ const mql = window.matchMedia(QUERY);
384
+ const onChange = (e) => setReduce(e.matches);
385
+ mql.addEventListener("change", onChange);
386
+ return () => mql.removeEventListener("change", onChange);
387
+ }, []);
388
+ return reduce;
389
+ }
390
+
391
+ //#endregion
392
+ //#region src/app/lib/step-context.tsx
393
+ const GLOBAL_KEY = "__open_aippt_step_host_context__";
394
+ const g = globalThis;
395
+ if (!g[GLOBAL_KEY]) g[GLOBAL_KEY] = createContext(null);
396
+ const StepHostContext = g[GLOBAL_KEY];
397
+ function Steps({ children }) {
398
+ const host = useContext(StepHostContext);
399
+ const flat = Children.toArray(children);
400
+ const stepCount = flat.filter((c) => isValidElement(c) && c.type === Step).length;
401
+ const initial = host?.controlled ? 0 : host?.entryDirection === "forward" ? 0 : stepCount;
402
+ const revealedRef = useRef(initial);
403
+ const [revealed, setRevealed] = useState(initial);
404
+ const idRef = useRef({});
405
+ const applyRevealed = useCallback((n) => {
406
+ revealedRef.current = n;
407
+ setRevealed(n);
408
+ }, []);
409
+ useLayoutEffect(() => {
410
+ if (!host) return;
411
+ const id = idRef.current;
412
+ const ctrl = {
413
+ advance: () => {
414
+ if (revealedRef.current >= stepCount) return false;
415
+ applyRevealed(revealedRef.current + 1);
416
+ host.reportRevealed(id, revealedRef.current);
417
+ return true;
418
+ },
419
+ retreat: () => {
420
+ if (revealedRef.current <= 0) return false;
421
+ applyRevealed(revealedRef.current - 1);
422
+ host.reportRevealed(id, revealedRef.current);
423
+ return true;
424
+ }
425
+ };
426
+ return host.register({
427
+ id,
428
+ stepCount,
429
+ initialRevealed: revealedRef.current,
430
+ controller: ctrl,
431
+ setRevealed: applyRevealed
432
+ });
433
+ }, [
434
+ host,
435
+ stepCount,
436
+ applyRevealed
437
+ ]);
438
+ const effectiveRevealed = host ? revealed : stepCount;
439
+ let stepIdx = 0;
440
+ return /* @__PURE__ */ jsx(Fragment, { children: flat.map((child, key) => {
441
+ if (isValidElement(child) && child.type === Step) {
442
+ const idx = stepIdx++;
443
+ return cloneElement(child, {
444
+ key: child.key ?? key,
445
+ _revealed: idx < effectiveRevealed
446
+ });
447
+ }
448
+ return child;
449
+ }) });
450
+ }
451
+ function Step({ children, duration = 180, _revealed }) {
452
+ const reduceMotion = usePrefersReducedMotion();
453
+ const revealed = _revealed ?? true;
454
+ const ms = reduceMotion ? 0 : duration;
455
+ return /* @__PURE__ */ jsx("div", {
456
+ "data-osd-step": revealed ? "revealed" : "pending",
457
+ style: {
458
+ opacity: revealed ? 1 : 0,
459
+ visibility: revealed ? "visible" : "hidden",
460
+ transition: `opacity ${ms}ms cubic-bezier(0, 0, 0.2, 1)`
461
+ },
462
+ children
463
+ });
464
+ }
465
+
466
+ //#endregion
467
+ export { CANVAS_HEIGHT, CANVAS_WIDTH, ImagePlaceholder, Step, Steps, cssVarsToString, defaultDesign, designToCssVars, unstable_SharedElement, useSlidePageNumber };
@@ -0,0 +1,24 @@
1
+ import { Locale, Plural } from "../types-CHmFPIG_.js";
2
+
3
+ //#region src/locale/en.d.ts
4
+ declare const en: Locale;
5
+
6
+ //#endregion
7
+ //#region src/locale/format.d.ts
8
+ declare function format(template: string, vars: Record<string, string | number>): string;
9
+ declare function plural(count: number, forms: Plural): string;
10
+
11
+ //#endregion
12
+ //#region src/locale/ja.d.ts
13
+ declare const ja: Locale;
14
+
15
+ //#endregion
16
+ //#region src/locale/zh-cn.d.ts
17
+ declare const zhCN: Locale;
18
+
19
+ //#endregion
20
+ //#region src/locale/zh-tw.d.ts
21
+ declare const zhTW: Locale;
22
+
23
+ //#endregion
24
+ export { Locale, Plural, en, format, ja, plural, zhCN, zhTW };
@@ -0,0 +1,3 @@
1
+ import { en, format, ja, plural, zhCN, zhTW } from "../format-BCeKbTOM.js";
2
+
3
+ export { en, format, ja, plural, zhCN, zhTW };
@@ -0,0 +1,18 @@
1
+ import "./design-cpzS8aud.js";
2
+ import { createViteConfig } from "./config-CjzqjrEA.js";
3
+ import { mergeConfig, preview as preview$1 } from "vite";
4
+
5
+ //#region src/cli/preview.ts
6
+ async function preview(opts = {}) {
7
+ const base = await createViteConfig({ userCwd: process.cwd() });
8
+ const config = mergeConfig(base, { preview: {
9
+ ...opts.port !== void 0 ? { port: opts.port } : {},
10
+ ...opts.host !== void 0 ? { host: opts.host } : {},
11
+ ...opts.open !== void 0 ? { open: opts.open } : {}
12
+ } });
13
+ const server = await preview$1(config);
14
+ server.printUrls();
15
+ }
16
+
17
+ //#endregion
18
+ export { preview };