@peteai/presentation-editor 0.0.7 → 0.0.8

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 (40) hide show
  1. package/dist/components/editor/active-layers.svelte +22 -7
  2. package/dist/components/editor/active-layers.svelte.d.ts +6 -1
  3. package/dist/components/editor/editor.svelte +15 -17
  4. package/dist/components/editor/editor.svelte.js +10 -8
  5. package/dist/components/editor/header.svelte +24 -20
  6. package/dist/components/editor/hotkeys.svelte +7 -0
  7. package/dist/components/editor/layers/buttons/opacity-button/opacity-button.svelte +1 -6
  8. package/dist/components/editor/layers/controls/group-resize-control/group-resize-control.svelte +11 -11
  9. package/dist/components/editor/layers/controls/rotate-control/rotate-control.svelte +11 -5
  10. package/dist/components/editor/layers/controls/rotate-control/rotate-control.svelte.d.ts +4 -1
  11. package/dist/components/editor/layers/controls/side-resize-control/side-resize-control.svelte +13 -13
  12. package/dist/components/editor/layers/index.d.ts +2 -2
  13. package/dist/components/editor/layers/index.js +2 -2
  14. package/dist/components/editor/layers/types/background/background-content-image.svelte +15 -20
  15. package/dist/components/editor/layers/types/background/background-layer.svelte +2 -2
  16. package/dist/components/editor/layers/types/image/controls/image-rotate-control/image-rotate-control.svelte +120 -0
  17. package/dist/components/editor/layers/types/image/controls/image-rotate-control/image-rotate-control.svelte.d.ts +8 -0
  18. package/dist/components/editor/layers/types/image/controls/image-rotate-control/index.d.ts +2 -0
  19. package/dist/components/editor/layers/types/image/controls/image-rotate-control/index.js +4 -0
  20. package/dist/components/editor/layers/types/image/controls/image-scale-control/image-scale-control.svelte +154 -0
  21. package/dist/components/editor/layers/types/image/controls/image-scale-control/image-scale-control.svelte.d.ts +91 -0
  22. package/dist/components/editor/layers/types/image/controls/image-scale-control/index.d.ts +2 -0
  23. package/dist/components/editor/layers/types/image/controls/image-scale-control/index.js +4 -0
  24. package/dist/components/editor/layers/types/image/image-layer-content.svelte +3 -3
  25. package/dist/components/editor/layers/types/image/image-layer-crop.svelte +182 -0
  26. package/dist/components/editor/layers/types/image/image-layer-crop.svelte.d.ts +10 -0
  27. package/dist/components/editor/layers/types/image/image-layer.svelte +16 -0
  28. package/dist/components/editor/layers/types/image/index.d.ts +2 -1
  29. package/dist/components/editor/layers/types/image/index.js +2 -1
  30. package/dist/components/editor/layers/types/text/extensions/list-item/list-item.js +0 -2
  31. package/dist/components/editor/layers/utils.d.ts +24 -9
  32. package/dist/components/editor/layers/utils.js +107 -54
  33. package/dist/components/editor/page-editor.svelte +6 -2
  34. package/dist/components/editor/sidebar/image-crop-sidebar.svelte +112 -0
  35. package/dist/components/editor/sidebar/image-crop-sidebar.svelte.d.ts +7 -0
  36. package/dist/components/editor/sidebar/position-sidebar.svelte +0 -2
  37. package/dist/components/editor/sidebar/sidebar.svelte +6 -3
  38. package/dist/components/editor/types.d.ts +2 -1
  39. package/dist/components/editor/utils.js +1 -0
  40. package/package.json +1 -1
