@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.
- package/dist/components/editor/active-layers.svelte +2 -2
- package/dist/components/editor/design.svelte +92 -0
- package/dist/components/editor/design.svelte.d.ts +8 -0
- package/dist/components/editor/editor.svelte +1 -1
- package/dist/components/editor/editor.svelte.js +14 -2
- package/dist/components/editor/header.svelte +1 -1
- package/dist/components/editor/index.d.ts +2 -1
- package/dist/components/editor/index.js +2 -1
- package/dist/components/editor/layers/active-layer-border.svelte +1 -1
- package/dist/components/editor/layers/buttons/border-button/border-button-colors.svelte +1 -1
- package/dist/components/editor/layers/controls/corner-scale-control/corner-scale-control.svelte +1 -1
- package/dist/components/editor/layers/controls/rotate-control/rotate-control.svelte +1 -1
- package/dist/components/editor/layers/controls/side-scale-control/side-scale-control.svelte +1 -1
- package/dist/components/editor/layers/layer-button.svelte +1 -1
- package/dist/components/editor/layers/types/background/background-layer-buttons.svelte +1 -1
- package/dist/components/editor/layers/types/image/controls/image-rotate-control/image-rotate-control.svelte +1 -1
- package/dist/components/editor/layers/types/image/controls/image-scale-control/image-scale-control.svelte +1 -1
- package/dist/components/editor/layers/types/image/image-layer-crop.svelte +2 -2
- package/dist/components/editor/page-editor.svelte +7 -0
- package/dist/components/editor/{pages-navigation/page-preview.svelte → page-preview.svelte} +4 -4
- package/dist/components/editor/{pages-navigation/page-preview.svelte.d.ts → page-preview.svelte.d.ts} +2 -2
- package/dist/components/editor/page-transition-preview.svelte +34 -0
- package/dist/components/editor/page-transition-preview.svelte.d.ts +9 -0
- package/dist/components/editor/page-with-transition.svelte +48 -0
- package/dist/components/editor/page-with-transition.svelte.d.ts +10 -0
- package/dist/components/editor/page.svelte +12 -19
- package/dist/components/editor/pages-navigation/pages-navigation-item.svelte +80 -20
- package/dist/components/editor/pages-navigation/pages-navigation.svelte +7 -4
- package/dist/components/editor/sidebar/color-sidebar/color-sidebar-color.svelte +2 -2
- package/dist/components/editor/sidebar/color-sidebar/color-sidebar-gradient-picker.svelte +5 -5
- package/dist/components/editor/sidebar/color-sidebar/color-sidebar.svelte +91 -81
- package/dist/components/editor/sidebar/color-sidebar/color-sidebar.svelte.d.ts +5 -1
- package/dist/components/editor/sidebar/font-sidebar/font-sidebar.svelte +10 -6
- package/dist/components/editor/sidebar/font-sidebar/font-sidebar.svelte.d.ts +5 -1
- package/dist/components/editor/sidebar/image-crop-sidebar.svelte +28 -37
- package/dist/components/editor/sidebar/image-crop-sidebar.svelte.d.ts +2 -0
- package/dist/components/editor/sidebar/position-sidebar/index.d.ts +2 -0
- package/dist/components/editor/sidebar/position-sidebar/index.js +2 -0
- package/dist/components/editor/sidebar/position-sidebar/position-sidebar.svelte +130 -0
- package/dist/components/editor/sidebar/position-sidebar/position-sidebar.svelte.d.ts +7 -0
- package/dist/components/editor/sidebar/sidebar-text-tab.svelte +7 -3
- package/dist/components/editor/sidebar/sidebar-text-tab.svelte.d.ts +5 -16
- package/dist/components/editor/sidebar/sidebar-uploads-tab.svelte +10 -8
- package/dist/components/editor/sidebar/sidebar-uploads-tab.svelte.d.ts +5 -1
- package/dist/components/editor/sidebar/sidebar-wrapper.svelte +4 -3
- package/dist/components/editor/sidebar/sidebar-wrapper.svelte.d.ts +1 -0
- package/dist/components/editor/sidebar/sidebar.svelte +20 -13
- package/dist/components/editor/sidebar/transition-sidebar/index.d.ts +2 -0
- package/dist/components/editor/sidebar/transition-sidebar/index.js +2 -0
- package/dist/components/editor/sidebar/transition-sidebar/transition-sidebar.svelte +257 -0
- package/dist/components/editor/sidebar/transition-sidebar/transition-sidebar.svelte.d.ts +7 -0
- package/dist/components/editor/snapping-guides.svelte +3 -3
- package/dist/components/editor/types.d.ts +40 -6
- package/dist/components/editor/utils.d.ts +2 -2
- package/dist/components/editor/utils.js +21 -0
- package/dist/components/ui/button/button.svelte +2 -1
- package/dist/components/ui/button/button.svelte.d.ts +3 -0
- package/dist/components/ui/color-picker/color-picker-alpha-grid.svelte +2 -1
- package/dist/components/ui/color-picker/color-picker.svelte +6 -6
- package/dist/components/ui/context-menu/context-menu-checkbox-item.svelte +1 -1
- package/dist/components/ui/context-menu/context-menu-content.svelte +3 -1
- package/dist/components/ui/context-menu/context-menu-group-heading.svelte +1 -1
- package/dist/components/ui/context-menu/context-menu-item.svelte +1 -1
- package/dist/components/ui/context-menu/context-menu-radio-item.svelte +1 -1
- package/dist/components/ui/context-menu/context-menu-separator.svelte +1 -1
- package/dist/components/ui/context-menu/context-menu-shortcut.svelte +1 -1
- package/dist/components/ui/context-menu/context-menu-sub-content.svelte +1 -1
- package/dist/components/ui/context-menu/context-menu-sub-trigger.svelte +1 -1
- package/dist/components/ui/dialog/dialog-content.svelte +4 -2
- package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu-content.svelte +2 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-item.svelte +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +1 -1
- package/dist/components/ui/input/input.svelte +1 -1
- package/dist/components/ui/slider/slider.svelte +3 -3
- package/dist/components/ui/tabs/index.d.ts +4 -4
- package/dist/components/ui/tabs/index.js +4 -4
- package/dist/components/ui/tabs/tabs-content.svelte +4 -4
- package/dist/components/ui/tabs/tabs-content.svelte.d.ts +1 -1
- package/dist/components/ui/tabs/tabs-list.svelte +5 -9
- package/dist/components/ui/tabs/tabs-list.svelte.d.ts +1 -1
- package/dist/components/ui/tabs/tabs-trigger.svelte +4 -4
- package/dist/components/ui/tabs/tabs-trigger.svelte.d.ts +1 -1
- package/dist/transitions/circleWipe.d.ts +10 -0
- package/dist/transitions/circleWipe.js +16 -0
- package/dist/transitions/lineWipe.d.ts +9 -0
- package/dist/transitions/lineWipe.js +17 -0
- package/dist/transitions/stack.d.ts +8 -0
- package/dist/transitions/stack.js +13 -0
- package/package.json +19 -19
- package/dist/components/editor/layers/types/image/image-layer-active.svelte +0 -36
- package/dist/components/editor/layers/types/image/image-layer-active.svelte.d.ts +0 -7
- package/dist/components/editor/sidebar/position-sidebar.svelte +0 -136
- 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="
|
|
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="
|
|
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
|
-
|
|
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="
|
|
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
|
|
@@ -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="
|
|
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="
|
|
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>
|
package/dist/components/editor/layers/controls/corner-scale-control/corner-scale-control.svelte
CHANGED
|
@@ -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="
|
|
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="
|
|
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="
|
|
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
|
-
'
|
|
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="
|
|
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="
|
|
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="
|
|
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="
|
|
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="
|
|
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 '
|
|
9
|
-
import type { Page } from '
|
|
8
|
+
} from './layers/index.js';
|
|
9
|
+
import type { Page } from './types.js';
|
|
10
10
|
|
|
11
11
|
interface Props {
|
|
12
12
|
page: Page;
|
|
13
|
-
thumbScale
|
|
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 '
|
|
1
|
+
import type { Page } from './types.js';
|
|
2
2
|
interface Props {
|
|
3
3
|
page: Page;
|
|
4
|
-
thumbScale
|
|
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 './
|
|
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
|
-
|
|
39
|
-
|
|
38
|
+
const width = 1920;
|
|
39
|
+
const height = 1080;
|
|
40
40
|
|
|
41
|
-
let
|
|
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
|
-
|
|
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
|
|
59
|
-
<div
|
|
60
|
-
<
|
|
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>
|