@peteai/presentation-editor 0.0.8 → 0.0.10

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 (96) hide show
  1. package/dist/components/editor/active-layers.svelte +2 -2
  2. package/dist/components/editor/design.svelte +92 -0
  3. package/dist/components/editor/design.svelte.d.ts +8 -0
  4. package/dist/components/editor/editor.svelte +1 -1
  5. package/dist/components/editor/editor.svelte.js +14 -2
  6. package/dist/components/editor/header.svelte +1 -1
  7. package/dist/components/editor/index.d.ts +2 -1
  8. package/dist/components/editor/index.js +2 -1
  9. package/dist/components/editor/layers/active-layer-border.svelte +1 -1
  10. package/dist/components/editor/layers/buttons/border-button/border-button-colors.svelte +1 -1
  11. package/dist/components/editor/layers/controls/corner-scale-control/corner-scale-control.svelte +1 -1
  12. package/dist/components/editor/layers/controls/rotate-control/rotate-control.svelte +1 -1
  13. package/dist/components/editor/layers/controls/side-scale-control/side-scale-control.svelte +1 -1
  14. package/dist/components/editor/layers/layer-button.svelte +1 -1
  15. package/dist/components/editor/layers/types/background/background-layer-buttons.svelte +1 -1
  16. package/dist/components/editor/layers/types/image/controls/image-rotate-control/image-rotate-control.svelte +1 -1
  17. package/dist/components/editor/layers/types/image/controls/image-scale-control/image-scale-control.svelte +1 -1
  18. package/dist/components/editor/layers/types/image/image-layer-crop.svelte +2 -2
  19. package/dist/components/editor/page-editor.svelte +7 -0
  20. package/dist/components/editor/{pages-navigation/page-preview.svelte → page-preview.svelte} +4 -4
  21. package/dist/components/editor/{pages-navigation/page-preview.svelte.d.ts → page-preview.svelte.d.ts} +2 -2
  22. package/dist/components/editor/page-transition-preview.svelte +34 -0
  23. package/dist/components/editor/page-transition-preview.svelte.d.ts +9 -0
  24. package/dist/components/editor/page-with-transition.svelte +48 -0
  25. package/dist/components/editor/page-with-transition.svelte.d.ts +10 -0
  26. package/dist/components/editor/page.svelte +12 -19
  27. package/dist/components/editor/pages-navigation/pages-navigation-item.svelte +80 -20
  28. package/dist/components/editor/pages-navigation/pages-navigation.svelte +7 -4
  29. package/dist/components/editor/sidebar/color-sidebar/color-sidebar-color.svelte +2 -2
  30. package/dist/components/editor/sidebar/color-sidebar/color-sidebar-gradient-picker.svelte +5 -5
  31. package/dist/components/editor/sidebar/color-sidebar/color-sidebar.svelte +91 -81
  32. package/dist/components/editor/sidebar/color-sidebar/color-sidebar.svelte.d.ts +5 -1
  33. package/dist/components/editor/sidebar/font-sidebar/font-sidebar.svelte +10 -6
  34. package/dist/components/editor/sidebar/font-sidebar/font-sidebar.svelte.d.ts +5 -1
  35. package/dist/components/editor/sidebar/image-crop-sidebar.svelte +28 -37
  36. package/dist/components/editor/sidebar/image-crop-sidebar.svelte.d.ts +2 -0
  37. package/dist/components/editor/sidebar/position-sidebar/index.d.ts +2 -0
  38. package/dist/components/editor/sidebar/position-sidebar/index.js +2 -0
  39. package/dist/components/editor/sidebar/position-sidebar/position-sidebar.svelte +130 -0
  40. package/dist/components/editor/sidebar/position-sidebar/position-sidebar.svelte.d.ts +7 -0
  41. package/dist/components/editor/sidebar/sidebar-text-tab.svelte +7 -3
  42. package/dist/components/editor/sidebar/sidebar-text-tab.svelte.d.ts +5 -16
  43. package/dist/components/editor/sidebar/sidebar-uploads-tab.svelte +10 -8
  44. package/dist/components/editor/sidebar/sidebar-uploads-tab.svelte.d.ts +5 -1
  45. package/dist/components/editor/sidebar/sidebar-wrapper.svelte +4 -3
  46. package/dist/components/editor/sidebar/sidebar-wrapper.svelte.d.ts +1 -0
  47. package/dist/components/editor/sidebar/sidebar.svelte +20 -13
  48. package/dist/components/editor/sidebar/transition-sidebar/index.d.ts +2 -0
  49. package/dist/components/editor/sidebar/transition-sidebar/index.js +2 -0
  50. package/dist/components/editor/sidebar/transition-sidebar/transition-sidebar.svelte +257 -0
  51. package/dist/components/editor/sidebar/transition-sidebar/transition-sidebar.svelte.d.ts +7 -0
  52. package/dist/components/editor/snapping-guides.svelte +3 -3
  53. package/dist/components/editor/types.d.ts +40 -6
  54. package/dist/components/editor/utils.d.ts +2 -2
  55. package/dist/components/editor/utils.js +21 -0
  56. package/dist/components/ui/button/button.svelte +2 -1
  57. package/dist/components/ui/button/button.svelte.d.ts +3 -0
  58. package/dist/components/ui/color-picker/color-picker-alpha-grid.svelte +2 -1
  59. package/dist/components/ui/color-picker/color-picker.svelte +6 -6
  60. package/dist/components/ui/context-menu/context-menu-checkbox-item.svelte +1 -1
  61. package/dist/components/ui/context-menu/context-menu-content.svelte +3 -1
  62. package/dist/components/ui/context-menu/context-menu-group-heading.svelte +1 -1
  63. package/dist/components/ui/context-menu/context-menu-item.svelte +1 -1
  64. package/dist/components/ui/context-menu/context-menu-radio-item.svelte +1 -1
  65. package/dist/components/ui/context-menu/context-menu-separator.svelte +1 -1
  66. package/dist/components/ui/context-menu/context-menu-shortcut.svelte +1 -1
  67. package/dist/components/ui/context-menu/context-menu-sub-content.svelte +1 -1
  68. package/dist/components/ui/context-menu/context-menu-sub-trigger.svelte +1 -1
  69. package/dist/components/ui/dialog/dialog-content.svelte +4 -2
  70. package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +1 -1
  71. package/dist/components/ui/dropdown-menu/dropdown-menu-content.svelte +2 -0
  72. package/dist/components/ui/dropdown-menu/dropdown-menu-item.svelte +1 -1
  73. package/dist/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte +1 -1
  74. package/dist/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte +1 -1
  75. package/dist/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +1 -1
  76. package/dist/components/ui/input/input.svelte +1 -1
  77. package/dist/components/ui/slider/slider.svelte +3 -3
  78. package/dist/components/ui/tabs/index.d.ts +4 -4
  79. package/dist/components/ui/tabs/index.js +4 -4
  80. package/dist/components/ui/tabs/tabs-content.svelte +4 -4
  81. package/dist/components/ui/tabs/tabs-content.svelte.d.ts +1 -1
  82. package/dist/components/ui/tabs/tabs-list.svelte +5 -9
  83. package/dist/components/ui/tabs/tabs-list.svelte.d.ts +1 -1
  84. package/dist/components/ui/tabs/tabs-trigger.svelte +4 -4
  85. package/dist/components/ui/tabs/tabs-trigger.svelte.d.ts +1 -1
  86. package/dist/transitions/circleWipe.d.ts +10 -0
  87. package/dist/transitions/circleWipe.js +16 -0
  88. package/dist/transitions/lineWipe.d.ts +9 -0
  89. package/dist/transitions/lineWipe.js +17 -0
  90. package/dist/transitions/stack.d.ts +8 -0
  91. package/dist/transitions/stack.js +13 -0
  92. package/package.json +19 -19
  93. package/dist/components/editor/layers/types/image/image-layer-active.svelte +0 -36
  94. package/dist/components/editor/layers/types/image/image-layer-active.svelte.d.ts +0 -7
  95. package/dist/components/editor/sidebar/position-sidebar.svelte +0 -136
  96. package/dist/components/editor/sidebar/position-sidebar.svelte.d.ts +0 -3