@@ -1,12 +1,4 @@
1
- export const rotatePointOld = (point, angleRad) => {
2
- const cos = Math.cos(angleRad);
3
- const sin = Math.sin(angleRad);
4
- return {
5
- x: point.x * cos - point.y * sin,
6
- y: point.x * sin + point.y * cos,
7
- };
8
- };
9
- const getPoints = (origin, width, height) => {
1
+ const getOriginRelativePoint = (origin, width, height) => {
10
2
  const halfWidth = width / 2;
11
3
  const halfHeight = height / 2;
12
4
  switch (origin) {
@@ -41,36 +33,42 @@ export const calculateLayerTransform = (layer, groupScale = 1) => ({
41
33
  scale: layer.scale,
42
34
  });
43
35
  export const calculateNewPosition = (origin, transform, newWidth, newHeight) => {
44
- const { x, y, width, height, rotate, scale } = transform;
45
- const oldPoint = getPoints(origin, width * scale, height * scale);
46
- const newPoint = getPoints(origin, newWidth, newHeight);
47
- let deltaX = newPoint.x - oldPoint.x;
48
- let deltaY = newPoint.y - oldPoint.y;
49
- if (rotate !== 0) {
50
- const rad = (rotate * Math.PI) / 180;
51
- const rotatedOldCenter = rotatePointOld(oldPoint, rad);
52
- const rotatedNewCenter = rotatePointOld(newPoint, rad);
53
- deltaX = rotatedNewCenter.x - rotatedOldCenter.x;
54
- deltaY = rotatedNewCenter.y - rotatedOldCenter.y;
55
- }
36
+ const { x, y, width: rawWidth, height: rawHeight, rotate, scale } = transform;
37
+ const width = rawWidth * scale;
38
+ const height = rawHeight * scale;
39
+ // Get relative points based on origin for old and new dimensions
40
+ const oldPoint = getOriginRelativePoint(origin, width, height);
41
+ const newPoint = getOriginRelativePoint(origin, newWidth, newHeight);
42
+ // Calculate position delta
43
+ const delta = {
44
+ x: newPoint.x - oldPoint.x,
45
+ y: newPoint.y - oldPoint.y,
46
+ };
47
+ // Apply rotation if needed
48
+ const rotatedDelta = rotate !== 0 ? rotatePoint(degToRad(rotate), delta) : delta;
49
+ // Calculate new position accounting for size difference and delta
56
50
  return {
57
- newX: x - deltaX - (newWidth - width * scale) / 2,
58
- newY: y - deltaY - (newHeight - height * scale) / 2,
51
+ newX: x - rotatedDelta.x - (newWidth - width) / 2,
52
+ newY: y - rotatedDelta.y - (newHeight - height) / 2,
59
53
  };
60
54
  };
61
55
  export function calculateBoundingBox(transform) {
62
- const { x, y, width, height, rotate, scale } = transform;
56
+ const { x, y, width: rawWidth, height: rawHeight, rotate, scale } = transform;
57
+ const width = rawWidth * scale;
58
+ const height = rawHeight * scale;
63
59
  if (rotate === 0) {
64
- return { x, y, width: width * scale, height: height * scale };
60
+ return { x, y, width, height };
65
61
  }
66
- const radians = (rotate * Math.PI) / 180;
67
- const origins = ['top-left', 'top-right'];
68
- const corners = origins.map((position) => rotatePointOld(getPoints(position, width * scale, height * scale), radians));
69
- const maxX = Math.max(...corners.map((corner) => Math.abs(corner.x)));
70
- const maxY = Math.max(...corners.map((corner) => Math.abs(corner.y)));
62
+ const rad = degToRad(rotate);
63
+ const cos = Math.cos(rad);
64
+ const sin = Math.sin(rad);
65
+ const hw = width / 2;
66
+ const hh = height / 2;
67
+ const maxX = Math.abs(hw * cos) + Math.abs(hh * sin);
68
+ const maxY = Math.abs(hw * sin) + Math.abs(hh * cos);
71
69
  return {
72
- x: x + (width * scale) / 2 - maxX,
73
- y: y + (height * scale) / 2 - maxY,
70
+ x: x + width / 2 - maxX,
71
+ y: y + height / 2 - maxY,
74
72
  width: maxX * 2,
75
73
  height: maxY * 2,
76
74
  };
@@ -78,20 +76,20 @@ export function calculateBoundingBox(transform) {
78
76
  export function degToRad(deg) {
79
77
  return (deg * Math.PI) / 180;
80
78
  }
81
- export function rotatePoint(p, origin, angleRad) {
82
- const dx = p.x - origin.x;
83
- const dy = p.y - origin.y;
84
- const cos = Math.cos(angleRad);
85
- const sin = Math.sin(angleRad);
79
+ export function rotatePoint(rad, p, center = { x: 0, y: 0 }) {
80
+ const cos = Math.cos(rad);
81
+ const sin = Math.sin(rad);
82
+ const dx = p.x - center.x;
83
+ const dy = p.y - center.y;
86
84
  return {
87
- x: origin.x + dx * cos - dy * sin,
88
- y: origin.y + dx * sin + dy * cos,
85
+ x: center.x + dx * cos - dy * sin,
86
+ y: center.y + dx * sin + dy * cos,
89
87
  };
90
88
  }
91
89
  export function getRotatedCorners(rect) {
90
+ const rad = degToRad(rect.rotate);
92
91
  const cx = rect.x + (rect.width * rect.scale) / 2;
93
92
  const cy = rect.y + (rect.height * rect.scale) / 2;
94
- const angle = degToRad(rect.rotate);
95
93
  const hw = (rect.width * rect.scale) / 2;
96
94
  const hh = (rect.height * rect.scale) / 2;
97
95
  const corners = [
@@ -100,7 +98,7 @@ export function getRotatedCorners(rect) {
100
98
  { x: cx + hw, y: cy + hh },
101
99
  { x: cx - hw, y: cy + hh },
102
100
  ];
103
- return corners.map((p) => rotatePoint(p, { x: cx, y: cy }, angle));
101
+ return corners.map((p) => rotatePoint(rad, p, { x: cx, y: cy }));
104
102
  }
105
103
  export function isRotatedVertically(rotate) {
106
104
  const rotationNormalized = ((rotate % 360) + 360) % 360;
@@ -166,9 +164,9 @@ export function calculateGroupRotatedBoundingBox(transforms, rotate = 0) {
166
164
  if (!rotate)
167
165
  return calculateGroupBoundingBox(transforms);
168
166
  const allCorners = transforms.flatMap((t) => getRotatedCorners(t));
169
- const theta = degToRad(-rotate); // inverse to align bbox with axes
167
+ const rad = degToRad(rotate);
170
168
  // Rotate all points to align with desired angle
171
- const rotatedPoints = allCorners.map((p) => rotatePoint(p, { x: 0, y: 0 }, theta));
169
+ const rotatedPoints = allCorners.map((p) => rotatePoint(-rad, p));
172
170
  // Compute AABB of rotated points
173
171
  const xs = rotatedPoints.map((p) => p.x);
174
172
  const ys = rotatedPoints.map((p) => p.y);
@@ -183,7 +181,7 @@ export function calculateGroupRotatedBoundingBox(transforms, rotate = 0) {
183
181
  y: (minY + maxY) / 2,
184
182
  };
185
183
  // Rotate center back to original space
186
- const center = rotatePoint(centerRotated, { x: 0, y: 0 }, degToRad(rotate));
184
+ const center = rotatePoint(rad, centerRotated);
187
185
  return {
188
186
  x: center.x - width / 2,
189
187
  y: center.y - height / 2,
@@ -194,7 +192,7 @@ export function calculateGroupRotatedBoundingBox(transforms, rotate = 0) {
194
192
  };
195
193
  }
196
194
  export function calculateRelativeRects(bbox, absoluteRects) {
197
- const theta = degToRad(-bbox.rotate); // inverse to align bbox with axes
195
+ const rad = degToRad(bbox.rotate); // inverse to align bbox with axes
198
196
  const bboxCenter = {
199
197
  x: bbox.x + (bbox.width * bbox.scale) / 2,
200
198
  y: bbox.y + (bbox.height * bbox.scale) / 2,
@@ -206,17 +204,18 @@ export function calculateRelativeRects(bbox, absoluteRects) {
206
204
  y: rect.y + (rect.height * rect.scale) / 2,
207
205
  };
208
206
  // Rotate center ralatively to the bbox center
209
- const relativeCenter = rotatePoint(center, bboxCenter, theta);
207
+ const relativeCenter = rotatePoint(-rad, center, bboxCenter);
210
208
  return {
211
209
  ...rect,
212
- x: (relativeCenter.x - bbox.x) / bbox.scale - (rect.width * rect.scale) / 2,
213
- y: (relativeCenter.y - bbox.y) / bbox.scale - (rect.height * rect.scale) / 2,
210
+ x: ((relativeCenter.x - bbox.x) / bbox.scale - (rect.width * rect.scale) / 2) / bbox.scale,
211
+ y: ((relativeCenter.y - bbox.y) / bbox.scale - (rect.height * rect.scale) / 2) / bbox.scale,
214
212
  rotate: rect.rotate - bbox.rotate,
213
+ scale: rect.scale / bbox.scale,
215
214
  };
216
215
  });
217
216
  }
218
217
  export function calculateAbsoluteRects(bbox, rects) {
219
- const theta = degToRad(bbox.rotate);
218
+ const rad = degToRad(bbox.rotate);
220
219
  const bboxCenter = {
221
220
  x: bbox.x + (bbox.width * bbox.scale) / 2,
222
221
  y: bbox.y + (bbox.height * bbox.scale) / 2,
@@ -226,7 +225,7 @@ export function calculateAbsoluteRects(bbox, rects) {
226
225
  x: bbox.x + (rect.x + (rect.width * rect.scale) / 2) * bbox.scale,
227
226
  y: bbox.y + (rect.y + (rect.height * rect.scale) / 2) * bbox.scale,
228
227
  };
229
- const center = rotatePoint(relativeCenter, bboxCenter, theta);
228
+ const center = rotatePoint(rad, relativeCenter, bboxCenter);
230
229
  return {
231
230
  ...rect,
232
231
  x: center.x - (rect.width * rect.scale * bbox.scale) / 2,
@@ -293,12 +292,14 @@ const minScaleToContain = (rotatedRect, rect) => {
293
292
  };
294
293
  export function calculateImageCover(image, bbox) {
295
294
  const scale = minScaleToContain(image, bbox);
295
+ const width = bbox.width / scale;
296
+ const height = bbox.height / scale;
296
297
  return {
297
- width: bbox.width / scale,
298
- height: bbox.height / scale,
298
+ width,
299
+ height,
299
300
  scale,
300
- offsetX: (image.width - bbox.width / scale) / 2,
301
- offsetY: (image.height - bbox.height / scale) / 2,
301
+ offsetX: (width - image.width) / 2,
302
+ offsetY: (height - image.height) / 2,
302
303
  };
303
304
  }
304
305
  export const defaultColor = '#000000';
@@ -322,3 +323,55 @@ export function buildBackgroundCircleStyle(colors) {
322
323
  .join(', ');
323
324
  return `background-image: conic-gradient(${gradientColors})`;
324
325
  }
326
+ export function getImageLayerBboxRelativeToImageCenter(layer) {
327
+ const { width, height, image, offsetX, offsetY, imageRotate } = layer;
328
+ // current image center in layer coords (rotation doesn't change it)
329
+ const imageCenter = { x: image.width / 2 + offsetX, y: image.height / 2 + offsetY };
330
+ const imageRad = degToRad(imageRotate);
331
+ // For each corner, compute v = corner - C, rotate by -theta, accumulate max abs X/Y
332
+ const corners = [
333
+ { x: 0, y: 0 },
334
+ { x: width, y: 0 },
335
+ { x: width, y: height },
336
+ { x: 0, y: height },
337
+ ].map((p) => {
338
+ const v = { x: p.x - imageCenter.x, y: p.y - imageCenter.y }; // layer->center
339
+ return rotatePoint(-imageRad, v); // bring into image unrotated axes
340
+ });
341
+ // Compute AABB of rotated points
342
+ const xs = corners.map((p) => p.x);
343
+ const ys = corners.map((p) => p.y);
344
+ const minX = Math.min(...xs);
345
+ const maxX = Math.max(...xs);
346
+ const minY = Math.min(...ys);
347
+ const maxY = Math.max(...ys);
348
+ return { minX, minY, maxX, maxY };
349
+ }
350
+ export function calculateImageLayerPropsForImageRotate(layer, imageRotate) {
351
+ const { width, height, scale, image, offsetX, offsetY } = layer;
352
+ // image half-width and half-height
353
+ const ihw = image.width / 2;
354
+ const ihh = image.height / 2;
355
+ // current image center in layer coords (rotation doesn't change it)
356
+ const imageCenter = { x: ihw + offsetX, y: ihh + offsetY };
357
+ const bbox = getImageLayerBboxRelativeToImageCenter({ ...layer, imageRotate });
358
+ const maxAbsX = Math.max(Math.abs(bbox.minX), Math.abs(bbox.maxX));
359
+ const maxAbsY = Math.max(Math.abs(bbox.minY), Math.abs(bbox.maxY));
360
+ // Required scale so half-extents of (Iw*s, Ih*s) cover maxAbsX/Y:
361
+ // Iw*s/2 >= maxAbsX => s >= 2*maxAbsX / Iw
362
+ // Ih*s/2 >= maxAbsY => s >= 2*maxAbsY / Ih
363
+ const sReqX = (2 * maxAbsX) / image.width;
364
+ const sReqY = (2 * maxAbsY) / image.height;
365
+ const minScaleFactor = Math.max(sReqX, sReqY);
366
+ if (minScaleFactor < 1) {
367
+ return { imageRotate };
368
+ }
369
+ return {
370
+ imageRotate,
371
+ scale: scale * minScaleFactor,
372
+ width: width / minScaleFactor,
373
+ height: height / minScaleFactor,
374
+ offsetX: imageCenter.x / minScaleFactor - ihw,
375
+ offsetY: imageCenter.y / minScaleFactor - ihh,
376
+ };
377
+ }
@@ -25,6 +25,8 @@
25
25
 
26
26
  const editor = getEditorContext();
27
27
 
28
+ let pageRef: HTMLDivElement | null = $state(null);
29
+
28
30
  let activeLayerGuides: ActiveLayerGuide[] = $state([]);
29
31
 
30
32
  let hoveredLayerId: string | null = $state(null);
@@ -38,7 +40,7 @@
38
40
  <div class="flex min-h-full flex-1">
39
41
  <div class="box-border flex w-full shrink-0 items-center justify-center p-0">
40
42
  <div bind:this={wrapperRef} class="translate-x-0 translate-y-0 p-4 transition-transform">
41
- <div class="relative flex flex-col items-center" data-page-container>
43
+ <div bind:this={pageRef} class="relative flex flex-col items-center">
42
44
  <div
43
45
  class="m-0 overflow-hidden shadow-xl"
44
46
  style:width="{scaledWidth}px"
@@ -89,7 +91,9 @@
89
91
  {/if}
90
92
  {/if}
91
93
 
92
- <ActiveLayers />
94
+ {#if viewportRef && pageRef}
95
+ <ActiveLayers {viewportRef} {wrapperRef} {pageRef} />
96
+ {/if}
93
97
 
94
98
  <SnappingGuides zoom={editor.zoom} guides={activeLayerGuides} />
95
99
  </div>
@@ -0,0 +1,112 @@
1
+ <script lang="ts">
2
+ import XIcon from '@lucide/svelte/icons/x';
3
+ import { Button } from '../../ui/button/index.js';
4
+ import { Slider } from '../../ui/slider/index.js';
5
+ import { Input } from '../../ui/input/index.js';
6
+ import { getEditorContext } from '../editor.svelte.js';
7
+ import {
8
+ calculateImageLayerPropsForImageRotate,
9
+ calculateRelativeRects,
10
+ } from '../layers/utils.js';
11
+ import type { ImageLayer } from '../types.js';
12
+
13
+ interface Props {
14
+ layer: ImageLayer;
15
+ }
16
+
17
+ let { layer }: Props = $props();
18
+
19
+ const editor = $derived(getEditorContext());
20
+
21
+ let value = $derived(Math.round(layer.imageRotate * 10) / 10);
22
+ let originalLayer = $derived(
23
+ editor.selectedLayersNotLocked.find((l) => l.id === layer.id),
24
+ ) as ImageLayer;
25
+
26
+ const min = -180;
27
+ const max = 180;
28
+ const step = 0.1;
29
+
30
+ let layerCache: ImageLayer | null = $state.snapshot(null);
31
+
32
+ const setImageRotate = (value: string | number) => {
33
+ value = Number(value);
34
+ if (!layerCache) {
35
+ layerCache = $state.snapshot(layer);
36
+ }
37
+ const props = calculateImageLayerPropsForImageRotate(layerCache, value);
38
+ Object.assign(layer, props);
39
+ };
40
+
41
+ const applyChanges = () => {
42
+ if (!originalLayer) return;
43
+ const relativeLayer = editor.activeGroupAndChild
44
+ ? (calculateRelativeRects(editor.activeGroupAndChild.groupLayer, [layer])[0] as ImageLayer)
45
+ : layer;
46
+ // Define keys to check for changes in image layer properties
47
+ const imageLayerKeys: (keyof ImageLayer)[] = [
48
+ 'imageRotate', // Rotation angle of the image
49
+ 'scale', // Scale/zoom level
50
+ 'width', // Width dimension
51
+ 'height', // Height dimension
52
+ 'offsetX', // X offset position
53
+ 'offsetY', // Y offset position
54
+ ];
55
+
56
+ // Filter keys that have different values between original and relative layers
57
+ const changedKeys = imageLayerKeys.filter((key) => originalLayer[key] !== relativeLayer[key]);
58
+ if (changedKeys.length > 0) {
59
+ editor.historyPush({
60
+ type: 'layerUpdate',
61
+ pageId: editor.activePage.id,
62
+ layer: { id: layer.id, type: layer.type },
63
+ undo: Object.fromEntries(changedKeys.map((key) => [key, originalLayer[key]])),
64
+ redo: Object.fromEntries(changedKeys.map((key) => [key, relativeLayer[key]])),
65
+ });
66
+ }
67
+ editor.imageCropLayer = null;
68
+ };
69
+
70
+ $effect(() => {
71
+ if (!originalLayer) {
72
+ editor.imageCropLayer = null;
73
+ }
74
+ });
75
+ </script>
76
+
77
+ <div class="flex h-full flex-col gap-2">
78
+ <div class="flex items-center justify-between">
79
+ <div class="text-sm font-bold">Crop</div>
80
+ <Button variant="ghost" size="icon" onclick={() => (editor.imageCropLayer = null)}>
81
+ <XIcon />
82
+ </Button>
83
+ </div>
84
+ <div class="flex-1 resize-none overflow-y-auto">
85
+ <div class="flex items-center gap-2">
86
+ <div class="grow">
87
+ <Slider
88
+ type="single"
89
+ {value}
90
+ {min}
91
+ {max}
92
+ {step}
93
+ onValueChange={(value) => setImageRotate(value)}
94
+ onValueCommit={() => (layerCache = null)}
95
+ />
96
+ </div>
97
+ <Input
98
+ class="w-12 bg-transparent p-0 text-center font-semibold leading-none [&::-webkit-inner-spin-button]:appearance-none"
99
+ inputmode="decimal"
100
+ placeholder="--"
101
+ {value}
102
+ onchange={(e) => setImageRotate(e.currentTarget.value)}
103
+ />
104
+ </div>
105
+ <div class="flex justify-end gap-2 p-2">
106
+ <Button class="flex-1" variant="outline" onclick={() => (editor.imageCropLayer = null)}>
107
+ Cancel
108
+ </Button>
109
+ <Button class="flex-1" onclick={applyChanges}>Done</Button>
110
+ </div>
111
+ </div>
112
+ </div>
@@ -0,0 +1,7 @@
1
+ import type { ImageLayer } from '../types.js';
2
+ interface Props {
3
+ layer: ImageLayer;
4
+ }
5
+ declare const ImageCropSidebar: import("svelte").Component<Props, {}, "">;
6
+ type ImageCropSidebar = ReturnType<typeof ImageCropSidebar>;
7
+ export default ImageCropSidebar;
@@ -19,8 +19,6 @@
19
19
 
20
20
  const editor = $derived(getEditorContext());
21
21
 
22
- $inspect(editor.sortedPages);
23
-
24
22
  const flipDurationMs = 300;
25
23
  const otherOptions = { flipDurationMs, type: 'layers', dropTargetStyle: {} };
26
24
 
@@ -10,6 +10,7 @@
10
10
  import PositionSidebar from './position-sidebar.svelte';
11
11
  import { ColorSidebar } from './color-sidebar/index.js';
12
12
  import { FontSidebar } from './font-sidebar/index.js';
13
+ import ImageCropSidebar from './image-crop-sidebar.svelte';
13
14
 
14
15
  interface Props {
15
16
  editor: Editor;
@@ -62,13 +63,15 @@
62
63
  {/each}
63
64
  </div>
64
65
 
65
- {#if editor.activeSidebarPopup || editor.activeSidebarTab}
66
+ {#if editor.activeSidebarPopup || editor.activeSidebarTab || editor.imageCropLayer}
66
67
  <div class="bg-background h-full w-80 shrink-0 overflow-y-auto border-r border-gray-200 p-2">
67
- {#if editor.activeSidebarPopup === 'position'}
68
+ {#if editor.imageCropLayer}
69
+ <ImageCropSidebar layer={editor.imageCropLayer} />
70
+ {:else if editor.activeSidebarPopup === 'position'}
68
71
  <PositionSidebar />
69
72
  {:else if editor.activeSidebarPopup === 'font'}
70
73
  <FontSidebar />
71
- {:else if editor.activeSidebarPopup}
74
+ {:else if editor.activeSidebarPopup?.indexOf('Color')}
72
75
  <ColorSidebar />
73
76
  {:else if editor.activeSidebarTab === 'text'}
74
77
  <SidebarTextTab />
@@ -46,6 +46,7 @@ export type LayerBorder = {
46
46
  export interface ImageLayer extends BaseLayer, LayerBorder {
47
47
  type: 'image';
48
48
  image: Image;
49
+ imageRotate: number;
49
50
  offsetX: number;
50
51
  offsetY: number;
51
52
  cornerRadius: number;
@@ -61,7 +62,7 @@ export type Gradient = {
61
62
  type: 'linear90' | 'linear180' | 'linear135' | 'radialCenter' | 'radialTopLeft';
62
63
  colors: string[];
63
64
  };
64
- export type BackgroundImage = Pick<ImageLayer, 'rotate' | 'opacity' | 'scale' | 'image' | 'offsetX' | 'offsetY' | 'flipX' | 'flipY'>;
65
+ export type BackgroundImage = Pick<ImageLayer, 'opacity' | 'scale' | 'image' | 'imageRotate' | 'offsetX' | 'offsetY' | 'flipX' | 'flipY'>;
65
66
  export type Page = {
66
67
  id: string;
67
68
  backgroundColor: string | null;
@@ -363,6 +363,7 @@ const buildTextLayerBulletsFields = ({ bullets }) => ({
363
363
  });
364
364
  const buildImageLayerFields = (image) => ({
365
365
  image,
366
+ imageRotate: 0,
366
367
  offsetX: 0,
367
368
  offsetY: 0,
368
369
  cornerRadius: 0,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peteai/presentation-editor",
3
- "version": "0.0.7",
3
+ "version": "0.0.8",
4
4
  "scripts": {
5
5
  "dev": "vite dev",
6
6
  "build": "vite build && npm run package",