@open-slide/core 1.0.6 → 1.2.0
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/dist/{build-4wOJF1l4.js → build-6BeQ3cxb.js} +1 -1
- package/dist/cli/bin.js +3 -3
- package/dist/{config-evLWCV1-.js → config-AxZ5OE1u.js} +772 -201
- package/dist/{config-D2y1AXaN.d.ts → config-CtT8K4VF.d.ts} +1 -1
- package/dist/{dev-BUr0S-Ij.js → dev-C9eLmUEq.js} +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/locale/index.d.ts +1 -1
- package/dist/locale/index.js +136 -24
- package/dist/{preview-DP_gIphz.js → preview-Cunm-f4i.js} +1 -1
- package/dist/{types-BVvl_xup.d.ts → types-CRHIeoNq.d.ts} +37 -4
- package/dist/vite/index.d.ts +2 -2
- package/dist/vite/index.js +1 -1
- package/package.json +5 -1
- package/skills/current-slide/SKILL.md +110 -0
- package/skills/slide-authoring/SKILL.md +48 -1
- package/src/app/components/inspector/image-crop-dialog.tsx +212 -0
- package/src/app/components/inspector/inspect-overlay.tsx +17 -2
- package/src/app/components/inspector/inspector-panel.tsx +90 -26
- package/src/app/components/inspector/inspector-provider.tsx +136 -1
- package/src/app/components/notes-drawer.tsx +117 -0
- package/src/app/components/player.tsx +26 -8
- package/src/app/components/present/overview-grid.tsx +2 -2
- package/src/app/components/present/use-idle.ts +6 -4
- package/src/app/components/style-panel/design-provider.tsx +13 -0
- package/src/app/components/style-panel/style-panel.tsx +23 -11
- package/src/app/components/thumbnail-rail.tsx +317 -55
- package/src/app/components/ui/context-menu.tsx +237 -0
- package/src/app/lib/design-presets.ts +94 -0
- package/src/app/lib/inspector/use-notes.ts +134 -0
- package/src/app/routes/home.tsx +34 -12
- package/src/app/routes/presenter.tsx +27 -24
- package/src/app/routes/slide.tsx +238 -51
- package/src/locale/en.ts +35 -4
- package/src/locale/ja.ts +35 -4
- package/src/locale/types.ts +38 -4
- package/src/locale/zh-cn.ts +35 -4
- package/src/locale/zh-tw.ts +35 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Locale, Plural } from "./types-
|
|
2
|
-
import { OpenSlideConfig } from "./config-
|
|
1
|
+
import { Locale, Plural } from "./types-CRHIeoNq.js";
|
|
2
|
+
import { OpenSlideConfig } from "./config-CtT8K4VF.js";
|
|
3
3
|
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
4
4
|
import { CSSProperties, ComponentType, HTMLAttributes } from "react";
|
|
5
5
|
|
package/dist/locale/index.d.ts
CHANGED
package/dist/locale/index.js
CHANGED
|
@@ -78,6 +78,8 @@ const en = {
|
|
|
78
78
|
slide: {
|
|
79
79
|
home: "Home",
|
|
80
80
|
backToHome: "Back to home",
|
|
81
|
+
agentConnected: "Agent connected",
|
|
82
|
+
agentConnectedTooltip: "The dev server is publishing your current slide and inspector selection to your agent. Ask \"this slide\" or \"this element\" in chat and it will resolve. Disappears in production builds.",
|
|
81
83
|
download: "Download",
|
|
82
84
|
exportAsHtml: "Export as HTML",
|
|
83
85
|
exportAsPdf: "Export as PDF",
|
|
@@ -148,6 +150,8 @@ const en = {
|
|
|
148
150
|
inspector: {
|
|
149
151
|
inspect: "Inspect",
|
|
150
152
|
deselect: "Deselect",
|
|
153
|
+
agentWatching: "Agent is watching",
|
|
154
|
+
agentWatchingTooltip: "Your agent already sees the selected element via the dev server — just ask it in chat. Leave comments here only when you want to queue a few before asking.",
|
|
151
155
|
contentSection: "Content",
|
|
152
156
|
typographySection: "Typography",
|
|
153
157
|
colorSection: "Color",
|
|
@@ -177,10 +181,17 @@ const en = {
|
|
|
177
181
|
pickerLoading: "Loading…",
|
|
178
182
|
pickerEmpty: "No images in this slide's assets folder yet. Add some from the Assets tab.",
|
|
179
183
|
placeholderHintLabel: "Hint:",
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
+
crop: "Crop…",
|
|
185
|
+
cropDialogTitle: "Crop image",
|
|
186
|
+
cropDialogDescription: "Drag the frame to choose what stays visible.",
|
|
187
|
+
cropFitCover: "Fill",
|
|
188
|
+
cropFitContain: "Fit",
|
|
189
|
+
cropApply: "Apply",
|
|
190
|
+
cropResetAria: "Reset crop",
|
|
191
|
+
leaveComment: "Leave a comment",
|
|
192
|
+
commentPlaceholder: "Describe a change for the agent…",
|
|
193
|
+
commentShortcutHint: "⌘↵ to add",
|
|
194
|
+
addComment: "Add comment",
|
|
184
195
|
unsavedChanges: {
|
|
185
196
|
one: "{count} unsaved change",
|
|
186
197
|
other: "{count} unsaved changes"
|
|
@@ -214,7 +225,9 @@ const en = {
|
|
|
214
225
|
radiusLabel: "Radius",
|
|
215
226
|
designToggle: "Design",
|
|
216
227
|
designToggleTitle: "Design tokens",
|
|
217
|
-
fontPresetCustom: "Custom…"
|
|
228
|
+
fontPresetCustom: "Custom…",
|
|
229
|
+
shuffleAria: "Shuffle design",
|
|
230
|
+
shuffleTitle: "Shuffle for inspiration"
|
|
218
231
|
},
|
|
219
232
|
asset: {
|
|
220
233
|
devOnlyMessage: "Asset management is only available in dev mode.",
|
|
@@ -270,7 +283,14 @@ const en = {
|
|
|
270
283
|
},
|
|
271
284
|
thumbnailRail: {
|
|
272
285
|
pages: "Pages",
|
|
273
|
-
goToPageAria: "Go to page {n}"
|
|
286
|
+
goToPageAria: "Go to page {n}",
|
|
287
|
+
duplicatePage: "Duplicate",
|
|
288
|
+
deletePage: "Delete",
|
|
289
|
+
pageActionsAria: "Page {n} actions",
|
|
290
|
+
toastDuplicated: "Duplicated page {n}",
|
|
291
|
+
toastDeleted: "Deleted page {n}",
|
|
292
|
+
toastDuplicateFailed: "Could not duplicate page",
|
|
293
|
+
toastDeleteFailed: "Could not delete page"
|
|
274
294
|
},
|
|
275
295
|
pdfToast: {
|
|
276
296
|
title: "Exporting PDF",
|
|
@@ -288,6 +308,14 @@ const en = {
|
|
|
288
308
|
clickNav: {
|
|
289
309
|
prevAria: "Previous page",
|
|
290
310
|
nextAria: "Next page"
|
|
311
|
+
},
|
|
312
|
+
notesDrawer: {
|
|
313
|
+
toggle: "Notes",
|
|
314
|
+
pageLabel: "page {n}/{total}",
|
|
315
|
+
placeholder: "Write speaker notes for this slide…",
|
|
316
|
+
statusSaving: "Saving…",
|
|
317
|
+
statusSaved: "Saved",
|
|
318
|
+
statusError: "Save failed: {msg}"
|
|
291
319
|
}
|
|
292
320
|
};
|
|
293
321
|
|
|
@@ -382,6 +410,8 @@ const ja = {
|
|
|
382
410
|
pickIcon: "アイコンを選択"
|
|
383
411
|
},
|
|
384
412
|
slide: {
|
|
413
|
+
agentConnected: "エージェント接続中",
|
|
414
|
+
agentConnectedTooltip: "現在のスライドと Inspector の選択状態を dev server がエージェントに公開しています。チャットで「このスライド」「この要素」と言えば認識されます。本番ビルドでは表示されません。",
|
|
385
415
|
home: "ホーム",
|
|
386
416
|
backToHome: "ホームへ戻る",
|
|
387
417
|
download: "ダウンロード",
|
|
@@ -483,10 +513,19 @@ const ja = {
|
|
|
483
513
|
pickerLoading: "読み込み中…",
|
|
484
514
|
pickerEmpty: "このスライドのアセットフォルダにまだ画像がありません。「アセット」タブから追加してください。",
|
|
485
515
|
placeholderHintLabel: "ヒント:",
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
516
|
+
crop: "トリミング…",
|
|
517
|
+
cropDialogTitle: "画像をトリミング",
|
|
518
|
+
cropDialogDescription: "枠をドラッグして表示する範囲を選択します。",
|
|
519
|
+
cropFitCover: "塗りつぶす",
|
|
520
|
+
cropFitContain: "全体表示",
|
|
521
|
+
cropApply: "適用",
|
|
522
|
+
cropResetAria: "トリミングをリセット",
|
|
523
|
+
agentWatching: "エージェント監視中",
|
|
524
|
+
agentWatchingTooltip: "エージェントは選択中の要素を dev server 経由で把握しています。直接チャットで頼めます。ここにコメントを残すのは、複数の依頼をまとめて出したいときだけで OK。",
|
|
525
|
+
leaveComment: "コメントを残す",
|
|
526
|
+
commentPlaceholder: "エージェントに依頼する変更を記述…",
|
|
527
|
+
commentShortcutHint: "⌘↵ で追加",
|
|
528
|
+
addComment: "コメントを追加",
|
|
490
529
|
unsavedChanges: {
|
|
491
530
|
one: "未保存の変更 {count} 件",
|
|
492
531
|
other: "未保存の変更 {count} 件"
|
|
@@ -520,7 +559,9 @@ const ja = {
|
|
|
520
559
|
radiusLabel: "角丸",
|
|
521
560
|
designToggle: "デザイン",
|
|
522
561
|
designToggleTitle: "デザイントークン",
|
|
523
|
-
fontPresetCustom: "カスタム…"
|
|
562
|
+
fontPresetCustom: "カスタム…",
|
|
563
|
+
shuffleAria: "デザインをシャッフル",
|
|
564
|
+
shuffleTitle: "シャッフルしてインスピレーションを得る"
|
|
524
565
|
},
|
|
525
566
|
asset: {
|
|
526
567
|
devOnlyMessage: "アセット管理は開発モードでのみ利用できます。",
|
|
@@ -576,7 +617,14 @@ const ja = {
|
|
|
576
617
|
},
|
|
577
618
|
thumbnailRail: {
|
|
578
619
|
pages: "ページ",
|
|
579
|
-
goToPageAria: "ページ {n} へ移動"
|
|
620
|
+
goToPageAria: "ページ {n} へ移動",
|
|
621
|
+
duplicatePage: "複製",
|
|
622
|
+
deletePage: "削除",
|
|
623
|
+
pageActionsAria: "ページ {n} の操作",
|
|
624
|
+
toastDuplicated: "ページ {n} を複製しました",
|
|
625
|
+
toastDeleted: "ページ {n} を削除しました",
|
|
626
|
+
toastDuplicateFailed: "ページを複製できませんでした",
|
|
627
|
+
toastDeleteFailed: "ページを削除できませんでした"
|
|
580
628
|
},
|
|
581
629
|
pdfToast: {
|
|
582
630
|
title: "PDF を書き出し中",
|
|
@@ -594,6 +642,14 @@ const ja = {
|
|
|
594
642
|
clickNav: {
|
|
595
643
|
prevAria: "前のページ",
|
|
596
644
|
nextAria: "次のページ"
|
|
645
|
+
},
|
|
646
|
+
notesDrawer: {
|
|
647
|
+
toggle: "発表者ノート",
|
|
648
|
+
pageLabel: "{n} / {total} ページ",
|
|
649
|
+
placeholder: "このスライドの発表者ノートを記入…",
|
|
650
|
+
statusSaving: "保存中…",
|
|
651
|
+
statusSaved: "保存済み",
|
|
652
|
+
statusError: "保存に失敗しました: {msg}"
|
|
597
653
|
}
|
|
598
654
|
};
|
|
599
655
|
|
|
@@ -676,6 +732,8 @@ const zhCN = {
|
|
|
676
732
|
pickIcon: "选择图标"
|
|
677
733
|
},
|
|
678
734
|
slide: {
|
|
735
|
+
agentConnected: "Agent 已连接",
|
|
736
|
+
agentConnectedTooltip: "Dev server 正在把你目前在哪张 slide、Inspector 选了哪个元素发布给 agent。直接到聊天说\"这张 slide\"或\"这个元素\"就行。Production build 不会出现。",
|
|
679
737
|
home: "首页",
|
|
680
738
|
backToHome: "返回首页",
|
|
681
739
|
download: "下载",
|
|
@@ -777,10 +835,19 @@ const zhCN = {
|
|
|
777
835
|
pickerLoading: "加载中…",
|
|
778
836
|
pickerEmpty: "该幻灯片的素材文件夹中尚无图片。请从「素材」标签页添加。",
|
|
779
837
|
placeholderHintLabel: "提示:",
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
838
|
+
crop: "裁剪…",
|
|
839
|
+
cropDialogTitle: "裁剪图片",
|
|
840
|
+
cropDialogDescription: "拖动框线决定要保留的可见区域。",
|
|
841
|
+
cropFitCover: "填满",
|
|
842
|
+
cropFitContain: "完整显示",
|
|
843
|
+
cropApply: "应用",
|
|
844
|
+
cropResetAria: "重置裁剪",
|
|
845
|
+
agentWatching: "Agent 正在关注",
|
|
846
|
+
agentWatchingTooltip: "Agent 已经通过 dev server 看到你选的元素了,直接到聊天请它修改就行。想累积几个再一次问才需要在这里留 comments。",
|
|
847
|
+
leaveComment: "留个 comment",
|
|
848
|
+
commentPlaceholder: "描述你希望代理执行的更改…",
|
|
849
|
+
commentShortcutHint: "⌘↵ 添加",
|
|
850
|
+
addComment: "添加 comment",
|
|
784
851
|
unsavedChanges: {
|
|
785
852
|
one: "{count} 项未保存的更改",
|
|
786
853
|
other: "{count} 项未保存的更改"
|
|
@@ -814,7 +881,9 @@ const zhCN = {
|
|
|
814
881
|
radiusLabel: "圆角",
|
|
815
882
|
designToggle: "设计",
|
|
816
883
|
designToggleTitle: "设计样式",
|
|
817
|
-
fontPresetCustom: "自定义…"
|
|
884
|
+
fontPresetCustom: "自定义…",
|
|
885
|
+
shuffleAria: "随机设计",
|
|
886
|
+
shuffleTitle: "随机配色获取灵感"
|
|
818
887
|
},
|
|
819
888
|
asset: {
|
|
820
889
|
devOnlyMessage: "素材管理仅在开发模式下可用。",
|
|
@@ -870,7 +939,14 @@ const zhCN = {
|
|
|
870
939
|
},
|
|
871
940
|
thumbnailRail: {
|
|
872
941
|
pages: "页面",
|
|
873
|
-
goToPageAria: "前往第 {n} 页"
|
|
942
|
+
goToPageAria: "前往第 {n} 页",
|
|
943
|
+
duplicatePage: "复制",
|
|
944
|
+
deletePage: "删除",
|
|
945
|
+
pageActionsAria: "第 {n} 页的操作",
|
|
946
|
+
toastDuplicated: "已复制第 {n} 页",
|
|
947
|
+
toastDeleted: "已删除第 {n} 页",
|
|
948
|
+
toastDuplicateFailed: "无法复制页面",
|
|
949
|
+
toastDeleteFailed: "无法删除页面"
|
|
874
950
|
},
|
|
875
951
|
pdfToast: {
|
|
876
952
|
title: "导出 PDF",
|
|
@@ -888,6 +964,14 @@ const zhCN = {
|
|
|
888
964
|
clickNav: {
|
|
889
965
|
prevAria: "上一页",
|
|
890
966
|
nextAria: "下一页"
|
|
967
|
+
},
|
|
968
|
+
notesDrawer: {
|
|
969
|
+
toggle: "演讲备注",
|
|
970
|
+
pageLabel: "第 {n} / {total} 页",
|
|
971
|
+
placeholder: "为这一页撰写演讲备注…",
|
|
972
|
+
statusSaving: "保存中…",
|
|
973
|
+
statusSaved: "已保存",
|
|
974
|
+
statusError: "保存失败:{msg}"
|
|
891
975
|
}
|
|
892
976
|
};
|
|
893
977
|
|
|
@@ -970,6 +1054,8 @@ const zhTW = {
|
|
|
970
1054
|
pickIcon: "選擇圖示"
|
|
971
1055
|
},
|
|
972
1056
|
slide: {
|
|
1057
|
+
agentConnected: "Agent 已連線",
|
|
1058
|
+
agentConnectedTooltip: "Dev server 正在把你目前在哪張 slide、Inspector 選了哪個元素發布給 agent。直接到聊天說「這張 slide」或「這個元素」就行。Production build 不會出現。",
|
|
973
1059
|
home: "首頁",
|
|
974
1060
|
backToHome: "返回首頁",
|
|
975
1061
|
download: "下載",
|
|
@@ -1071,10 +1157,19 @@ const zhTW = {
|
|
|
1071
1157
|
pickerLoading: "載入中…",
|
|
1072
1158
|
pickerEmpty: "此投影片的素材資料夾尚未有圖片。請從「素材」分頁加入。",
|
|
1073
1159
|
placeholderHintLabel: "提示:",
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1160
|
+
crop: "裁切…",
|
|
1161
|
+
cropDialogTitle: "裁切圖片",
|
|
1162
|
+
cropDialogDescription: "拖曳框線決定要保留的可見範圍。",
|
|
1163
|
+
cropFitCover: "填滿",
|
|
1164
|
+
cropFitContain: "完整顯示",
|
|
1165
|
+
cropApply: "套用",
|
|
1166
|
+
cropResetAria: "重設裁切",
|
|
1167
|
+
agentWatching: "Agent 正在關注",
|
|
1168
|
+
agentWatchingTooltip: "Agent 已經透過 dev server 看到你選的元素了,直接到聊天請它修改就行。想累積幾個再一次問才需要在這裡留 comments。",
|
|
1169
|
+
leaveComment: "留個 comment",
|
|
1170
|
+
commentPlaceholder: "描述你希望代理進行的修改…",
|
|
1171
|
+
commentShortcutHint: "⌘↵ 新增",
|
|
1172
|
+
addComment: "新增 comment",
|
|
1078
1173
|
unsavedChanges: {
|
|
1079
1174
|
one: "{count} 項未儲存的變更",
|
|
1080
1175
|
other: "{count} 項未儲存的變更"
|
|
@@ -1108,7 +1203,9 @@ const zhTW = {
|
|
|
1108
1203
|
radiusLabel: "圓角",
|
|
1109
1204
|
designToggle: "設計",
|
|
1110
1205
|
designToggleTitle: "設計樣式",
|
|
1111
|
-
fontPresetCustom: "自訂…"
|
|
1206
|
+
fontPresetCustom: "自訂…",
|
|
1207
|
+
shuffleAria: "隨機設計",
|
|
1208
|
+
shuffleTitle: "隨機配色獲取靈感"
|
|
1112
1209
|
},
|
|
1113
1210
|
asset: {
|
|
1114
1211
|
devOnlyMessage: "素材管理僅在開發模式下可用。",
|
|
@@ -1164,7 +1261,14 @@ const zhTW = {
|
|
|
1164
1261
|
},
|
|
1165
1262
|
thumbnailRail: {
|
|
1166
1263
|
pages: "頁面",
|
|
1167
|
-
goToPageAria: "前往第 {n} 頁"
|
|
1264
|
+
goToPageAria: "前往第 {n} 頁",
|
|
1265
|
+
duplicatePage: "複製",
|
|
1266
|
+
deletePage: "刪除",
|
|
1267
|
+
pageActionsAria: "第 {n} 頁的操作",
|
|
1268
|
+
toastDuplicated: "已複製第 {n} 頁",
|
|
1269
|
+
toastDeleted: "已刪除第 {n} 頁",
|
|
1270
|
+
toastDuplicateFailed: "無法複製頁面",
|
|
1271
|
+
toastDeleteFailed: "無法刪除頁面"
|
|
1168
1272
|
},
|
|
1169
1273
|
pdfToast: {
|
|
1170
1274
|
title: "匯出 PDF",
|
|
@@ -1182,6 +1286,14 @@ const zhTW = {
|
|
|
1182
1286
|
clickNav: {
|
|
1183
1287
|
prevAria: "上一頁",
|
|
1184
1288
|
nextAria: "下一頁"
|
|
1289
|
+
},
|
|
1290
|
+
notesDrawer: {
|
|
1291
|
+
toggle: "講稿",
|
|
1292
|
+
pageLabel: "第 {n} / {total} 頁",
|
|
1293
|
+
placeholder: "為這一頁撰寫演講備忘…",
|
|
1294
|
+
statusSaving: "儲存中…",
|
|
1295
|
+
statusSaved: "已儲存",
|
|
1296
|
+
statusError: "儲存失敗:{msg}"
|
|
1185
1297
|
}
|
|
1186
1298
|
};
|
|
1187
1299
|
|
|
@@ -85,6 +85,8 @@ type Locale = {
|
|
|
85
85
|
slide: {
|
|
86
86
|
home: string;
|
|
87
87
|
backToHome: string;
|
|
88
|
+
agentConnected: string;
|
|
89
|
+
agentConnectedTooltip: string;
|
|
88
90
|
download: string;
|
|
89
91
|
exportAsHtml: string;
|
|
90
92
|
exportAsPdf: string;
|
|
@@ -157,6 +159,8 @@ type Locale = {
|
|
|
157
159
|
inspector: {
|
|
158
160
|
inspect: string;
|
|
159
161
|
deselect: string;
|
|
162
|
+
agentWatching: string;
|
|
163
|
+
agentWatchingTooltip: string;
|
|
160
164
|
contentSection: string;
|
|
161
165
|
typographySection: string;
|
|
162
166
|
colorSection: string;
|
|
@@ -187,10 +191,17 @@ type Locale = {
|
|
|
187
191
|
pickerLoading: string;
|
|
188
192
|
pickerEmpty: string;
|
|
189
193
|
placeholderHintLabel: string;
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
+
crop: string;
|
|
195
|
+
cropDialogTitle: string;
|
|
196
|
+
cropDialogDescription: string;
|
|
197
|
+
cropFitCover: string;
|
|
198
|
+
cropFitContain: string;
|
|
199
|
+
cropApply: string;
|
|
200
|
+
cropResetAria: string;
|
|
201
|
+
leaveComment: string;
|
|
202
|
+
commentPlaceholder: string;
|
|
203
|
+
commentShortcutHint: string;
|
|
204
|
+
addComment: string;
|
|
194
205
|
/** templates: "{count} unsaved change" / "{count} unsaved changes" */
|
|
195
206
|
unsavedChanges: Plural;
|
|
196
207
|
/** templates: "{count} comment" / "{count} comments" */
|
|
@@ -223,6 +234,8 @@ type Locale = {
|
|
|
223
234
|
designToggle: string;
|
|
224
235
|
designToggleTitle: string;
|
|
225
236
|
fontPresetCustom: string;
|
|
237
|
+
shuffleAria: string;
|
|
238
|
+
shuffleTitle: string;
|
|
226
239
|
};
|
|
227
240
|
asset: {
|
|
228
241
|
devOnlyMessage: string;
|
|
@@ -291,6 +304,16 @@ type Locale = {
|
|
|
291
304
|
pages: string;
|
|
292
305
|
/** template: "Go to page {n}" */
|
|
293
306
|
goToPageAria: string;
|
|
307
|
+
duplicatePage: string;
|
|
308
|
+
deletePage: string;
|
|
309
|
+
/** template: "Page {n} actions" */
|
|
310
|
+
pageActionsAria: string;
|
|
311
|
+
/** template: "Duplicated page {n}" */
|
|
312
|
+
toastDuplicated: string;
|
|
313
|
+
/** template: "Deleted page {n}" */
|
|
314
|
+
toastDeleted: string;
|
|
315
|
+
toastDuplicateFailed: string;
|
|
316
|
+
toastDeleteFailed: string;
|
|
294
317
|
};
|
|
295
318
|
pdfToast: {
|
|
296
319
|
title: string;
|
|
@@ -310,5 +333,15 @@ type Locale = {
|
|
|
310
333
|
prevAria: string;
|
|
311
334
|
nextAria: string;
|
|
312
335
|
};
|
|
336
|
+
notesDrawer: {
|
|
337
|
+
toggle: string;
|
|
338
|
+
/** template: "page {n}/{total}" */
|
|
339
|
+
pageLabel: string;
|
|
340
|
+
placeholder: string;
|
|
341
|
+
statusSaving: string;
|
|
342
|
+
statusSaved: string;
|
|
343
|
+
/** template: "Save failed: {msg}" */
|
|
344
|
+
statusError: string;
|
|
345
|
+
};
|
|
313
346
|
}; //#endregion
|
|
314
347
|
export { Locale, Plural };
|
package/dist/vite/index.d.ts
CHANGED
package/dist/vite/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-slide/core",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Runtime and CLI for open-slide — write slides in slides/, we handle the rest.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -53,6 +53,9 @@
|
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@babel/parser": "^7.29.2",
|
|
55
55
|
"@babel/types": "^7.29.0",
|
|
56
|
+
"@dnd-kit/core": "^6.3.1",
|
|
57
|
+
"@dnd-kit/sortable": "^10.0.0",
|
|
58
|
+
"@dnd-kit/utilities": "^3.2.2",
|
|
56
59
|
"@fontsource-variable/geist": "^5.2.8",
|
|
57
60
|
"@tailwindcss/vite": "^4.2.2",
|
|
58
61
|
"@vitejs/plugin-react": "^4.3.3",
|
|
@@ -68,6 +71,7 @@
|
|
|
68
71
|
"radix-ui": "^1.4.3",
|
|
69
72
|
"react": "^18.3.1",
|
|
70
73
|
"react-dom": "^18.3.1",
|
|
74
|
+
"react-image-crop": "^11.0.10",
|
|
71
75
|
"react-router-dom": "^6.26.2",
|
|
72
76
|
"shadcn": "^4.3.0",
|
|
73
77
|
"sonner": "^2.0.7",
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: current-slide
|
|
3
|
+
description: Resolve which slide, page, and (optionally) selected element the user is currently viewing in the open-slide dev server. Consult this whenever the user references "this page", "this slide", "this element", "the slide I'm on", "the current page", or any deictic reference to slide content without naming it. Re-read `node_modules/.open-slide/current.json` at the start of every such turn — the user navigates between turns, so a value you read earlier in the conversation is almost certainly stale.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Where is the user right now?
|
|
7
|
+
|
|
8
|
+
When the user says "fix this page", "tweak this heading", or "the slide I'm looking at", they almost never name the slide id, page number, or element — they mean wherever they are in the dev viewer. Before asking "which slide?" or "which element?", check the file the dev server writes on every navigation and inspector pick.
|
|
9
|
+
|
|
10
|
+
## Re-read on every deictic turn — never reuse a prior read
|
|
11
|
+
|
|
12
|
+
`current.json` is a live cursor, not a fact about the conversation. The user moves between slides, pages, and elements freely between your turns — including while you were doing other work. **Read the file fresh at the start of every new turn that uses a deictic reference**, even if:
|
|
13
|
+
|
|
14
|
+
- you already read it earlier in this same conversation,
|
|
15
|
+
- you just finished editing the slide it pointed to,
|
|
16
|
+
- the user's new message sounds like a continuation ("now make it bigger", "also fix this one", "keep going").
|
|
17
|
+
|
|
18
|
+
A "continue editing" follow-up is exactly the case where the user has likely just navigated to a different slide or picked a different element. Trusting your last read here will silently edit the wrong file. Re-read, compare `slideId` / `pageIndex` / `selection` against what you used last time, and act on the new values.
|
|
19
|
+
|
|
20
|
+
## How to read it
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
node_modules/.open-slide/current.json
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Path is relative to the project root (the user's `cwd`, the directory that contains `slides/` and `package.json`). Use the `Read` tool. The file is JSON.
|
|
27
|
+
|
|
28
|
+
## What you get
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"slideId": "q2-roadmap",
|
|
33
|
+
"pageIndex": 2,
|
|
34
|
+
"pageNumber": 3,
|
|
35
|
+
"totalPages": 8,
|
|
36
|
+
"slideTitle": "Q2 Roadmap",
|
|
37
|
+
"view": "slides",
|
|
38
|
+
"pagePath": "slides/q2-roadmap/index.tsx",
|
|
39
|
+
"selection": {
|
|
40
|
+
"line": 42,
|
|
41
|
+
"column": 6,
|
|
42
|
+
"tagName": "h1",
|
|
43
|
+
"text": "Q2 Roadmap"
|
|
44
|
+
},
|
|
45
|
+
"updatedAt": "2026-05-09T14:32:11.123Z"
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
- `slideId` — folder name under `slides/`. Use as-is for any `/__slides/<id>/...` API or as the URL segment.
|
|
50
|
+
- `pageIndex` — 0-based, for use with the page array in `index.tsx` (`export default [Cover, Body, ...]`).
|
|
51
|
+
- `pageNumber` — 1-based, for use in messages to the user ("page 3 of 8") and for the URL `?p=N`.
|
|
52
|
+
- `pagePath` — relative path to the slide source. Hand straight to `Read` / `Edit`.
|
|
53
|
+
- `view` — `"slides"` (canvas view) or `"assets"` (asset manager). If `"assets"`, the user is browsing files for that slide rather than viewing a page.
|
|
54
|
+
- `selection` — `null` if nothing is selected. Otherwise, the JSX element the user picked in the inspector overlay:
|
|
55
|
+
- `line` (1-indexed) and `column` (0-indexed) point to the JSX opening tag inside `pagePath`. This is the canonical handle — match against the source line, not the rendered DOM.
|
|
56
|
+
- `tagName` is the rendered DOM tag, lowercased (`"h1"`, `"div"`, `"img"`).
|
|
57
|
+
- `text` is a trimmed text snippet (≤120 chars) from the element's `textContent`, useful as a sanity check that you're looking at the right node.
|
|
58
|
+
- Selection auto-clears whenever the user navigates to a different slide or page.
|
|
59
|
+
- `updatedAt` — ISO timestamp of the last navigation or selection change. Use it to detect staleness.
|
|
60
|
+
|
|
61
|
+
## When to use this
|
|
62
|
+
|
|
63
|
+
- The user references the current slide/page deictically: "this", "here", "the page I'm on", "the slide I'm looking at", "what I'm working on".
|
|
64
|
+
- The user references a specific element: "this heading", "this image", "the button I just clicked", "tighten this", "change the color of this". If `selection` is non-null, that's the element they mean.
|
|
65
|
+
- Before asking "which slide?" or "which element?" as a clarifying question — check this file first.
|
|
66
|
+
- Before guessing from `git log`, recently-edited files, or the most recent slide folder.
|
|
67
|
+
|
|
68
|
+
## When NOT to use this
|
|
69
|
+
|
|
70
|
+
- The user names a slide explicitly ("edit `q2-roadmap`") — use that name directly.
|
|
71
|
+
- The `apply-comments` workflow already finds the right file via `@slide-comment` markers; it doesn't need this skill.
|
|
72
|
+
- For listing or discovering slides — read `slides/` directly.
|
|
73
|
+
|
|
74
|
+
## Staleness — verify before acting
|
|
75
|
+
|
|
76
|
+
`updatedAt` is the last time the user navigated. Treat it like a cache:
|
|
77
|
+
|
|
78
|
+
- **Fresh (under ~5 minutes old)**: trust it. Open `pagePath`, do the work.
|
|
79
|
+
- **Older than ~5 minutes, or older than your last interaction with the user**: confirm with the user before editing. The dev server may not be running; the user may have switched contexts.
|
|
80
|
+
- **Hours/days old**: ignore it. Ask the user which slide they mean.
|
|
81
|
+
|
|
82
|
+
A *newer* `updatedAt` than the one you saw last turn is the normal signal that the user has moved — switch to the new `slideId` / `pageIndex` / `selection` without asking.
|
|
83
|
+
|
|
84
|
+
## When the file is missing
|
|
85
|
+
|
|
86
|
+
- The dev server hasn't been opened on a slide yet, or has never run.
|
|
87
|
+
- Don't create the file or guess. Ask the user which slide they mean, or suggest they open the slide in the dev server first.
|
|
88
|
+
|
|
89
|
+
## Example — page-level reference
|
|
90
|
+
|
|
91
|
+
User: "tighten the spacing on this page"
|
|
92
|
+
|
|
93
|
+
1. Read `node_modules/.open-slide/current.json`.
|
|
94
|
+
2. Check `updatedAt` is recent.
|
|
95
|
+
3. Read `pagePath` (e.g. `slides/q2-roadmap/index.tsx`).
|
|
96
|
+
4. Identify the page at `pageIndex` in the default-exported array.
|
|
97
|
+
5. Consult the `slide-authoring` skill for spacing rules, then edit that page in place.
|
|
98
|
+
|
|
99
|
+
If `current.json` is missing or stale, ask: "Which slide and page should I tighten? The dev server hasn't published a current page recently."
|
|
100
|
+
|
|
101
|
+
## Example — element-level reference
|
|
102
|
+
|
|
103
|
+
User: "make this bigger"
|
|
104
|
+
|
|
105
|
+
1. Read `node_modules/.open-slide/current.json`.
|
|
106
|
+
2. If `selection` is non-null, the user means that element. Read `pagePath`, jump to `selection.line`, and find the JSX opening tag near that line/column. Confirm with the snippet in `selection.text` and the `tagName`.
|
|
107
|
+
3. Consult `slide-authoring` for type-scale and layout rules before editing.
|
|
108
|
+
4. Edit the JSX node in place.
|
|
109
|
+
|
|
110
|
+
If `selection` is null, fall back to the page-level flow above — and consider asking "which element?" since the user used a deictic but hasn't picked one in the inspector.
|
|
@@ -9,6 +9,7 @@ This skill is the **technical reference** for everything that happens inside `sl
|
|
|
9
9
|
|
|
10
10
|
- `create-slide` owns "draft a new deck" — it asks the user scoping questions, then delegates the *how* to this skill.
|
|
11
11
|
- `apply-comments` owns "process inspector markers" — it finds markers and applies edits, but the edits themselves follow the rules here.
|
|
12
|
+
- `current-slide` resolves deictic references ("this page", "the slide I'm on") to a concrete `slideId` + `pageIndex`. Consult it **first** when the user references the current slide without naming it, then come back here for how to edit it.
|
|
12
13
|
- Any ad-hoc slide edit (manual tweak, one-off fix) should also consult this skill before touching the file.
|
|
13
14
|
|
|
14
15
|
When any of those paths reach the point of *writing React code for a page*, this is the source of truth. Do not duplicate the knowledge below into other skills — link here instead.
|
|
@@ -19,7 +20,7 @@ When any of those paths reach the point of *writing React code for a page*, this
|
|
|
19
20
|
- Entry is `slides/<id>/index.tsx`. Images/videos/fonts go under `slides/<id>/assets/`.
|
|
20
21
|
- Do **not** touch `package.json`, `open-slide.config.ts`, or other slides.
|
|
21
22
|
- Do not add dependencies. Only `react` and standard web APIs are available.
|
|
22
|
-
- Do not create `
|
|
23
|
+
- A slide is **one `index.tsx` plus `assets/`** — nothing else. Do not create sibling `.tsx`/`.ts` files (`Card.tsx`, `components/`, `helpers.ts`, etc.); helper components and constants go inside `index.tsx`. Do not create `README.md` or other prose files either.
|
|
23
24
|
|
|
24
25
|
## File contract
|
|
25
26
|
|
|
@@ -264,6 +265,50 @@ The user uploads the real file via the Assets panel, then clicks the placeholder
|
|
|
264
265
|
|
|
265
266
|
Size the placeholder to the slot it occupies. Pass `width`/`height` when the layout has a fixed image box; omit them when the placeholder fills a flex/grid cell. The `hint` should describe the *content* the user needs ("Q3 revenue chart") not the *role* ("hero image").
|
|
266
267
|
|
|
268
|
+
## Repeated elements: component, not `map`
|
|
269
|
+
|
|
270
|
+
When a page has visually repeated items — cards, logo rows, gallery tiles, list rows, step indicators — **define a small component and instantiate it once per item**. Do **not** render the group with `array.map` over a data array.
|
|
271
|
+
|
|
272
|
+
Define the component **in the same `index.tsx`**, alongside the `Page` components. Never split it into a sibling file like `Card.tsx` — a slide is always a single `index.tsx` plus its `assets/`.
|
|
273
|
+
|
|
274
|
+
```tsx
|
|
275
|
+
// ✅ Each card is its own JSX node — inspector edits one at a time.
|
|
276
|
+
const Card = ({ src, label }: { src: string; label: string }) => (
|
|
277
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
|
|
278
|
+
<img src={src} style={{ width: 320, height: 320, objectFit: 'cover', borderRadius: 12 }} />
|
|
279
|
+
<p style={{ fontSize: 32 }}>{label}</p>
|
|
280
|
+
</div>
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 64 }}>
|
|
284
|
+
<Card src={alpha} label="Alpha" />
|
|
285
|
+
<Card src={beta} label="Beta" />
|
|
286
|
+
<Card src={gamma} label="Gamma" />
|
|
287
|
+
</div>
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
```tsx
|
|
291
|
+
// ❌ One shared template — replacing the image or text in the inspector
|
|
292
|
+
// changes every rendered card at once.
|
|
293
|
+
const items = [
|
|
294
|
+
{ src: alpha, label: 'Alpha' },
|
|
295
|
+
{ src: beta, label: 'Beta' },
|
|
296
|
+
{ src: gamma, label: 'Gamma' },
|
|
297
|
+
];
|
|
298
|
+
items.map((item) => (
|
|
299
|
+
<div>
|
|
300
|
+
<img src={item.src} />
|
|
301
|
+
<p>{item.label}</p>
|
|
302
|
+
</div>
|
|
303
|
+
));
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
The inspector edits source JSX in place. A `map` body is **one source location** shared by every rendered instance, so when the user replaces an image or tweaks a label there, every card mutates together. Explicit instances give each card its own JSX node and its own props — the unit the inspector can target.
|
|
307
|
+
|
|
308
|
+
The component definition stays the single source of truth for layout/styling (change it once → all cards update). Only the per-instance data — `src`, `label`, accent color — lives at the call site.
|
|
309
|
+
|
|
310
|
+
This applies whenever the *visual element* repeats, not whenever the *data* does. Pure-text lists (`<ul><li>` bullets) are fine: each `<li>` is already its own JSX node, so plain literal markup is the correct shape — no need to wrap them in a component.
|
|
311
|
+
|
|
267
312
|
## Runtime behavior you get for free
|
|
268
313
|
|
|
269
314
|
- Home page lists every folder under `slides/`.
|
|
@@ -282,6 +327,7 @@ Size the placeholder to the slot it occupies. Pass `width`/`height` when the lay
|
|
|
282
327
|
- [ ] One coherent visual direction across every page (palette + type scale).
|
|
283
328
|
- [ ] Slide declares a top-level `export const design: DesignSystem = { … }` and references the values via `var(--osd-X)` (use `design.X` only when you need a JS number for arithmetic). Only omit the `design` const for a one-off slide whose palette is intentionally locked.
|
|
284
329
|
- [ ] One idea per page.
|
|
330
|
+
- [ ] Visually repeated elements (cards, tiles, logo rows) are rendered as explicit `<Component />` instances, not via `array.map` over a data list.
|
|
285
331
|
- [ ] All imported assets exist on disk under `slides/<id>/assets/`.
|
|
286
332
|
- [ ] Every `<ImagePlaceholder>` corresponds to a real image the user must supply — not decorative filler. If it could be replaced by typography or layout, it should be.
|
|
287
333
|
- [ ] Nothing outside `slides/<id>/` was edited.
|
|
@@ -302,3 +348,4 @@ Size the placeholder to the slot it occupies. Pass `width`/`height` when the lay
|
|
|
302
348
|
- ❌ Editing `package.json`, `open-slide.config.ts`, or other slides.
|
|
303
349
|
- ❌ Sprinkling `<ImagePlaceholder>` across pages "for visual interest". Placeholders are for content the user owns; they're not stock-photo slots.
|
|
304
350
|
- ❌ Using a placeholder for an icon or decorative shape — those are typography/SVG problems, not asset problems.
|
|
351
|
+
- ❌ Rendering visually repeated elements with `array.map(...)` over a data array. Define a component and instantiate it explicitly per item (`<Card />`, `<Card />`, `<Card />`) so the inspector can edit each independently — a shared `map` body mutates every instance at once.
|