@open-slide/core 1.8.0 → 1.9.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.
@@ -5,12 +5,14 @@ import {
5
5
  ChevronLeft,
6
6
  Download,
7
7
  FileCode2,
8
+ FileImage,
8
9
  FileText,
9
10
  Link2,
10
11
  Loader2,
11
12
  Maximize,
12
13
  MonitorSpeaker,
13
14
  Play,
15
+ Presentation,
14
16
  } from 'lucide-react';
15
17
  import { type RefObject, useCallback, useEffect, useMemo, useRef, useState } from 'react';
16
18
  import { Link, useParams, useSearchParams } from 'react-router-dom';
@@ -33,6 +35,7 @@ import {
33
35
  DropdownMenu,
34
36
  DropdownMenuContent,
35
37
  DropdownMenuItem,
38
+ DropdownMenuSeparator,
36
39
  DropdownMenuTrigger,
37
40
  } from '@/components/ui/dropdown-menu';
38
41
  import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs';
@@ -47,11 +50,13 @@ import { cn } from '@/lib/utils';
47
50
  import { NotesDrawer } from '../components/notes-drawer';
48
51
  import { PdfProgressToast } from '../components/pdf-progress-toast';
49
52
  import { openPresenterWindow, Player } from '../components/player';
53
+ import { PptxProgressToast } from '../components/pptx-progress-toast';
50
54
  import { SlideCanvas } from '../components/slide-canvas';
51
55
  import { SlideTransitionLayer } from '../components/slide-transition-layer';
52
56
  import { type ThumbnailActions, ThumbnailRail } from '../components/thumbnail-rail';
53
57
  import { exportSlideAsHtml } from '../lib/export-html';
54
58
  import { exportSlideAsPdf, isSafari } from '../lib/export-pdf';
59
+ import { exportSlideAsImagePptx } from '../lib/export-pptx';
55
60
  import { remapNotesSessionCacheAfterReorder } from '../lib/inspector/use-notes';
56
61
  import type { SlideModule } from '../lib/sdk';
57
62
  import { usePrefersReducedMotion } from '../lib/use-prefers-reduced-motion';
@@ -500,6 +505,69 @@ export function Slide() {
500
505
  <FileText />
501
506
  {t.slide.exportAsPdf}
502
507
  </DropdownMenuItem>
508
+ <DropdownMenuSeparator />
509
+ <DropdownMenuItem
510
+ disabled={exporting}
511
+ onSelect={async () => {
512
+ if (!slide || exporting) return;
513
+ setExporting(true);
514
+ const toastId = `pptx-export-${slideId}`;
515
+ toast.custom(
516
+ () => (
517
+ <PptxProgressToast
518
+ progress={{
519
+ phase: 'processing',
520
+ current: 0,
521
+ total: pages.length,
522
+ percent: 0,
523
+ }}
524
+ />
525
+ ),
526
+ { id: toastId, duration: Infinity },
527
+ );
528
+ try {
529
+ await exportSlideAsImagePptx(slide, slideId, (p) => {
530
+ toast.custom(() => <PptxProgressToast progress={p} />, {
531
+ id: toastId,
532
+ duration: Infinity,
533
+ });
534
+ });
535
+ } catch (err) {
536
+ console.error('[open-slide] image pptx export failed', err);
537
+ toast.error(t.slide.imagePptxExportFailed, {
538
+ id: toastId,
539
+ duration: 4000,
540
+ });
541
+ } finally {
542
+ setExporting(false);
543
+ toast.dismiss(toastId);
544
+ }
545
+ }}
546
+ >
547
+ <FileImage />
548
+ {t.slide.exportAsImagePptx}
549
+ </DropdownMenuItem>
550
+ <TooltipProvider delayDuration={200}>
551
+ <Tooltip>
552
+ <TooltipTrigger asChild>
553
+ <div
554
+ aria-disabled
555
+ className="relative flex cursor-help items-center justify-between gap-2 rounded-[5px] px-2 py-1.5 text-[12.5px] opacity-45 select-none [&_svg]:size-3.5 [&_svg]:shrink-0 [&_svg]:opacity-80"
556
+ >
557
+ <span className="flex items-center gap-2">
558
+ <Presentation />
559
+ {t.slide.exportAsPptx}
560
+ </span>
561
+ <span className="rounded-[3px] bg-muted px-1.5 py-0.5 font-mono text-[9.5px] tracking-[0.04em] text-muted-foreground">
562
+ {t.slide.comingSoon}
563
+ </span>
564
+ </div>
565
+ </TooltipTrigger>
566
+ <TooltipContent side="left" className="max-w-[240px] leading-relaxed">
567
+ {t.slide.pptxComingSoonTooltip}
568
+ </TooltipContent>
569
+ </Tooltip>
570
+ </TooltipProvider>
503
571
  </DropdownMenuContent>
504
572
  </DropdownMenu>
505
573
  )}
