@peteai/presentation-editor 0.0.9 → 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/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/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.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 +9 -5
- 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 +8 -6
- 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/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/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 +1 -1
- 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
|
@@ -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="h-12 w-full border-b border-gray-200
|
|
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
|
|
@@ -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>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { dragHandle } from 'svelte-dnd-action';
|
|
3
3
|
import PlusIcon from '@lucide/svelte/icons/plus';
|
|
4
|
+
import ArrowBigRightDashIcon from '@lucide/svelte/icons/arrow-big-right-dash';
|
|
4
5
|
import EllipsisIcon from '@lucide/svelte/icons/ellipsis';
|
|
5
6
|
import IconLocked from '@lucide/svelte/icons/lock-keyhole';
|
|
6
7
|
import { Button, buttonVariants } from '../../ui/button/index.js';
|
|
@@ -9,8 +10,8 @@
|
|
|
9
10
|
import { cn } from '../../../utils.js';
|
|
10
11
|
import type { Editor } from '../editor.svelte.js';
|
|
11
12
|
import type { Page } from '../types.js';
|
|
12
|
-
import
|
|
13
|
-
import PagePreview from '
|
|
13
|
+
import PageMenuContent from '../menu/page-menu-content.svelte';
|
|
14
|
+
import PagePreview from '../page-preview.svelte';
|
|
14
15
|
|
|
15
16
|
interface Props {
|
|
16
17
|
editor: Editor;
|
|
@@ -24,27 +25,29 @@
|
|
|
24
25
|
let menuOpen = $state(false);
|
|
25
26
|
</script>
|
|
26
27
|
|
|
27
|
-
<div class="relative flex items-
|
|
28
|
-
|
|
29
|
-
<div class="
|
|
30
|
-
|
|
31
|
-
class="relative z-30 flex h-full w-0 items-center justify-center transition-all duration-300 group-hover:w-6"
|
|
32
|
-
>
|
|
28
|
+
<div class="relative flex items-stretch">
|
|
29
|
+
{#if index === 0}
|
|
30
|
+
<div class="group ml-2 py-2">
|
|
31
|
+
<div class="absolute -left-2 top-0 z-20 h-full w-4 group-hover:w-16"></div>
|
|
33
32
|
<div
|
|
34
|
-
class="
|
|
35
|
-
role="menu"
|
|
33
|
+
class="relative z-30 flex h-full w-0 items-center justify-center transition-all duration-300 group-hover:w-6"
|
|
36
34
|
>
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
class="my-1 h-6 w-6 rounded-full"
|
|
41
|
-
onclick={() => editor.addPage({ index })}
|
|
35
|
+
<div
|
|
36
|
+
class="absolute inline-flex flex-col opacity-0 transition-opacity duration-500 group-hover:opacity-100"
|
|
37
|
+
role="menu"
|
|
42
38
|
>
|
|
43
|
-
<
|
|
44
|
-
|
|
39
|
+
<Button
|
|
40
|
+
variant="outline"
|
|
41
|
+
size="icon-xs"
|
|
42
|
+
class="my-1 h-6 w-6 rounded-full"
|
|
43
|
+
onclick={() => editor.addPage({ index })}
|
|
44
|
+
>
|
|
45
|
+
<PlusIcon class="h-4 w-4" />
|
|
46
|
+
</Button>
|
|
47
|
+
</div>
|
|
45
48
|
</div>
|
|
46
49
|
</div>
|
|
47
|
-
|
|
50
|
+
{/if}
|
|
48
51
|
<div class="group relative mx-2 my-1 transition-transform">
|
|
49
52
|
<div use:dragHandle role="none">
|
|
50
53
|
<button class="block" onclick={() => editor.setActivePage(page.id)}>
|
|
@@ -73,7 +76,7 @@
|
|
|
73
76
|
</div>
|
|
74
77
|
</ContextMenu.Trigger>
|
|
75
78
|
<ContextMenu.Content class="w-72">
|
|
76
|
-
<
|
|
79
|
+
<PageMenuContent {editor} {page} />
|
|
77
80
|
</ContextMenu.Content>
|
|
78
81
|
</ContextMenu.Root>
|
|
79
82
|
</button>
|
|
@@ -115,9 +118,66 @@
|
|
|
115
118
|
</DropdownMenu.Trigger>
|
|
116
119
|
|
|
117
120
|
<DropdownMenu.Content class="w-72" side="top" align="start" trapFocus={false}>
|
|
118
|
-
<
|
|
121
|
+
<PageMenuContent {editor} {page} />
|
|
119
122
|
</DropdownMenu.Content>
|
|
120
123
|
</DropdownMenu.Root>
|
|
121
124
|
</div>
|
|
122
125
|
</div>
|
|
126
|
+
{#if index < editor.pages.length - 1}
|
|
127
|
+
<div class="group py-2">
|
|
128
|
+
<div class="absolute -right-2 top-0 z-20 h-full w-4 group-hover:w-16"></div>
|
|
129
|
+
<div
|
|
130
|
+
class="relative z-30 flex h-full w-0 items-center justify-center transition-all duration-300 group-hover:w-6"
|
|
131
|
+
>
|
|
132
|
+
<!-- {#if page.transition}
|
|
133
|
+
<div
|
|
134
|
+
class="absolute inline-flex flex-col opacity-100 transition-opacity duration-500 group-hover:opacity-0"
|
|
135
|
+
>
|
|
136
|
+
<Button
|
|
137
|
+
variant="outline"
|
|
138
|
+
size="icon-xs"
|
|
139
|
+
active={page.id === editor.activePage.id}
|
|
140
|
+
class="my-1 h-6 w-6 rounded-full"
|
|
141
|
+
onclick={() => editor.setActivePage(page.id)}
|
|
142
|
+
>
|
|
143
|
+
<ArrowBigRightDashIcon class="h-4 w-4" />
|
|
144
|
+
</Button>
|
|
145
|
+
</div>
|
|
146
|
+
{/if} -->
|
|
147
|
+
<div class="flex h-full flex-col items-center" role="menu">
|
|
148
|
+
<div
|
|
149
|
+
class="flex flex-1 items-center opacity-0 transition-all duration-500 group-hover:opacity-100"
|
|
150
|
+
>
|
|
151
|
+
<Button
|
|
152
|
+
variant="outline"
|
|
153
|
+
size="icon-xs"
|
|
154
|
+
class="h-6 w-6 rounded-full"
|
|
155
|
+
onclick={() => editor.addPage({ index: index + 1 })}
|
|
156
|
+
>
|
|
157
|
+
<PlusIcon class="h-4 w-4" />
|
|
158
|
+
</Button>
|
|
159
|
+
</div>
|
|
160
|
+
<div
|
|
161
|
+
class={cn(
|
|
162
|
+
'flex flex-1 items-center transition-all group-hover:translate-y-0 group-hover:opacity-100',
|
|
163
|
+
page.transition ? '-translate-y-1/2 duration-300' : 'opacity-0 duration-500',
|
|
164
|
+
)}
|
|
165
|
+
>
|
|
166
|
+
<Button
|
|
167
|
+
variant="outline"
|
|
168
|
+
size="icon-xs"
|
|
169
|
+
class="h-6 w-6 rounded-full"
|
|
170
|
+
active={!!page.transition && page.id === editor.activePage.id}
|
|
171
|
+
onclick={() => {
|
|
172
|
+
editor.setActivePage(page.id);
|
|
173
|
+
editor.activeSidebarPopup = 'transition';
|
|
174
|
+
}}
|
|
175
|
+
>
|
|
176
|
+
<ArrowBigRightDashIcon class="h-4 w-4" />
|
|
177
|
+
</Button>
|
|
178
|
+
</div>
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
</div>
|
|
182
|
+
{/if}
|
|
123
183
|
</div>
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import type { Editor } from '../editor.svelte.js';
|
|
6
6
|
import type { Page } from '../types.js';
|
|
7
7
|
import PagesNavigationItem from './pages-navigation-item.svelte';
|
|
8
|
+
import { Button } from '../../ui/button/index.js';
|
|
8
9
|
|
|
9
10
|
interface Props {
|
|
10
11
|
editor: Editor;
|
|
@@ -85,19 +86,21 @@
|
|
|
85
86
|
{/each}
|
|
86
87
|
</section>
|
|
87
88
|
<div class="relative py-2" role="none">
|
|
88
|
-
<
|
|
89
|
-
|
|
89
|
+
<Button
|
|
90
|
+
variant="outline"
|
|
91
|
+
size="vague"
|
|
92
|
+
class="mx-2 my-1 rounded-lg"
|
|
90
93
|
aria-label="New Page"
|
|
91
94
|
onclick={() => editor.addPage({ index: editor.pages.length })}
|
|
92
95
|
>
|
|
93
96
|
<div
|
|
94
|
-
class="relative flex items-center justify-center
|
|
97
|
+
class="relative flex items-center justify-center"
|
|
95
98
|
style:width="{editor.width * thumbScale}px"
|
|
96
99
|
style:height="{editor.height * thumbScale}px"
|
|
97
100
|
>
|
|
98
101
|
<PlusIcon class="h-6 w-6" />
|
|
99
102
|
</div>
|
|
100
|
-
</
|
|
103
|
+
</Button>
|
|
101
104
|
</div>
|
|
102
105
|
</div>
|
|
103
106
|
</nav>
|