@@ -147,14 +147,14 @@
147
147
  >
148
148
  {#if !group.items.length}
149
149
  <div
150
- class="border-primary absolute -inset-px border-2"
150
+ class="absolute -inset-px border-2 border-primary"
151
151
  style:box-shadow="0 0 0 1px hsla(0, 0%, 100%, .07), inset 0 0 0 1px hsla(0, 0%, 100%, .07)"
152
152
  ></div>
153
153
  {:else}
154
154
  <div class="group-border absolute -inset-px"></div>
155
155
  {#each group.items as item}
156
156
  <div
157
- class="border-primary absolute -left-px -top-px border-2"
157
+ class="absolute -left-px -top-px border-2 border-primary"
158
158
  style:box-shadow="0 0 0 1px hsla(0, 0%, 100%, .07), inset 0 0 0 1px hsla(0, 0%, 100%, .07)"
159
159
  style:width={`${item.width * item.scale * editor.zoom + 2}px`}
160
160
  style:height={`${item.height * item.scale * editor.zoom + 2}px`}
@@ -0,0 +1,92 @@
1
+ <script lang="ts">
2
+ import { BROWSER } from 'esm-env';
3
+ import { onMount } from 'svelte';
4
+ import type { DesignOptions, Page } from './types.js';
5
+ import { normalizePage } from './editor.svelte.js';
6
+ import { extractNodeFonts } from './layers/types/text/editor/utils.js';
7
+ import { defaultFonts } from './fonts.js';
8
+ import PageWithTransition from './page-with-transition.svelte';
9
+
10
+ const {
11
+ pages: pagesInput,
12
+ fonts = defaultFonts,
13
+ loadFont = async (family: string) => {
14
+ const font = fonts[family];
15
+ if (!font) return;
16
+ const WebFont = await import('webfontloader');
17
+ return new Promise((resolve, reject) => {
18
+ WebFont.load({
19
+ [font.type]: { families: [family] },
20
+ active: () => resolve(),
21
+ inactive: reject,
22
+ });
23
+ });
24
+ },
25
+ }: DesignOptions = $props();
26
+
27
+ const pages = pagesInput.map(normalizePage);
28
+
29
+ if (BROWSER) {
30
+ const fontFamilies = pages
31
+ .flatMap((page) => page.layers)
32
+ .filter((layer) => layer.type === 'text')
33
+ .flatMap((layer) => extractNodeFonts(layer.html));
34
+ Promise.all(fontFamilies.map(loadFont));
35
+ }
36
+
37
+ let element: HTMLDivElement | null = $state(null);
38
+
39
+ const width = 1920;
40
+ const height = 1080;
41
+
42
+ let thumbScale = $state(1);
43
+
44
+ onMount(() => {
45
+ const observer = new ResizeObserver((entries) => {
46
+ for (const entry of entries) {
47
+ const scaleX = entry.contentRect.width / width;
48
+ const scaleY = entry.contentRect.height / height;
49
+ thumbScale = Math.min(scaleX, scaleY); // preserve aspect ratio
50
+ }
51
+ });
52
+
53
+ if (element) observer.observe(element);
54
+
55
+ return () => observer.disconnect();
56
+ });
57
+
58
+ let sortedPages = $derived(pages.sort((a, b) => a.sortOrder - b.sortOrder));
59
+ let currentPageIndex = $state(0);
60
+ let page = $derived(sortedPages[currentPageIndex]);
61
+ let previousPage: Page | undefined = $state();
62
+
63
+ const setIndex = (index: number) => {
64
+ previousPage = page;
65
+ transition = page.transition;
66
+ currentPageIndex = index;
67
+ };
68
+ let transition = $derived(previousPage?.transition);
69
+
70
+ export const prevPage = () => {
71
+ if (currentPageIndex <= 0) return;
72
+ setIndex(currentPageIndex - 1);
73
+ };
74
+
75
+ export const nextPage = () => {
76
+ if (currentPageIndex >= sortedPages.length - 1) return;
77
+ setIndex(currentPageIndex + 1);
78
+ };
79
+
80
+ export const setPageIndex = (index: number) => {
81
+ if (index < 0 || index >= sortedPages.length) return;
82
+ setIndex(index);
83
+ };
84
+ </script>
85
+
86
+ <div bind:this={element} class="grid h-full w-full place-items-center">
87
+ <div style:width="{width * thumbScale}px" style:height="{height * thumbScale}px">
88
+ {#key page.id}
89
+ <PageWithTransition {page} {previousPage} {transition} {thumbScale} />
90
+ {/key}
91
+ </div>
92
+ </div>
@@ -0,0 +1,8 @@
1
+ import type { DesignOptions } from './types.js';
2
+ declare const Design: import("svelte").Component<DesignOptions, {
3
+ prevPage: () => void;
4
+ nextPage: () => void;
5
+ setPageIndex: (index: number) => void;
6
+ }, "">;
7
+ type Design = ReturnType<typeof Design>;
8
+ export default Design;
@@ -216,7 +216,7 @@
216
216
  <Hotkeys />
217
217
 
218
218
  <!-- svelte-ignore a11y_no_static_element_interactions -->
219
- <div class="flex h-full w-full select-none" ondragover={onDragOver} ondrop={onDrop}>
219
+ <div class="flex h-full w-full select-none bg-background" ondragover={onDragOver} ondrop={onDrop}>
220
220
  <Sidebar {editor} />
221
221
  <div class="flex h-full flex-1 select-none flex-col overflow-auto">
222
222
  <Dragged {editor} />
@@ -7,6 +7,12 @@ import { calculateBoundingBox, calculateImageCover, checkPolygonsIntersect, getR
7
7
  import createEditor from './layers/types/text/editor/createEditor.js';
8
8
  import { extensions } from './layers/types/text/extensions.js';
9
9
  import { SvelteSet } from 'svelte/reactivity';
10
+ export const normalizePage = (page) => {
11
+ return {
12
+ ...page,
13
+ transition: page.transition || null,
14
+ };
15
+ };
10
16
  export class Editor {
11
17
  mode = 'multiple';
12
18
  fonts = defaultFonts;
@@ -125,6 +131,7 @@ export class Editor {
125
131
  selectedLayersNotLocked = $derived(this.selectedLayers.filter((layer) => !layer.locked));
126
132
  selectedSimpleLayersNotLocked = $derived(this.selectedLayersNotLocked.flatMap((l) => l.type === 'group' ? this.findGroupChildren(this.activePage, l.id) : l));
127
133
  activeGroupRotate = $state(0);
134
+ pageTransitionPreview = $state(null);
128
135
  pageSelected = $state(false);
129
136
  clipboard = null;
130
137
  htmlEditor = createEditor({
@@ -142,11 +149,15 @@ export class Editor {
142
149
  const { page, ...rest } = options;
143
150
  Object.assign(this, { ...rest });
144
151
  if (page) {
145
- Object.assign(this, { pages: [page] });
152
+ Object.assign(this, { pages: [normalizePage(page)] });
146
153
  }
147
154
  }
148
155
  else {
149
- Object.assign(this, options);
156
+ const { pages, ...rest } = options;
157
+ Object.assign(this, rest);
158
+ if (pages) {
159
+ Object.assign(this, { pages: pages.map(normalizePage) });
160
+ }
150
161
  }
151
162
  if (!this.pages.length) {
152
163
  this.addPage();
@@ -163,6 +174,7 @@ export class Editor {
163
174
  backgroundImage: null,
164
175
  backgroundLocked: false,
165
176
  layers: [],
177
+ transition: null,
166
178
  };
167
179
  }
168
180
  addPage({ page, index } = {}) {
@@ -16,7 +16,7 @@
16
16
  let disabled = $derived(!!editor.imageCropLayer);
17
17
  </script>
18
18
 
19
- <div class="bg-background h-12 w-full border-b border-gray-200 px-2">
19
+ <div class="h-12 w-full border-b border-gray-200 px-2">
20
20
  <div class="flex h-full items-center justify-between">
21
21
  <div class="grid grid-flow-col items-center gap-2">
22
22
  <Button
@@ -1,3 +1,4 @@
1
1
  import Editor from './editor.svelte';
2
+ import Design from './design.svelte';
2
3
  import Page from './page.svelte';
3
- export { Editor, Page };
4
+ export { Editor, Design, Page };
@@ -1,3 +1,4 @@
1
1
  import Editor from './editor.svelte';
2
+ import Design from './design.svelte';
2
3
  import Page from './page.svelte';
3
- export { Editor, Page };
4
+ export { Editor, Design, Page };
@@ -18,7 +18,7 @@
18
18
  style:transform={`translate(${layer.x * editor.zoom}px, ${layer.y * editor.zoom}px) rotate(${layer.rotate}deg)`}
19
19
  >
20
20
  <div
21
- class="border-primary absolute -inset-px border-2"
21
+ class="absolute -inset-px border-2 border-primary"
22
22
  style:box-shadow="0 0 0 1px hsla(0, 0%, 100%, .07), inset 0 0 0 1px hsla(0, 0%, 100%, .07)"
23
23
  ></div>
24
24
  </div>
@@ -50,7 +50,7 @@
50
50
  {/each}
51
51
  </svg>
52
52
  <span
53
- class="bg-background absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full"
53
+ class="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full bg-background"
54
54
  style:width="{width / 2}px"
55
55
  style:height="{height / 2}px"
56
56
  ></span>
@@ -198,7 +198,7 @@
198
198
  <!-- svelte-ignore a11y_no_static_element_interactions -->
199
199
  <div class={cn(handler(), cursor())} onmousedown={onMouseDown}></div>
200
200
  <div
201
- class="group-hover:bg-primary group-active:bg-primary h-3 w-3 rounded-full bg-white transition-colors"
201
+ class="h-3 w-3 rounded-full bg-white transition-colors group-hover:bg-primary group-active:bg-primary"
202
202
  style:box-shadow="0 0 4px 1px rgba(57,76,96,.15), 0 0 0 1px rgba(43,59,74,.3)"
203
203
  ></div>
204
204
  </div>
@@ -180,7 +180,7 @@
180
180
  onmousedown={onMouseDown}
181
181
  ></div>
182
182
  <div
183
- class="group-hover:bg-primary group-active:bg-primary group-hover:text-primary-foreground group-active:text-primary-foreground flex h-6 w-6 items-center justify-center rounded-full bg-white transition-colors"
183
+ class="flex h-6 w-6 items-center justify-center rounded-full bg-white transition-colors group-hover:bg-primary group-hover:text-primary-foreground group-active:bg-primary group-active:text-primary-foreground"
184
184
  style:box-shadow="0 0 4px 1px rgba(57,76,96,.15), 0 0 0 1px rgba(43,59,74,.3)"
185
185
  >
186
186
  <RotateIcon class="h-4 w-4" />
@@ -146,7 +146,7 @@
146
146
  <!-- svelte-ignore a11y_no_static_element_interactions -->
147
147
  <div class={cn(handler(), cursor())} onmousedown={onMouseDown}></div>
148
148
  <div
149
- class="group-hover:bg-primary group-active:bg-primary h-4 w-1.5 rounded-sm bg-white transition-colors"
149
+ class="h-4 w-1.5 rounded-sm bg-white transition-colors group-hover:bg-primary group-active:bg-primary"
150
150
  style:box-shadow="0 0 4px 1px rgba(57,76,96,.15), 0 0 0 1px rgba(43,59,74,.3)"
151
151
  ></div>
152
152
  </div>
@@ -33,7 +33,7 @@
33
33
  <button
34
34
  {onclick}
35
35
  class={cn(
36
- 'bg-muted flex w-full items-center justify-between rounded-md border-2 border-transparent p-2 outline-none',
36
+ 'flex w-full items-center justify-between rounded-md border-2 border-transparent bg-muted p-2 outline-none',
37
37
  {
38
38
  'border-blue-500': layer
39
39
  ? editor.activeLayers.find((l) => l.id === layer.id)
@@ -20,7 +20,7 @@
20
20
  active={editor.activeSidebarPopup === 'backgroundColor'}
21
21
  >
22
22
  <div
23
- class="after:shadow-inner-1 relative h-6 w-6 overflow-hidden rounded-full after:absolute after:inset-0 after:rounded-full"
23
+ class="relative h-6 w-6 overflow-hidden rounded-full after:absolute after:inset-0 after:rounded-full after:shadow-inner-1"
24
24
  >
25
25
  <ColorPickerAlphaGrid size={12}>
26
26
  <ColorIndicator color={backgroundColor} />
@@ -110,7 +110,7 @@
110
110
  onmousedown={onMouseDown}
111
111
  >
112
112
  <div
113
- class="group-hover:bg-primary group-active:bg-primary group-hover:text-primary-foreground group-active:text-primary-foreground flex h-6 w-6 items-center justify-center rounded-full bg-white transition-colors after:pointer-events-auto after:absolute after:inset-0 after:rounded-full"
113
+ class="flex h-6 w-6 items-center justify-center rounded-full bg-white transition-colors after:pointer-events-auto after:absolute after:inset-0 after:rounded-full group-hover:bg-primary group-hover:text-primary-foreground group-active:bg-primary group-active:text-primary-foreground"
114
114
  style:box-shadow="0 0 4px 1px rgba(57,76,96,.15), 0 0 0 1px rgba(43,59,74,.3)"
115
115
  >
116
116
  <RotateIcon class="h-4 w-4" />
@@ -148,7 +148,7 @@
148
148
  <!-- svelte-ignore a11y_no_static_element_interactions -->
149
149
  <div class={cn(handler(), cursor())} onmousedown={onMouseDown}></div>
150
150
  <div
151
- class="group-hover:bg-primary group-active:bg-primary h-3 w-3 rounded-full bg-white transition-colors"
151
+ class="h-3 w-3 rounded-full bg-white transition-colors group-hover:bg-primary group-active:bg-primary"
152
152
  style:box-shadow="0 0 4px 1px rgba(57,76,96,.15), 0 0 0 1px rgba(43,59,74,.3)"
153
153
  ></div>
154
154
  </div>
@@ -156,7 +156,7 @@
156
156
  </div>
157
157
  <div class="pointer-events-auto">
158
158
  <div
159
- class="shadow-inner-1 outline-primary/50 pointer-events-none absolute outline outline-2"
159
+ class="pointer-events-none absolute shadow-inner-1 outline outline-2 outline-primary/50"
160
160
  style:width={`${layer.image.width * layer.scale * editor.zoom}px`}
161
161
  style:height={`${layer.image.height * layer.scale * editor.zoom}px`}
162
162
  style:transform={`translate(${imageTransform.x * editor.zoom}px, ${imageTransform.y * editor.zoom}px) rotate(${imageTransform.rotate}deg)`}
@@ -173,7 +173,7 @@
173
173
  <ImageRotateControl {pageRef} {layer} />
174
174
  </div>
175
175
  <div
176
- class="outline-primary pointer-events-none absolute outline outline-2"
176
+ class="pointer-events-none absolute outline outline-2 outline-primary"
177
177
  style:width={`${layer.width * layer.scale * editor.zoom}px`}
178
178
  style:height={`${layer.height * layer.scale * editor.zoom}px`}
179
179
  style:transform={`translate(${layer.x * editor.zoom}px, ${layer.y * editor.zoom}px) rotate(${layer.rotate}deg)`}
@@ -15,6 +15,7 @@
15
15
  import PageInner from './page-inner.svelte';
16
16
  import ActiveLayers from './active-layers.svelte';
17
17
  import SnappingGuides from './snapping-guides.svelte';
18
+ import PageTransitionPreview from './page-transition-preview.svelte';
18
19
 
19
20
  interface Props {
20
21
  viewportRef: HTMLDivElement | null;
@@ -96,6 +97,12 @@
96
97
  {/if}
97
98
 
98
99
  <SnappingGuides zoom={editor.zoom} guides={activeLayerGuides} />
100
+
101
+ {#if editor.pageTransitionPreview}
102
+ {#key editor.pageTransitionPreview}
103
+ <PageTransitionPreview {editor} transition={editor.pageTransitionPreview} />
104
+ {/key}
105
+ {/if}
99
106
  </div>
100
107
  </div>
101
108
  </div>
@@ -5,15 +5,15 @@
5
5
  TextLayerContent,
6
6
  ImageLayerContent,
7
7
  GroupLayerContent,
8
- } from '../layers/index.js';
9
- import type { Page } from '../types.js';
8
+ } from './layers/index.js';
9
+ import type { Page } from './types.js';
10
10
 
11
11
  interface Props {
12
12
  page: Page;
13
- thumbScale: number;
13
+ thumbScale?: number;
14
14
  }
15
15
 
16
- let { page, thumbScale }: Props = $props();
16
+ let { page, thumbScale = 1 }: Props = $props();
17
17
 
18
18
  let rootLayers = $derived(page.layers.filter((l) => l.type === 'group' || !l.groupId));
19
19
  </script>
@@ -1,7 +1,7 @@
1
- import type { Page } from '../types.js';
1
+ import type { Page } from './types.js';
2
2
  interface Props {
3
3
  page: Page;
4
- thumbScale: number;
4
+ thumbScale?: number;
5
5
  }
6
6
  declare const PagePreview: import("svelte").Component<Props, {}, "">;
7
7
  type PagePreview = ReturnType<typeof PagePreview>;
@@ -0,0 +1,34 @@
1
+ <script lang="ts">
2
+ import { onMount } from 'svelte';
3
+ import type { PageTransition } from './types.js';
4
+ import type { Editor } from './editor.svelte.js';
5
+ import PageWithTransition from './page-with-transition.svelte';
6
+
7
+ interface Props {
8
+ editor: Editor;
9
+ transition: PageTransition;
10
+ }
11
+
12
+ const { editor, transition }: Props = $props();
13
+
14
+ let nextPage = $derived(
15
+ editor.sortedPages.find((p) => p.sortOrder > editor.activePage.sortOrder),
16
+ );
17
+
18
+ onMount(() => {
19
+ const timeout = setTimeout(() => {
20
+ editor.pageTransitionPreview = null;
21
+ }, transition.duration + 500);
22
+
23
+ return () => clearTimeout(timeout);
24
+ });
25
+ </script>
26
+
27
+ {#if nextPage}
28
+ <PageWithTransition
29
+ page={nextPage}
30
+ previousPage={editor.activePage}
31
+ {transition}
32
+ thumbScale={editor.zoom}
33
+ />
34
+ {/if}
@@ -0,0 +1,9 @@
1
+ import type { PageTransition } from './types.js';
2
+ import type { Editor } from './editor.svelte.js';
3
+ interface Props {
4
+ editor: Editor;
5
+ transition: PageTransition;
6
+ }
7
+ declare const PageTransitionPreview: import("svelte").Component<Props, {}, "">;
8
+ type PageTransitionPreview = ReturnType<typeof PageTransitionPreview>;
9
+ export default PageTransitionPreview;
@@ -0,0 +1,48 @@
1
+ <script lang="ts">
2
+ import { fade } from 'svelte/transition';
3
+ import { circleWipe } from '../../transitions/circleWipe.js';
4
+ import { lineWipe } from '../../transitions/lineWipe.js';
5
+ import { stack } from '../../transitions/stack.js';
6
+ import type { Page, PageTransition } from './types.js';
7
+ import PagePreview from './page-preview.svelte';
8
+
9
+ interface Props {
10
+ page: Page;
11
+ previousPage?: Page;
12
+ transition: PageTransition | null | undefined;
13
+ thumbScale: number;
14
+ }
15
+
16
+ const { page, previousPage, transition, thumbScale }: Props = $props();
17
+
18
+ const previousPageTransition = (node: HTMLElement) => {
19
+ if (!transition) return { duration: 0 };
20
+ if (transition.type === 'slide') return stack(node, { ...transition, reverse: true });
21
+ return { duration: 0 };
22
+ };
23
+
24
+ const pageTransition = (node: HTMLElement) => {
25
+ if (!transition) return { duration: 0 };
26
+ if (transition.type === 'fade') return fade(node, transition);
27
+ if (transition.type === 'slide') return stack(node, transition);
28
+ if (transition.type === 'circleWipe') return circleWipe(node, transition);
29
+ if (transition.type === 'lineWipe') return lineWipe(node, transition);
30
+ if (transition.type === 'stack') return stack(node, transition);
31
+ return { duration: 0 };
32
+ };
33
+ </script>
34
+
35
+ <div class="relative h-full w-full overflow-hidden">
36
+ {#if previousPage}
37
+ <div class="absolute inset-0">
38
+ <div in:previousPageTransition|global class="h-full w-full">
39
+ <PagePreview page={previousPage} {thumbScale} />
40
+ </div>
41
+ </div>
42
+ {/if}
43
+ <div class="absolute inset-0">
44
+ <div in:pageTransition|global class="h-full w-full">
45
+ <PagePreview {page} {thumbScale} />
46
+ </div>
47
+ </div>
48
+ </div>
@@ -0,0 +1,10 @@
1
+ import type { Page, PageTransition } from './types.js';
2
+ interface Props {
3
+ page: Page;
4
+ previousPage?: Page;
5
+ transition: PageTransition | null | undefined;
6
+ thumbScale: number;
7
+ }
8
+ declare const PageWithTransition: import("svelte").Component<Props, {}, "">;
9
+ type PageWithTransition = ReturnType<typeof PageWithTransition>;
10
+ export default PageWithTransition;
@@ -2,13 +2,13 @@
2
2
  import { BROWSER } from 'esm-env';
3
3
  import { onMount } from 'svelte';
4
4
  import type { PageOptions } from './types.js';
5
+ import { normalizePage } from './editor.svelte.js';
5
6
  import { extractNodeFonts } from './layers/types/text/editor/utils.js';
6
7
  import { defaultFonts } from './fonts.js';
7
- import PagePreview from './pages-navigation/page-preview.svelte';
8
+ import PagePreview from './page-preview.svelte';
8
9
 
9
10
  const {
10
- page,
11
- thumbScale = 1,
11
+ page: pageInput,
12
12
  fonts = defaultFonts,
13
13
  loadFont = async (family: string) => {
14
14
  const font = fonts[family];
@@ -22,10 +22,10 @@
22
22
  });
23
23
  });
24
24
  },
25
- class: className,
26
- ...restProps
27
25
  }: PageOptions = $props();
28
26
 
27
+ const page = normalizePage(pageInput);
28
+
29
29
  if (BROWSER) {
30
30
  const fontFamilies = page.layers
31
31
  .filter((layer) => layer.type === 'text')
@@ -35,17 +35,17 @@
35
35
 
36
36
  let element: HTMLDivElement | null = $state(null);
37
37
 
38
- let width = 1920 * thumbScale;
39
- let height = 1080 * thumbScale;
38
+ const width = 1920;
39
+ const height = 1080;
40
40
 
41
- let scale = $state(1);
41
+ let thumbScale = $state(1);
42
42
 
43
43
  onMount(() => {
44
44
  const observer = new ResizeObserver((entries) => {
45
45
  for (const entry of entries) {
46
46
  const scaleX = entry.contentRect.width / width;
47
47
  const scaleY = entry.contentRect.height / height;
48
- scale = Math.min(scaleX, scaleY); // preserve aspect ratio
48
+ thumbScale = Math.min(scaleX, scaleY); // preserve aspect ratio
49
49
  }
50
50
  });
51
51
 
@@ -55,15 +55,8 @@
55
55
  });
56
56
  </script>
57
57
 
58
- <div class={className} {...restProps}>
59
- <div bind:this={element} class="h-full w-full">
60
- <div
61
- class="relative origin-top-left"
62
- style:width="{width}px"
63
- style:height="{height}px"
64
- style:transform="scale({scale})"
65
- >
66
- <PagePreview {page} {thumbScale} />
67
- </div>
58
+ <div bind:this={element} class="grid h-full w-full place-items-center">
59
+ <div class="relative" style:width="{width * thumbScale}px" style:height="{height * thumbScale}px">
60
+ <PagePreview {page} {thumbScale} />
68
61
  </div>
69
62
  </div>