@@ -13,6 +13,7 @@ declare module 'virtual:open-slide/config' {
13
13
  slidesDir?: string;
14
14
  port?: number;
15
15
  locale?: Locale;
16
+ version: string;
16
17
  build: {
17
18
  showSlideBrowser: boolean;
18
19
  showSlideUi: boolean;
package/src/locale/en.ts CHANGED
@@ -44,6 +44,7 @@ export const en: Locale = {
44
44
  folders: 'Folders',
45
45
  newFolder: 'New folder',
46
46
  folderName: 'Folder name',
47
+ updateAvailable: 'open-slide {version} is available — update the package to get the latest.',
47
48
  changeIcon: 'Change icon',
48
49
  iconEmojiTab: 'Emoji',
49
50
  iconColorTab: 'Color',
@@ -105,7 +106,13 @@ export const en: Locale = {
105
106
  toastCopyLinkFailed: 'Failed to copy link',
106
107
  exportAsHtml: 'Export as HTML',
107
108
  exportAsPdf: 'Export as PDF',
109
+ exportAsImagePptx: 'Export as image PPTX',
110
+ exportAsPptx: 'Export as PPTX',
111
+ comingSoon: 'Coming soon',
112
+ pptxComingSoonTooltip:
113
+ 'Editable PPTX export isn’t ready yet. For now, use “Export as image PPTX” instead.',
108
114
  pdfExportFailed: 'PDF export failed',
115
+ imagePptxExportFailed: 'PPTX export failed',
109
116
  pdfExportSafariUnsupported:
110
117
  'Export as PDF is not supported on Safari. Please try a Chromium-based browser instead.',
111
118
  present: 'Present',
@@ -345,6 +352,13 @@ export const en: Locale = {
345
352
  done: 'Done',
346
353
  },
347
354
 
355
+ pptxToast: {
356
+ title: 'Exporting PPTX',
357
+ processing: 'Rendering page {current} of {total}',
358
+ generating: 'Building presentation…',
359
+ done: 'Done',
360
+ },
361
+
348
362
  themeToggle: {
349
363
  toggleAria: 'Toggle theme',
350
364
  title: 'Theme',
@@ -353,6 +367,11 @@ export const en: Locale = {
353
367
  system: 'System',
354
368
  },
355
369
 
370
+ languageToggle: {
371
+ toggleAria: 'Change language',
372
+ title: 'Language',
373
+ },
374
+
356
375
  imagePlaceholder: {
357
376
  dropOverlay: 'Drop image to use here',
358
377
  uploading: 'Uploading…',
package/src/locale/ja.ts CHANGED
@@ -44,6 +44,8 @@ export const ja: Locale = {
44
44
  folders: 'フォルダ',
45
45
  newFolder: '新規フォルダ',
46
46
  folderName: 'フォルダ名',
47
+ updateAvailable:
48
+ 'open-slide {version} が利用可能です — パッケージを更新して最新版を入手してください。',
47
49
  changeIcon: 'アイコンを変更',
48
50
  iconEmojiTab: '絵文字',
49
51
  iconColorTab: 'カラー',
@@ -105,7 +107,13 @@ export const ja: Locale = {
105
107
  toastCopyLinkFailed: 'リンクのコピーに失敗しました',
106
108
  exportAsHtml: 'HTML として書き出し',
107
109
  exportAsPdf: 'PDF として書き出し',
110
+ exportAsImagePptx: '画像 PPTX として書き出し',
111
+ exportAsPptx: 'PPTX として書き出し',
112
+ comingSoon: '近日公開',
113
+ pptxComingSoonTooltip:
114
+ '編集可能な PPTX の書き出しはまだ対応していません。それまでは「画像 PPTX として書き出し」をご利用ください。',
108
115
  pdfExportFailed: 'PDF の書き出しに失敗しました',
116
+ imagePptxExportFailed: 'PPTX の書き出しに失敗しました',
109
117
  pdfExportSafariUnsupported:
110
118
  'PDF の書き出しは現在 Safari では対応していません。Chromium ベースのブラウザでお試しください。',
111
119
  present: '発表',
@@ -349,6 +357,13 @@ export const ja: Locale = {
349
357
  done: '完了',
350
358
  },
351
359
 
360
+ pptxToast: {
361
+ title: 'PPTX を書き出し中',
362
+ processing: 'ページ {current} / {total} を描画中',
363
+ generating: 'プレゼンテーションを構築中…',
364
+ done: '完了',
365
+ },
366
+
352
367
  themeToggle: {
353
368
  toggleAria: 'テーマを切り替え',
354
369
  title: 'テーマ',
@@ -357,6 +372,11 @@ export const ja: Locale = {
357
372
  system: 'システム',
358
373
  },
359
374
 
375
+ languageToggle: {
376
+ toggleAria: '言語を切り替え',
377
+ title: '言語',
378
+ },
379
+
360
380
  imagePlaceholder: {
361
381
  dropOverlay: 'ここにドロップして使用',
362
382
  uploading: 'アップロード中…',
@@ -44,6 +44,7 @@ export type Locale = {
44
44
  folders: string;
45
45
  newFolder: string;
46
46
  folderName: string;
47
+ updateAvailable: string;
47
48
  changeIcon: string;
48
49
  iconEmojiTab: string;
49
50
  iconColorTab: string;
@@ -107,7 +108,12 @@ export type Locale = {
107
108
  toastCopyLinkFailed: string;
108
109
  exportAsHtml: string;
109
110
  exportAsPdf: string;
111
+ exportAsImagePptx: string;
112
+ exportAsPptx: string;
113
+ comingSoon: string;
114
+ pptxComingSoonTooltip: string;
110
115
  pdfExportFailed: string;
116
+ imagePptxExportFailed: string;
111
117
  pdfExportSafariUnsupported: string;
112
118
  present: string;
113
119
  presentMenuAria: string;
@@ -368,6 +374,14 @@ export type Locale = {
368
374
  done: string;
369
375
  };
370
376
 
377
+ pptxToast: {
378
+ title: string;
379
+ /** template: "Rendering page {current} of {total}" */
380
+ processing: string;
381
+ generating: string;
382
+ done: string;
383
+ };
384
+
371
385
  themeToggle: {
372
386
  toggleAria: string;
373
387
  title: string;
@@ -376,6 +390,11 @@ export type Locale = {
376
390
  system: string;
377
391
  };
378
392
 
393
+ languageToggle: {
394
+ toggleAria: string;
395
+ title: string;
396
+ };
397
+
379
398
  imagePlaceholder: {
380
399
  dropOverlay: string;
381
400
  uploading: string;
@@ -44,6 +44,7 @@ export const zhCN: Locale = {
44
44
  folders: '文件夹',
45
45
  newFolder: '新建文件夹',
46
46
  folderName: '文件夹名称',
47
+ updateAvailable: 'open-slide {version} 已发布,请更新软件包以获取最新版本。',
47
48
  changeIcon: '更换图标',
48
49
  iconEmojiTab: 'Emoji',
49
50
  iconColorTab: '颜色',
@@ -104,7 +105,12 @@ export const zhCN: Locale = {
104
105
  toastCopyLinkFailed: '复制链接失败',
105
106
  exportAsHtml: '导出为 HTML',
106
107
  exportAsPdf: '导出为 PDF',
108
+ exportAsImagePptx: '导出图片 PPTX',
109
+ exportAsPptx: '导出 PPTX',
110
+ comingSoon: '即将推出',
111
+ pptxComingSoonTooltip: '可编辑的 PPTX 导出尚未支持,在此之前可以先使用“导出图片 PPTX”。',
107
112
  pdfExportFailed: 'PDF 导出失败',
113
+ imagePptxExportFailed: 'PPTX 导出失败',
108
114
  pdfExportSafariUnsupported:
109
115
  '导出 PDF 目前不支持 Safari 设备,请尝试使用基于 Chromium 的浏览器替代。',
110
116
  present: '演示',
@@ -344,6 +350,13 @@ export const zhCN: Locale = {
344
350
  done: '完成',
345
351
  },
346
352
 
353
+ pptxToast: {
354
+ title: '导出 PPTX',
355
+ processing: '正在渲染第 {current} / {total} 页',
356
+ generating: '正在组合演示文稿…',
357
+ done: '完成',
358
+ },
359
+
347
360
  themeToggle: {
348
361
  toggleAria: '切换主题',
349
362
  title: '主题',
@@ -352,6 +365,11 @@ export const zhCN: Locale = {
352
365
  system: '系统',
353
366
  },
354
367
 
368
+ languageToggle: {
369
+ toggleAria: '切换语言',
370
+ title: '语言',
371
+ },
372
+
355
373
  imagePlaceholder: {
356
374
  dropOverlay: '拖入图片以使用',
357
375
  uploading: '上传中…',
@@ -44,6 +44,7 @@ export const zhTW: Locale = {
44
44
  folders: '資料夾',
45
45
  newFolder: '新增資料夾',
46
46
  folderName: '資料夾名稱',
47
+ updateAvailable: 'open-slide {version} 已發布,請更新套件以取得最新版本。',
47
48
  changeIcon: '變更圖示',
48
49
  iconEmojiTab: 'Emoji',
49
50
  iconColorTab: '顏色',
@@ -104,7 +105,12 @@ export const zhTW: Locale = {
104
105
  toastCopyLinkFailed: '複製連結失敗',
105
106
  exportAsHtml: '匯出為 HTML',
106
107
  exportAsPdf: '匯出為 PDF',
108
+ exportAsImagePptx: '匯出圖片 PPTX',
109
+ exportAsPptx: '匯出 PPTX',
110
+ comingSoon: '即將推出',
111
+ pptxComingSoonTooltip: '可編輯的 PPTX 匯出尚未支援,在此之前可以先使用「匯出圖片 PPTX」。',
107
112
  pdfExportFailed: 'PDF 匯出失敗',
113
+ imagePptxExportFailed: 'PPTX 匯出失敗',
108
114
  pdfExportSafariUnsupported:
109
115
  '匯出 PDF 目前不支援 Safari 裝置,請嘗試用 Chromium 基底瀏覽器替代。',
110
116
  present: '簡報',
@@ -344,6 +350,13 @@ export const zhTW: Locale = {
344
350
  done: '完成',
345
351
  },
346
352
 
353
+ pptxToast: {
354
+ title: '匯出 PPTX',
355
+ processing: '正在算繪第 {current} / {total} 頁',
356
+ generating: '正在組合簡報…',
357
+ done: '完成',
358
+ },
359
+
347
360
  themeToggle: {
348
361
  toggleAria: '切換主題',
349
362
  title: '主題',
@@ -352,6 +365,11 @@ export const zhTW: Locale = {
352
365
  system: '系統',
353
366
  },
354
367
 
368
+ languageToggle: {
369
+ toggleAria: '切換語言',
370
+ title: '語言',
371
+ },
372
+
355
373
  imagePlaceholder: {
356
374
  dropOverlay: '拖入圖片以使用',
357
375
  uploading: '上傳中…',