@peteai/presentation-editor 0.0.1 → 0.0.3

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 (214) hide show
  1. package/README.md +172 -38
  2. package/dist/components/presentation-editor/active-layers-buttons.svelte +53 -0
  3. package/dist/components/presentation-editor/active-layers-buttons.svelte.d.ts +3 -0
  4. package/dist/components/presentation-editor/active-layers.svelte +181 -0
  5. package/dist/components/presentation-editor/active-layers.svelte.d.ts +3 -0
  6. package/dist/components/presentation-editor/color-indicator/color-indicator-gradient-def.svelte +81 -0
  7. package/dist/components/presentation-editor/color-indicator/color-indicator-gradient-def.svelte.d.ts +9 -0
  8. package/dist/components/presentation-editor/color-indicator/color-indicator-gradient.svelte +21 -0
  9. package/dist/components/presentation-editor/color-indicator/color-indicator-gradient.svelte.d.ts +8 -0
  10. package/dist/components/presentation-editor/color-indicator/color-indicator.svelte +23 -0
  11. package/dist/components/presentation-editor/color-indicator/color-indicator.svelte.d.ts +6 -0
  12. package/dist/components/presentation-editor/color-indicator/index.d.ts +4 -0
  13. package/dist/components/presentation-editor/color-indicator/index.js +6 -0
  14. package/dist/components/presentation-editor/cursor-tooltip.svelte +1 -1
  15. package/dist/components/presentation-editor/dragged.svelte +21 -11
  16. package/dist/components/presentation-editor/fonts.d.ts +3 -0
  17. package/dist/components/presentation-editor/fonts.js +1278 -0
  18. package/dist/components/presentation-editor/header.svelte +21 -33
  19. package/dist/components/presentation-editor/header.svelte.d.ts +16 -6
  20. package/dist/components/presentation-editor/hotkeys.svelte +85 -0
  21. package/dist/components/presentation-editor/{sidebar/layers.svelte.d.ts → hotkeys.svelte.d.ts} +3 -3
  22. package/dist/components/presentation-editor/layers/active-background-border.svelte +3 -7
  23. package/dist/components/presentation-editor/layers/active-layer-border.svelte +2 -5
  24. package/dist/components/presentation-editor/layers/active-layer-border.svelte.d.ts +0 -1
  25. package/dist/components/presentation-editor/layers/buttons/border-button/border-button.svelte +113 -129
  26. package/dist/components/presentation-editor/layers/buttons/border-button/border-button.svelte.d.ts +2 -2
  27. package/dist/components/presentation-editor/layers/buttons/corner-radius-button/corner-radius-button.svelte +51 -32
  28. package/dist/components/presentation-editor/layers/buttons/corner-radius-button/corner-radius-button.svelte.d.ts +2 -2
  29. package/dist/components/presentation-editor/layers/buttons/flip-button/flip-button.svelte +30 -7
  30. package/dist/components/presentation-editor/layers/buttons/flip-button/flip-button.svelte.d.ts +3 -3
  31. package/dist/components/presentation-editor/layers/buttons/opacity-button/opacity-button.svelte +76 -33
  32. package/dist/components/presentation-editor/layers/buttons/opacity-button/opacity-button.svelte.d.ts +3 -3
  33. package/dist/components/presentation-editor/layers/controls/corner-scale-control/corner-scale-control.svelte +89 -59
  34. package/dist/components/presentation-editor/layers/controls/corner-scale-control/corner-scale-control.svelte.d.ts +5 -100
  35. package/dist/components/presentation-editor/layers/controls/group-resize-control/group-resize-control.svelte +337 -0
  36. package/dist/components/presentation-editor/layers/controls/group-resize-control/group-resize-control.svelte.d.ts +104 -0
  37. package/dist/components/presentation-editor/layers/controls/group-resize-control/index.d.ts +2 -0
  38. package/dist/components/presentation-editor/layers/controls/group-resize-control/index.js +4 -0
  39. package/dist/components/presentation-editor/layers/controls/rotate-control/rotate-control.svelte +128 -43
  40. package/dist/components/presentation-editor/layers/controls/rotate-control/rotate-control.svelte.d.ts +1 -5
  41. package/dist/components/presentation-editor/layers/controls/side-resize-control/side-resize-control.svelte +68 -57
  42. package/dist/components/presentation-editor/layers/controls/side-resize-control/side-resize-control.svelte.d.ts +2 -110
  43. package/dist/components/presentation-editor/layers/controls/side-scale-control/side-scale-control.svelte +45 -32
  44. package/dist/components/presentation-editor/layers/controls/side-scale-control/side-scale-control.svelte.d.ts +2 -54
  45. package/dist/components/presentation-editor/layers/index.d.ts +4 -5
  46. package/dist/components/presentation-editor/layers/index.js +7 -8
  47. package/dist/components/presentation-editor/layers/layer-button.svelte +25 -7
  48. package/dist/components/presentation-editor/layers/layer-wrapper.svelte +212 -162
  49. package/dist/components/presentation-editor/layers/layer-wrapper.svelte.d.ts +2 -2
  50. package/dist/components/presentation-editor/layers/types/background/background-content-image.svelte +41 -0
  51. package/dist/components/presentation-editor/layers/types/background/background-content-image.svelte.d.ts +8 -0
  52. package/dist/components/presentation-editor/layers/types/background/background-layer-buttons.svelte +28 -74
  53. package/dist/components/presentation-editor/layers/types/background/background-layer-buttons.svelte.d.ts +2 -17
  54. package/dist/components/presentation-editor/layers/types/background/background-layer-content.svelte +19 -0
  55. package/dist/components/presentation-editor/layers/types/background/background-layer-content.svelte.d.ts +8 -0
  56. package/dist/components/presentation-editor/layers/types/background/background-layer.svelte +69 -61
  57. package/dist/components/presentation-editor/layers/types/background/background-layer.svelte.d.ts +2 -3
  58. package/dist/components/presentation-editor/layers/types/background/index.d.ts +2 -3
  59. package/dist/components/presentation-editor/layers/types/background/index.js +2 -3
  60. package/dist/components/presentation-editor/layers/types/html/buttons/alignment-button/alignment-button.svelte +55 -12
  61. package/dist/components/presentation-editor/layers/types/html/buttons/alignment-button/alignment-button.svelte.d.ts +3 -3
  62. package/dist/components/presentation-editor/layers/types/html/buttons/bold-button/bold-button.svelte +60 -8
  63. package/dist/components/presentation-editor/layers/types/html/buttons/bold-button/bold-button.svelte.d.ts +3 -3
  64. package/dist/components/presentation-editor/layers/types/html/buttons/case-button/case-button.svelte +59 -24
  65. package/dist/components/presentation-editor/layers/types/html/buttons/case-button/case-button.svelte.d.ts +3 -3
  66. package/dist/components/presentation-editor/layers/types/html/buttons/color-button/color-button.svelte +27 -76
  67. package/dist/components/presentation-editor/layers/types/html/buttons/color-button/color-button.svelte.d.ts +3 -3
  68. package/dist/components/presentation-editor/layers/types/html/buttons/font-family-button/font-family-button.svelte +36 -0
  69. package/dist/components/presentation-editor/layers/types/html/buttons/font-family-button/font-family-button.svelte.d.ts +7 -0
  70. package/dist/components/presentation-editor/layers/types/html/buttons/font-family-button/index.d.ts +2 -0
  71. package/dist/components/presentation-editor/layers/types/html/buttons/font-family-button/index.js +2 -0
  72. package/dist/components/presentation-editor/layers/types/html/buttons/font-size-button/font-size-button.svelte +72 -29
  73. package/dist/components/presentation-editor/layers/types/html/buttons/font-size-button/font-size-button.svelte.d.ts +3 -5
  74. package/dist/components/presentation-editor/layers/types/html/buttons/italic-button/italic-button.svelte +60 -8
  75. package/dist/components/presentation-editor/layers/types/html/buttons/italic-button/italic-button.svelte.d.ts +3 -3
  76. package/dist/components/presentation-editor/layers/types/html/buttons/list-button/list-button.svelte +71 -18
  77. package/dist/components/presentation-editor/layers/types/html/buttons/list-button/list-button.svelte.d.ts +3 -3
  78. package/dist/components/presentation-editor/layers/types/html/buttons/strikethrough-button/strikethrough-button.svelte +54 -8
  79. package/dist/components/presentation-editor/layers/types/html/buttons/strikethrough-button/strikethrough-button.svelte.d.ts +3 -3
  80. package/dist/components/presentation-editor/layers/types/html/buttons/underline-button/underline-button.svelte +54 -9
  81. package/dist/components/presentation-editor/layers/types/html/buttons/underline-button/underline-button.svelte.d.ts +3 -3
  82. package/dist/components/presentation-editor/layers/types/html/editor/createEditor.js +2 -2
  83. package/dist/components/presentation-editor/layers/types/html/editor/utils.d.ts +11 -0
  84. package/dist/components/presentation-editor/layers/types/html/editor/utils.js +88 -0
  85. package/dist/components/presentation-editor/layers/types/html/extensions/font-family/font-family.d.ts +27 -0
  86. package/dist/components/presentation-editor/layers/types/html/extensions/font-family/font-family.js +40 -0
  87. package/dist/components/presentation-editor/layers/types/html/extensions/font-family/index.d.ts +3 -0
  88. package/dist/components/presentation-editor/layers/types/html/extensions/font-family/index.js +3 -0
  89. package/dist/components/presentation-editor/layers/types/html/extensions/font-size/font-size.d.ts +5 -1
  90. package/dist/components/presentation-editor/layers/types/html/extensions/font-size/font-size.js +3 -7
  91. package/dist/components/presentation-editor/layers/types/html/extensions.d.ts +1 -0
  92. package/dist/components/presentation-editor/layers/types/html/extensions.js +56 -0
  93. package/dist/components/presentation-editor/layers/types/html/html-content.svelte +26 -5
  94. package/dist/components/presentation-editor/layers/types/html/html-layer-content.svelte +26 -0
  95. package/dist/components/presentation-editor/layers/types/html/html-layer-content.svelte.d.ts +9 -0
  96. package/dist/components/presentation-editor/layers/types/html/html-layer-edit.svelte +103 -0
  97. package/dist/components/presentation-editor/layers/types/html/html-layer-edit.svelte.d.ts +8 -0
  98. package/dist/components/presentation-editor/layers/types/html/html-layer.svelte +61 -53
  99. package/dist/components/presentation-editor/layers/types/html/index.d.ts +3 -5
  100. package/dist/components/presentation-editor/layers/types/html/index.js +3 -56
  101. package/dist/components/presentation-editor/layers/types/image/{image-content.svelte → image-layer-content.svelte} +11 -3
  102. package/dist/components/presentation-editor/layers/types/image/image-layer-content.svelte.d.ts +8 -0
  103. package/dist/components/presentation-editor/layers/types/image/image-layer.svelte +51 -21
  104. package/dist/components/presentation-editor/layers/types/image/index.d.ts +2 -4
  105. package/dist/components/presentation-editor/layers/types/image/index.js +2 -4
  106. package/dist/components/presentation-editor/layers/utils.d.ts +68 -9
  107. package/dist/components/presentation-editor/layers/utils.js +260 -25
  108. package/dist/components/presentation-editor/menu/background-menu-content.svelte +80 -0
  109. package/dist/components/presentation-editor/menu/background-menu-content.svelte.d.ts +9 -0
  110. package/dist/components/presentation-editor/menu/layer-menu-content.svelte +183 -0
  111. package/dist/components/presentation-editor/menu/layer-menu-content.svelte.d.ts +3 -0
  112. package/dist/components/presentation-editor/menu/slide-menu-content.svelte +67 -0
  113. package/dist/components/presentation-editor/menu/slide-menu-content.svelte.d.ts +9 -0
  114. package/dist/components/presentation-editor/presentation-editor.svelte +120 -176
  115. package/dist/components/presentation-editor/presentation-editor.svelte.d.ts +1 -4
  116. package/dist/components/presentation-editor/presentation-editor.svelte.js +597 -136
  117. package/dist/components/presentation-editor/sidebar/color-sidebar/color-sidebar-color.svelte +58 -0
  118. package/dist/components/presentation-editor/sidebar/color-sidebar/color-sidebar-color.svelte.d.ts +10 -0
  119. package/dist/components/presentation-editor/sidebar/color-sidebar/color-sidebar-gradient-picker.svelte +144 -0
  120. package/dist/components/presentation-editor/sidebar/color-sidebar/color-sidebar-gradient-picker.svelte.d.ts +7 -0
  121. package/dist/components/presentation-editor/sidebar/color-sidebar/color-sidebar.svelte +404 -0
  122. package/dist/components/presentation-editor/sidebar/color-sidebar/color-sidebar.svelte.d.ts +3 -0
  123. package/dist/components/presentation-editor/sidebar/color-sidebar/index.d.ts +2 -0
  124. package/dist/components/presentation-editor/sidebar/color-sidebar/index.js +2 -0
  125. package/dist/components/presentation-editor/sidebar/font-sidebar/font-sidebar-button.svelte +26 -0
  126. package/dist/components/presentation-editor/sidebar/font-sidebar/font-sidebar-button.svelte.d.ts +8 -0
  127. package/dist/components/presentation-editor/sidebar/font-sidebar/font-sidebar.svelte +216 -0
  128. package/dist/components/presentation-editor/sidebar/font-sidebar/font-sidebar.svelte.d.ts +3 -0
  129. package/dist/components/presentation-editor/sidebar/font-sidebar/index.d.ts +2 -0
  130. package/dist/components/presentation-editor/sidebar/font-sidebar/index.js +2 -0
  131. package/dist/components/presentation-editor/sidebar/position-slidebar.svelte +130 -0
  132. package/dist/components/presentation-editor/sidebar/position-slidebar.svelte.d.ts +18 -0
  133. package/dist/components/presentation-editor/sidebar/sidebar-text-tab-button.svelte +90 -0
  134. package/dist/components/presentation-editor/sidebar/sidebar-text-tab-button.svelte.d.ts +7 -0
  135. package/dist/components/presentation-editor/sidebar/sidebar-text-tab.svelte +82 -0
  136. package/dist/components/presentation-editor/sidebar/sidebar-text-tab.svelte.d.ts +18 -0
  137. package/dist/components/presentation-editor/sidebar/{images-library.svelte → sidebar-uploads-tab.svelte} +0 -1
  138. package/dist/components/presentation-editor/sidebar/sidebar-uploads-tab.svelte.d.ts +3 -0
  139. package/dist/components/presentation-editor/sidebar/sidebar-wrapper.svelte +25 -0
  140. package/dist/components/presentation-editor/sidebar/sidebar-wrapper.svelte.d.ts +7 -0
  141. package/dist/components/presentation-editor/sidebar/sidebar.svelte +71 -15
  142. package/dist/components/presentation-editor/sidebar/sidebar.svelte.d.ts +16 -5
  143. package/dist/components/presentation-editor/sidebar/uploads-image.svelte +28 -11
  144. package/dist/components/presentation-editor/slide-editor.svelte +20 -22
  145. package/dist/components/presentation-editor/slide-inner.svelte +19 -18
  146. package/dist/components/presentation-editor/slides-navigation/slide-preview.svelte +61 -52
  147. package/dist/components/presentation-editor/slides-navigation/slides-navigation.svelte +6 -8
  148. package/dist/components/presentation-editor/snapping-guides.svelte +3 -3
  149. package/dist/components/presentation-editor/types.d.ts +67 -27
  150. package/dist/components/presentation-editor/utils.d.ts +50 -1
  151. package/dist/components/presentation-editor/utils.js +101 -6
  152. package/dist/components/ui/button/button.svelte +3 -2
  153. package/dist/components/ui/button/button.svelte.d.ts +5 -82
  154. package/dist/components/ui/color-picker/color-picker-alpha-grid.svelte +43 -0
  155. package/dist/components/ui/color-picker/color-picker-alpha-grid.svelte.d.ts +8 -0
  156. package/dist/components/ui/color-picker/color-picker.svelte +344 -0
  157. package/dist/components/ui/color-picker/color-picker.svelte.d.ts +13 -0
  158. package/dist/components/ui/color-picker/index.d.ts +3 -0
  159. package/dist/components/ui/color-picker/index.js +5 -0
  160. package/dist/components/ui/context-menu/context-menu-shortcut.svelte +6 -3
  161. package/dist/components/ui/context-menu/context-menu-sub-trigger.svelte +1 -1
  162. package/dist/components/ui/dropdown-menu/dropdown-menu-item.svelte +1 -1
  163. package/dist/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte +6 -3
  164. package/dist/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +1 -1
  165. package/dist/components/ui/infinite-loader/index.d.ts +4 -0
  166. package/dist/components/ui/infinite-loader/index.js +4 -0
  167. package/dist/components/ui/infinite-loader/infinite-loader-loop-tracker.d.ts +13 -0
  168. package/dist/components/ui/infinite-loader/infinite-loader-loop-tracker.js +44 -0
  169. package/dist/components/ui/infinite-loader/infinite-loader-state.svelte.d.ts +15 -0
  170. package/dist/components/ui/infinite-loader/infinite-loader-state.svelte.js +28 -0
  171. package/dist/components/ui/infinite-loader/infinite-loader.svelte +149 -0
  172. package/dist/components/ui/infinite-loader/infinite-loader.svelte.d.ts +17 -0
  173. package/dist/components/ui/input/input.svelte +1 -1
  174. package/dist/components/ui/slider/slider.svelte +20 -18
  175. package/dist/components/ui/tabs/index.d.ts +6 -0
  176. package/dist/components/ui/tabs/index.js +8 -0
  177. package/dist/components/ui/tabs/tabs-content.svelte +19 -0
  178. package/dist/components/ui/tabs/tabs-content.svelte.d.ts +4 -0
  179. package/dist/components/ui/tabs/tabs-list.svelte +19 -0
  180. package/dist/components/ui/tabs/tabs-list.svelte.d.ts +4 -0
  181. package/dist/components/ui/tabs/tabs-trigger.svelte +19 -0
  182. package/dist/components/ui/tabs/tabs-trigger.svelte.d.ts +4 -0
  183. package/dist/components/ui/toggle/toggle.svelte +3 -2
  184. package/dist/components/ui/toggle/toggle.svelte.d.ts +2 -46
  185. package/dist/index.d.ts +5 -6
  186. package/dist/index.js +1 -4
  187. package/dist/plugin.js +3 -2
  188. package/dist/utils.d.ts +1 -0
  189. package/dist/utils.js +1 -0
  190. package/package.json +28 -25
  191. package/dist/components/presentation-editor/app.css +0 -12
  192. package/dist/components/presentation-editor/layers/hovered-layer.svelte +0 -34
  193. package/dist/components/presentation-editor/layers/hovered-layer.svelte.d.ts +0 -7
  194. package/dist/components/presentation-editor/layers/types/background/background-content.svelte +0 -11
  195. package/dist/components/presentation-editor/layers/types/background/background-content.svelte.d.ts +0 -7
  196. package/dist/components/presentation-editor/layers/types/background/background-layer-thumb.svelte +0 -12
  197. package/dist/components/presentation-editor/layers/types/background/background-layer-thumb.svelte.d.ts +0 -7
  198. package/dist/components/presentation-editor/layers/types/html/html-layer-active.svelte +0 -159
  199. package/dist/components/presentation-editor/layers/types/html/html-layer-active.svelte.d.ts +0 -8
  200. package/dist/components/presentation-editor/layers/types/html/html-layer-buttons.svelte +0 -42
  201. package/dist/components/presentation-editor/layers/types/html/html-layer-buttons.svelte.d.ts +0 -10
  202. package/dist/components/presentation-editor/layers/types/html/html-layer-thumb.svelte +0 -24
  203. package/dist/components/presentation-editor/layers/types/html/html-layer-thumb.svelte.d.ts +0 -8
  204. package/dist/components/presentation-editor/layers/types/image/image-content.svelte.d.ts +0 -8
  205. package/dist/components/presentation-editor/layers/types/image/image-layer-buttons.svelte +0 -21
  206. package/dist/components/presentation-editor/layers/types/image/image-layer-buttons.svelte.d.ts +0 -7
  207. package/dist/components/presentation-editor/layers/types/image/image-layer-thumb.svelte +0 -13
  208. package/dist/components/presentation-editor/layers/types/image/image-layer-thumb.svelte.d.ts +0 -8
  209. package/dist/components/presentation-editor/sidebar/images-library.svelte.d.ts +0 -3
  210. package/dist/components/presentation-editor/sidebar/layers.svelte +0 -94
  211. package/dist/components/presentation-editor/slides-navigation/buttons/slide-delete-button.svelte +0 -32
  212. package/dist/components/presentation-editor/slides-navigation/buttons/slide-delete-button.svelte.d.ts +0 -10
  213. package/dist/components/presentation-editor/slides-navigation/buttons/slide-duplicate-button.svelte +0 -34
  214. package/dist/components/presentation-editor/slides-navigation/buttons/slide-duplicate-button.svelte.d.ts +0 -10
@@ -1,4 +1,5 @@
1
- const rotatePoint = (point, angleRad) => {
1
+ import { tick } from 'svelte';
2
+ export const rotatePointOld = (point, angleRad) => {
2
3
  const cos = Math.cos(angleRad);
3
4
  const sin = Math.sin(angleRad);
4
5
  return {
@@ -32,17 +33,22 @@ const getPoints = (origin, width, height) => {
32
33
  throw new Error(`Unknown origin: ${origin}`);
33
34
  }
34
35
  };
35
- export const calculateNewPosition = (origin, element, newWidth, newHeight) => {
36
- const { x, y, width, height } = element;
37
- const rotate = element.rotate || 0;
36
+ export const calculateLayerTransform = (layer) => {
37
+ const { x, y, width, height } = layer;
38
+ const scale = layer.scale || 1;
39
+ const rotate = layer.rotate || 0;
40
+ return { x, y, width: width * scale, height: height * scale, rotate };
41
+ };
42
+ export const calculateNewPosition = (origin, transform, newWidth, newHeight) => {
43
+ const { x, y, width, height, rotate } = transform;
38
44
  const oldPoint = getPoints(origin, width, height);
39
45
  const newPoint = getPoints(origin, newWidth, newHeight);
40
46
  let deltaX = newPoint.x - oldPoint.x;
41
47
  let deltaY = newPoint.y - oldPoint.y;
42
48
  if (rotate !== 0) {
43
49
  const rad = (rotate * Math.PI) / 180;
44
- const rotatedOldCenter = rotatePoint(oldPoint, rad);
45
- const rotatedNewCenter = rotatePoint(newPoint, rad);
50
+ const rotatedOldCenter = rotatePointOld(oldPoint, rad);
51
+ const rotatedNewCenter = rotatePointOld(newPoint, rad);
46
52
  deltaX = rotatedNewCenter.x - rotatedOldCenter.x;
47
53
  deltaY = rotatedNewCenter.y - rotatedOldCenter.y;
48
54
  }
@@ -51,15 +57,14 @@ export const calculateNewPosition = (origin, element, newWidth, newHeight) => {
51
57
  newY: y - deltaY - (newHeight - height) / 2,
52
58
  };
53
59
  };
54
- export function calculateBoundingBox(element) {
55
- const { x, y, width, height } = element;
56
- const rotate = element.rotate || 0;
60
+ export function calculateBoundingBox(transform) {
61
+ const { x, y, width, height, rotate } = transform;
57
62
  if (rotate === 0) {
58
63
  return { x, y, width, height };
59
64
  }
60
65
  const radians = (rotate * Math.PI) / 180;
61
66
  const origins = ['top-left', 'top-right'];
62
- const corners = origins.map((position) => rotatePoint(getPoints(position, width, height), radians));
67
+ const corners = origins.map((position) => rotatePointOld(getPoints(position, width, height), radians));
63
68
  const maxX = Math.max(...corners.map((corner) => Math.abs(corner.x)));
64
69
  const maxY = Math.max(...corners.map((corner) => Math.abs(corner.y)));
65
70
  return {
@@ -69,24 +74,254 @@ export function calculateBoundingBox(element) {
69
74
  height: maxY * 2,
70
75
  };
71
76
  }
72
- export function calculateImageFill(image, bBox) {
73
- const widthScale = bBox.width / image.width;
74
- const heightScale = bBox.height / image.height;
75
- const scale = Math.max(widthScale, heightScale);
76
- const width = bBox.width / scale;
77
- const height = bBox.height / scale;
77
+ export function degToRad(deg) {
78
+ return (deg * Math.PI) / 180;
79
+ }
80
+ export function rotatePoint(p, origin, angleRad) {
81
+ const dx = p.x - origin.x;
82
+ const dy = p.y - origin.y;
83
+ const cos = Math.cos(angleRad);
84
+ const sin = Math.sin(angleRad);
85
+ return {
86
+ x: origin.x + dx * cos - dy * sin,
87
+ y: origin.y + dx * sin + dy * cos,
88
+ };
89
+ }
90
+ export function getRotatedCorners(rect) {
91
+ const cx = rect.x + rect.width / 2;
92
+ const cy = rect.y + rect.height / 2;
93
+ const angle = degToRad(rect.rotate);
94
+ const hw = rect.width / 2;
95
+ const hh = rect.height / 2;
96
+ const corners = [
97
+ { x: cx - hw, y: cy - hh },
98
+ { x: cx + hw, y: cy - hh },
99
+ { x: cx + hw, y: cy + hh },
100
+ { x: cx - hw, y: cy + hh },
101
+ ];
102
+ return corners.map((p) => rotatePoint(p, { x: cx, y: cy }, angle));
103
+ }
104
+ export function calculateBoundingBoxSize(width, height, rotate) {
105
+ const theta = degToRad(rotate);
106
+ const cosTheta = Math.abs(Math.cos(theta));
107
+ const sinTheta = Math.abs(Math.sin(theta));
108
+ return {
109
+ width: width * cosTheta + height * sinTheta,
110
+ height: width * sinTheta + height * cosTheta,
111
+ };
112
+ }
113
+ export function isRotatedVertically(rotate) {
114
+ const rotationNormalized = ((rotate % 360) + 360) % 360;
115
+ const rotationShifted = (rotationNormalized + 45) % 360;
116
+ return Math.floor(rotationShifted / 90) % 2 === 1;
117
+ }
118
+ export function calculateNewSize(width, height, rotate, scale, isHorizontal) {
119
+ const angle = degToRad(rotate);
120
+ const cosTheta = Math.abs(Math.cos(angle));
121
+ const sinTheta = Math.abs(Math.sin(angle));
122
+ // Bounding box dimensions
123
+ const bboxWidth = width * cosTheta + height * sinTheta;
124
+ const bboxHeight = width * sinTheta + height * cosTheta;
125
+ // Determine if sides are flipped by rotation
126
+ const rotatedVertically = isRotatedVertically(rotate);
127
+ const bboxSize = (isHorizontal ? bboxWidth : bboxHeight) * scale;
128
+ const scalingRectangleSide = isHorizontal !== rotatedVertically ? 'width' : 'height';
129
+ const scalingWidth = scalingRectangleSide === 'width';
130
+ const dimensionFactor = !rotatedVertically ? cosTheta : sinTheta;
131
+ const crossFactor = rotatedVertically ? cosTheta : sinTheta;
132
+ const newMainSize = (bboxSize - (scalingWidth ? height : width) * crossFactor) / dimensionFactor;
133
+ const newWidth = scalingWidth ? newMainSize : width;
134
+ const newHeight = !scalingWidth ? newMainSize : height;
135
+ return { width: newWidth, height: newHeight, scaled: scalingRectangleSide };
136
+ }
137
+ export function getRotatedBoundingBox(center, width, height, rotate) {
138
+ const angle = degToRad(rotate);
139
+ // Half dimensions
140
+ const hw = width / 2;
141
+ const hh = height / 2;
142
+ // Rotation matrix components
143
+ const cos = Math.cos(angle);
144
+ const sin = Math.sin(angle);
145
+ // Corners of the unrotated rectangle relative to center
146
+ const corners = [
147
+ { x: -hw, y: -hh },
148
+ { x: hw, y: -hh },
149
+ { x: hw, y: hh },
150
+ { x: -hw, y: hh },
151
+ ];
152
+ // Rotate corners and translate back to original position
153
+ const rotatedCorners = corners.map(({ x, y }) => {
154
+ return {
155
+ x: center.x + x * cos - y * sin,
156
+ y: center.y + x * sin + y * cos,
157
+ };
158
+ });
159
+ // Find min/max bounds
160
+ const xs = rotatedCorners.map((p) => p.x);
161
+ const ys = rotatedCorners.map((p) => p.y);
162
+ const minX = Math.min(...xs);
163
+ const maxX = Math.max(...xs);
164
+ const minY = Math.min(...ys);
165
+ const maxY = Math.max(...ys);
78
166
  return {
167
+ x: minX,
168
+ y: minY,
169
+ width: maxX - minX,
170
+ height: maxY - minY,
171
+ };
172
+ }
173
+ export function calculateGroupRotatedBoundingBox(rects, groupRotate = 0) {
174
+ if (!groupRotate)
175
+ return { ...calculateGroupBoundingBox(rects), rotate: 0 };
176
+ const allCorners = rects.flatMap(getRotatedCorners);
177
+ const theta = degToRad(-groupRotate); // inverse to align bbox with axes
178
+ // Rotate all points to align with desired bbox angle
179
+ const rotatedPoints = allCorners.map((p) => rotatePoint(p, { x: 0, y: 0 }, theta));
180
+ // Compute AABB of rotated points
181
+ const xs = rotatedPoints.map((p) => p.x);
182
+ const ys = rotatedPoints.map((p) => p.y);
183
+ const minX = Math.min(...xs);
184
+ const maxX = Math.max(...xs);
185
+ const minY = Math.min(...ys);
186
+ const maxY = Math.max(...ys);
187
+ const width = maxX - minX;
188
+ const height = maxY - minY;
189
+ const centerRotated = {
190
+ x: (minX + maxX) / 2,
191
+ y: (minY + maxY) / 2,
192
+ };
193
+ // Rotate center back to original space
194
+ const center = rotatePoint(centerRotated, { x: 0, y: 0 }, degToRad(groupRotate));
195
+ const bbox = {
196
+ x: center.x - width / 2,
197
+ y: center.y - height / 2,
79
198
  width,
80
199
  height,
81
- scale,
82
- ...(widthScale > heightScale
83
- ? {
84
- offsetX: 0,
85
- offsetY: (image.height - bBox.height / scale) / 2,
200
+ rotate: groupRotate,
201
+ };
202
+ return bbox;
203
+ }
204
+ export function calculateRelativeRects(bbox, rects) {
205
+ const theta = degToRad(-bbox.rotate); // inverse to align bbox with axes
206
+ const bboxCenter = { x: bbox.x + bbox.width / 2, y: bbox.y + bbox.height / 2 };
207
+ return rects.map((rect) => {
208
+ // Get center of original rect
209
+ const center = {
210
+ x: rect.x + rect.width / 2,
211
+ y: rect.y + rect.height / 2,
212
+ };
213
+ // Rotate center ralatively to the bbox center
214
+ const relativeCenter = rotatePoint(center, bboxCenter, theta);
215
+ return {
216
+ x: relativeCenter.x - rect.width / 2 - bbox.x,
217
+ y: relativeCenter.y - rect.height / 2 - bbox.y,
218
+ width: rect.width,
219
+ height: rect.height,
220
+ rotate: rect.rotate - bbox.rotate,
221
+ };
222
+ });
223
+ }
224
+ export const checkPolygonsIntersect = (a, b) => {
225
+ const polygons = [a, b];
226
+ for (const polygon of polygons) {
227
+ for (let i1 = 0; i1 < polygon.length; i1++) {
228
+ const i2 = (i1 + 1) % polygon.length;
229
+ const p1 = polygon[i1];
230
+ const p2 = polygon[i2];
231
+ const normal = { x: p2.y - p1.y, y: p1.x - p2.x };
232
+ let minA = Infinity, maxA = -Infinity;
233
+ for (const point of a) {
234
+ const projected = normal.x * point.x + normal.y * point.y;
235
+ minA = Math.min(minA, projected);
236
+ maxA = Math.max(maxA, projected);
86
237
  }
87
- : {
88
- offsetX: (image.width - bBox.width / scale) / 2,
89
- offsetY: 0,
90
- }),
238
+ let minB = Infinity, maxB = -Infinity;
239
+ for (const point of b) {
240
+ const projected = normal.x * point.x + normal.y * point.y;
241
+ minB = Math.min(minB, projected);
242
+ maxB = Math.max(maxB, projected);
243
+ }
244
+ if (maxA < minB || maxB < minA)
245
+ return false;
246
+ }
247
+ }
248
+ return true;
249
+ };
250
+ export function calculateGroupBoundingBox(transforms) {
251
+ let minX = Number.MAX_VALUE;
252
+ let maxX = Number.MIN_VALUE;
253
+ let minY = Number.MAX_VALUE;
254
+ let maxY = Number.MIN_VALUE;
255
+ transforms.forEach((transform) => {
256
+ const bbox = calculateBoundingBox(transform);
257
+ minX = Math.min(minX, bbox.x);
258
+ maxX = Math.max(maxX, bbox.x + bbox.width);
259
+ minY = Math.min(minY, bbox.y);
260
+ maxY = Math.max(maxY, bbox.y + bbox.height);
261
+ });
262
+ return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
263
+ }
264
+ const minScaleToContain = (rotatedRect, rect) => {
265
+ const { width: rw, height: rh, rotate } = rotatedRect;
266
+ const { width: w, height: h } = rect;
267
+ // Convert angle to radians
268
+ const angleRad = (rotate || 0) * (Math.PI / 180);
269
+ // Calculate the width and height of the bounding box of the rotated rectangle
270
+ const boundingWidth = Math.abs(w * Math.cos(angleRad)) + Math.abs(h * Math.sin(angleRad));
271
+ const boundingHeight = Math.abs(w * Math.sin(angleRad)) + Math.abs(h * Math.cos(angleRad));
272
+ // Calculate the scale factors needed to fit the rectangle into the bounding box
273
+ const scaleX = boundingWidth / rw;
274
+ const scaleY = boundingHeight / rh;
275
+ // The minimum scale factor is the maximum of the two scale factors
276
+ const minScale = Math.max(scaleX, scaleY);
277
+ return minScale;
278
+ };
279
+ export function calculateImageCover(image, bbox) {
280
+ const scale = minScaleToContain(image, bbox);
281
+ return {
282
+ width: bbox.width / scale,
283
+ height: bbox.height / scale,
284
+ scale,
285
+ offsetX: (image.width - bbox.width / scale) / 2,
286
+ offsetY: (image.height - bbox.height / scale) / 2,
91
287
  };
92
288
  }
289
+ export const defaultColor = '#000000';
290
+ export function extractBorderColors(layers) {
291
+ const layersWithBorder = layers.filter((layer) => layer.borderWidth);
292
+ if (!layersWithBorder.length)
293
+ return;
294
+ const set = new Set();
295
+ layersWithBorder.forEach((layer) => {
296
+ set.add(layer.borderColor || defaultColor);
297
+ });
298
+ return Array.from(set);
299
+ }
300
+ export function buildBackgroundCircleStyle(colors) {
301
+ if (colors.length < 2) {
302
+ return `background-color: ${colors[0] || defaultColor}`;
303
+ }
304
+ const step = 360 / colors.length;
305
+ const gradientColors = colors
306
+ .map((c, i) => `${c} ${Math.round(i * step)}deg ${Math.round((i + 1) * step)}deg`)
307
+ .join(', ');
308
+ return `background-image: conic-gradient(${gradientColors})`;
309
+ }
310
+ export async function applyHtmlToLayer(layer, html) {
311
+ layer.html = html;
312
+ await tick();
313
+ const { x, y, width, height } = layer;
314
+ const redo = { html, x, y, height };
315
+ const layerContent = document.getElementById(`layer-content-${layer.id}`);
316
+ if (layerContent && layerContent.offsetHeight !== layer.height) {
317
+ const scale = layer.scale || 1;
318
+ const rotate = layer.rotate || 0;
319
+ const newHeight = layerContent.offsetHeight * scale;
320
+ const { newX, newY } = calculateNewPosition(`top-left`, { x, y, width: width * scale, height: height * scale, rotate }, width * scale, newHeight);
321
+ redo.x = newX;
322
+ redo.y = newY;
323
+ redo.height = newHeight / scale;
324
+ }
325
+ Object.assign(layer, redo);
326
+ return redo;
327
+ }
@@ -0,0 +1,80 @@
1
+ <script lang="ts">
2
+ import CopyIcon from 'lucide-svelte/icons/copy';
3
+ import PasteIcon from 'lucide-svelte/icons/clipboard';
4
+ import DuplicateIcon from 'lucide-svelte/icons/copy-plus';
5
+ import AddIcon from 'lucide-svelte/icons/file-plus-2';
6
+ import TrashIcon from 'lucide-svelte/icons/trash-2';
7
+ import LockIcon from 'lucide-svelte/icons/lock-keyhole';
8
+ import UnlockIcon from 'lucide-svelte/icons/lock-keyhole-open';
9
+ import ExtractImageIcon from 'lucide-svelte/icons/square-arrow-out-up-right';
10
+ import * as DropdownMenu from '../../ui/dropdown-menu/index.js';
11
+ import type { PresentationEditor } from '../presentation-editor.svelte.js';
12
+ import type { Slide } from '../types.js';
13
+ import { checkIfMac } from '../../../utils.js';
14
+
15
+ interface Props {
16
+ editor: PresentationEditor;
17
+ slide: Slide;
18
+ }
19
+
20
+ let { editor, slide }: Props = $props();
21
+
22
+ const locked = $derived(slide.locked || slide.backgroundLocked);
23
+
24
+ const isMac = checkIfMac();
25
+ </script>
26
+
27
+ <DropdownMenu.Item onclick={() => editor.copySlide(slide.id)}>
28
+ <CopyIcon />
29
+ Copy
30
+ <DropdownMenu.Shortcut>{isMac ? '⌘C' : 'Ctrl+C'}</DropdownMenu.Shortcut>
31
+ </DropdownMenu.Item>
32
+ <DropdownMenu.Item
33
+ onclick={() => editor.clipboardPaste()}
34
+ disabled={!editor.clipboard || (slide.locked && !('layers' in editor.clipboard))}
35
+ >
36
+ <PasteIcon />
37
+ Paste
38
+ <DropdownMenu.Shortcut>{isMac ? '⌘V' : 'Ctrl+V'}</DropdownMenu.Shortcut>
39
+ </DropdownMenu.Item>
40
+ <DropdownMenu.Item onclick={() => editor.addSlide()}>
41
+ <AddIcon />
42
+ Add page
43
+ <DropdownMenu.Shortcut>{isMac ? '⌘⏎' : 'Ctrl+⏎'}</DropdownMenu.Shortcut>
44
+ </DropdownMenu.Item>
45
+ <DropdownMenu.Item onclick={() => editor.duplicateSlide(slide)}>
46
+ <DuplicateIcon />
47
+ Duplicate page
48
+ <DropdownMenu.Shortcut>{isMac ? '⌘D' : 'Ctrl+D'}</DropdownMenu.Shortcut>
49
+ </DropdownMenu.Item>
50
+ <DropdownMenu.Item onclick={() => editor.removeBackground(slide.id)} disabled={locked}>
51
+ <TrashIcon />
52
+ {#if slide.backgroundImage}
53
+ Delete background image
54
+ {:else}
55
+ Delete background
56
+ {/if}
57
+ <DropdownMenu.Shortcut>DELETE</DropdownMenu.Shortcut>
58
+ </DropdownMenu.Item>
59
+
60
+ <DropdownMenu.Separator />
61
+
62
+ <DropdownMenu.Item onclick={() => editor.backgroundToggleLocked(slide.id)} disabled={slide.locked}>
63
+ {#if slide.backgroundLocked}
64
+ <UnlockIcon />
65
+ Unlock background
66
+ {:else}
67
+ <LockIcon />
68
+ Lock background
69
+ {/if}
70
+ <DropdownMenu.Shortcut>{isMac ? '⌥⇧L' : 'Alt+Shift+L'}</DropdownMenu.Shortcut>
71
+ </DropdownMenu.Item>
72
+
73
+ {#if slide.backgroundImage}
74
+ <DropdownMenu.Separator />
75
+
76
+ <DropdownMenu.Item onclick={() => editor.backgroundImageToLayer(slide.id)} disabled={locked}>
77
+ <ExtractImageIcon />
78
+ Detach image from background
79
+ </DropdownMenu.Item>
80
+ {/if}
@@ -0,0 +1,9 @@
1
+ import type { PresentationEditor } from '../presentation-editor.svelte.js';
2
+ import type { Slide } from '../types.js';
3
+ interface Props {
4
+ editor: PresentationEditor;
5
+ slide: Slide;
6
+ }
7
+ declare const BackgroundMenuContent: import("svelte").Component<Props, {}, "">;
8
+ type BackgroundMenuContent = ReturnType<typeof BackgroundMenuContent>;
9
+ export default BackgroundMenuContent;
@@ -0,0 +1,183 @@
1
+ <script lang="ts">
2
+ import CopyIcon from 'lucide-svelte/icons/copy';
3
+ import PasteIcon from 'lucide-svelte/icons/clipboard';
4
+ import DuplicateIcon from 'lucide-svelte/icons/copy-plus';
5
+ import TrashIcon from 'lucide-svelte/icons/trash-2';
6
+ import LayerIcon from 'lucide-svelte/icons/layers';
7
+ import LayerBringForwardIcon from 'lucide-svelte/icons/arrow-up';
8
+ import LayerBringToFrontIcon from 'lucide-svelte/icons/arrow-up-to-line';
9
+ import LayerSendBackwardIcon from 'lucide-svelte/icons/arrow-down';
10
+ import LayerSendToBackIcon from 'lucide-svelte/icons/arrow-down-to-line';
11
+ import AlignLeftIcon from 'lucide-svelte/icons/align-start-vertical';
12
+ import AlignCenterIcon from 'lucide-svelte/icons/align-center-vertical';
13
+ import AlignRightIcon from 'lucide-svelte/icons/align-end-vertical';
14
+ import AlignTopIcon from 'lucide-svelte/icons/align-start-horizontal';
15
+ import AlignMiddleIcon from 'lucide-svelte/icons/align-center-horizontal';
16
+ import AlignBottomIcon from 'lucide-svelte/icons/align-end-horizontal';
17
+ import LockIcon from 'lucide-svelte/icons/lock-keyhole';
18
+ import UnlockIcon from 'lucide-svelte/icons/lock-keyhole-open';
19
+ import SetAsBackgroundIcon from 'lucide-svelte/icons/image-upscale';
20
+ import * as DropdownMenu from '../../ui/dropdown-menu/index.js';
21
+ import { getPresentationEditorContext } from '../presentation-editor.svelte.js';
22
+ import { checkIfMac } from '../../../utils.js';
23
+
24
+ const editor = getPresentationEditorContext();
25
+
26
+ const someLayersLocked = $derived(editor.activeLayers.some((layer) => layer.locked));
27
+ const locked = $derived(editor.activeSlide.locked || someLayersLocked);
28
+
29
+ const isMac = checkIfMac();
30
+
31
+ const activeLayerIds = $derived(editor.activeLayers.map((l) => l.id));
32
+
33
+ const singleImageLayer = $derived(
34
+ editor.activeLayers.length === 1 && editor.activeLayers[0].type === 'image'
35
+ ? editor.activeLayers[0]
36
+ : null,
37
+ );
38
+
39
+ let overlaps = editor.getLayerOverlaps(editor.activeSlide, editor.activeLayers);
40
+ </script>
41
+
42
+ <DropdownMenu.Item onclick={() => editor.copyLayers(editor.activeSlide.id, activeLayerIds)}>
43
+ <CopyIcon />
44
+ Copy
45
+ <DropdownMenu.Shortcut>{isMac ? '⌘C' : 'Ctrl+C'}</DropdownMenu.Shortcut>
46
+ </DropdownMenu.Item>
47
+ <DropdownMenu.Item onclick={() => editor.clipboardPaste()} disabled={!editor.clipboard}>
48
+ <PasteIcon />
49
+ Paste
50
+ <DropdownMenu.Shortcut>{isMac ? '⌘V' : 'Ctrl+V'}</DropdownMenu.Shortcut>
51
+ </DropdownMenu.Item>
52
+ <DropdownMenu.Item onclick={() => editor.duplicateLayers(editor.activeLayers)}>
53
+ <DuplicateIcon />
54
+ Duplicate
55
+ <DropdownMenu.Shortcut>{isMac ? '⌘D' : 'Ctrl+D'}</DropdownMenu.Shortcut>
56
+ </DropdownMenu.Item>
57
+ <DropdownMenu.Item
58
+ onclick={() => editor.removeLayers(editor.activeSlide.id, activeLayerIds)}
59
+ disabled={locked}
60
+ >
61
+ <TrashIcon />
62
+ Delete
63
+ <DropdownMenu.Shortcut>DELETE</DropdownMenu.Shortcut>
64
+ </DropdownMenu.Item>
65
+
66
+ <DropdownMenu.Separator />
67
+
68
+ {#if overlaps}
69
+ <DropdownMenu.Sub>
70
+ <DropdownMenu.SubTrigger disabled={locked}>
71
+ <LayerIcon />
72
+ Layers
73
+ </DropdownMenu.SubTrigger>
74
+ <DropdownMenu.SubContent class="w-56" align="start">
75
+ <DropdownMenu.Item
76
+ disabled={overlaps.forward === undefined}
77
+ onclick={() => editor.moveLayers(editor.activeSlide.id, activeLayerIds, 'forward')}
78
+ >
79
+ <LayerBringForwardIcon />
80
+ Bring forward
81
+ <DropdownMenu.Shortcut>{isMac ? '⌘]' : 'Ctrl+]'}</DropdownMenu.Shortcut>
82
+ </DropdownMenu.Item>
83
+ <DropdownMenu.Item
84
+ disabled={overlaps.front === undefined}
85
+ onclick={() => editor.moveLayers(editor.activeSlide.id, activeLayerIds, 'front')}
86
+ >
87
+ <LayerBringToFrontIcon />
88
+ Bring to front
89
+ <DropdownMenu.Shortcut>{isMac ? '⌥⌘]' : 'Ctrl+]'}</DropdownMenu.Shortcut>
90
+ </DropdownMenu.Item>
91
+ <DropdownMenu.Item
92
+ disabled={overlaps.backward === undefined}
93
+ onclick={() => editor.moveLayers(editor.activeSlide.id, activeLayerIds, 'backward')}
94
+ >
95
+ <LayerSendBackwardIcon />
96
+ Send backward
97
+ <DropdownMenu.Shortcut>{isMac ? '⌘[' : 'Ctrl+['}</DropdownMenu.Shortcut>
98
+ </DropdownMenu.Item>
99
+ <DropdownMenu.Item
100
+ disabled={overlaps.back === undefined}
101
+ onclick={() => editor.moveLayers(editor.activeSlide.id, activeLayerIds, 'back')}
102
+ >
103
+ <LayerSendToBackIcon />
104
+ Send to back
105
+ <DropdownMenu.Shortcut>{isMac ? '⌥⌘[' : 'Ctrl+['}</DropdownMenu.Shortcut>
106
+ </DropdownMenu.Item>
107
+ </DropdownMenu.SubContent>
108
+ </DropdownMenu.Sub>
109
+ {/if}
110
+
111
+ <DropdownMenu.Sub>
112
+ <DropdownMenu.SubTrigger disabled={locked}>
113
+ <AlignLeftIcon />
114
+ Align to page
115
+ </DropdownMenu.SubTrigger>
116
+ <DropdownMenu.SubContent class="w-32" align="start">
117
+ <DropdownMenu.Item
118
+ onclick={() => editor.alignLayers(editor.activeSlide.id, activeLayerIds, 'left')}
119
+ >
120
+ <AlignLeftIcon />
121
+ Left
122
+ </DropdownMenu.Item>
123
+ <DropdownMenu.Item
124
+ onclick={() => editor.alignLayers(editor.activeSlide.id, activeLayerIds, 'center')}
125
+ >
126
+ <AlignCenterIcon />
127
+ Center
128
+ </DropdownMenu.Item>
129
+ <DropdownMenu.Item
130
+ onclick={() => editor.alignLayers(editor.activeSlide.id, activeLayerIds, 'right')}
131
+ >
132
+ <AlignRightIcon />
133
+ Right
134
+ </DropdownMenu.Item>
135
+ <DropdownMenu.Separator />
136
+ <DropdownMenu.Item
137
+ onclick={() => editor.alignLayers(editor.activeSlide.id, activeLayerIds, 'top')}
138
+ >
139
+ <AlignTopIcon />
140
+ Top
141
+ </DropdownMenu.Item>
142
+ <DropdownMenu.Item
143
+ onclick={() => editor.alignLayers(editor.activeSlide.id, activeLayerIds, 'middle')}
144
+ >
145
+ <AlignMiddleIcon />
146
+ Middle
147
+ </DropdownMenu.Item>
148
+ <DropdownMenu.Item
149
+ onclick={() => editor.alignLayers(editor.activeSlide.id, activeLayerIds, 'bottom')}
150
+ >
151
+ <AlignBottomIcon />
152
+ Bottom
153
+ </DropdownMenu.Item>
154
+ </DropdownMenu.SubContent>
155
+ </DropdownMenu.Sub>
156
+
157
+ <DropdownMenu.Separator />
158
+
159
+ <DropdownMenu.Item
160
+ onclick={() =>
161
+ editor.toggleLayersLocked(editor.activeSlide.id, activeLayerIds, !someLayersLocked)}
162
+ disabled={editor.activeSlide.locked}
163
+ >
164
+ {#if someLayersLocked}
165
+ <UnlockIcon />
166
+ Unlock
167
+ {:else}
168
+ <LockIcon />
169
+ Lock
170
+ {/if}
171
+ <DropdownMenu.Shortcut>{isMac ? '⌥⇧L' : 'Alt+Shift+L'}</DropdownMenu.Shortcut>
172
+ </DropdownMenu.Item>
173
+
174
+ {#if singleImageLayer}
175
+ <DropdownMenu.Separator />
176
+ <DropdownMenu.Item
177
+ onclick={() => editor.imageLayerToBackground(editor.activeSlide.id, singleImageLayer.id)}
178
+ disabled={locked}
179
+ >
180
+ <SetAsBackgroundIcon />
181
+ Set image as background
182
+ </DropdownMenu.Item>
183
+ {/if}
@@ -0,0 +1,3 @@
1
+ declare const LayerMenuContent: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type LayerMenuContent = ReturnType<typeof LayerMenuContent>;
3
+ export default LayerMenuContent;
@@ -0,0 +1,67 @@
1
+ <script lang="ts">
2
+ import CopyIcon from 'lucide-svelte/icons/copy';
3
+ import PasteIcon from 'lucide-svelte/icons/clipboard';
4
+ import DuplicateIcon from 'lucide-svelte/icons/copy-plus';
5
+ import AddIcon from 'lucide-svelte/icons/file-plus-2';
6
+ import TrashIcon from 'lucide-svelte/icons/trash-2';
7
+ import LockIcon from 'lucide-svelte/icons/lock-keyhole';
8
+ import UnlockIcon from 'lucide-svelte/icons/lock-keyhole-open';
9
+ import * as DropdownMenu from '../../ui/dropdown-menu/index.js';
10
+ import type { PresentationEditor } from '../presentation-editor.svelte.js';
11
+ import type { Slide } from '../types.js';
12
+ import { checkIfMac } from '../../../utils.js';
13
+
14
+ interface Props {
15
+ editor: PresentationEditor;
16
+ slide: Slide;
17
+ }
18
+
19
+ let { editor, slide }: Props = $props();
20
+
21
+ const locked = $derived(slide.locked);
22
+
23
+ const isMac = checkIfMac();
24
+ </script>
25
+
26
+ <DropdownMenu.Item onclick={() => editor.copySlide(slide.id)}>
27
+ <CopyIcon />
28
+ Copy
29
+ <DropdownMenu.Shortcut>{isMac ? '⌘C' : 'Ctrl+C'}</DropdownMenu.Shortcut>
30
+ </DropdownMenu.Item>
31
+
32
+ <DropdownMenu.Item onclick={() => editor.clipboardPaste()} disabled={!editor.clipboard}>
33
+ <PasteIcon />
34
+ Paste
35
+ <DropdownMenu.Shortcut>{isMac ? '⌘V' : 'Ctrl+V'}</DropdownMenu.Shortcut>
36
+ </DropdownMenu.Item>
37
+
38
+ <DropdownMenu.Item onclick={() => editor.addSlide()}>
39
+ <AddIcon />
40
+ Add page
41
+ <DropdownMenu.Shortcut>{isMac ? '⌘⏎' : 'Ctrl+⏎'}</DropdownMenu.Shortcut>
42
+ </DropdownMenu.Item>
43
+
44
+ <DropdownMenu.Item onclick={() => editor.duplicateSlide(slide)}>
45
+ <DuplicateIcon />
46
+ Duplicate page
47
+ <DropdownMenu.Shortcut>{isMac ? '⌘D' : 'Ctrl+D'}</DropdownMenu.Shortcut>
48
+ </DropdownMenu.Item>
49
+
50
+ <DropdownMenu.Item onclick={() => editor.removeSlide(slide.id)} disabled={locked}>
51
+ <TrashIcon />
52
+ Delete page
53
+ <DropdownMenu.Shortcut>DELETE</DropdownMenu.Shortcut>
54
+ </DropdownMenu.Item>
55
+
56
+ <DropdownMenu.Separator />
57
+
58
+ <DropdownMenu.Item onclick={() => editor.toggleSlideLocked(slide.id)}>
59
+ {#if slide.locked}
60
+ <UnlockIcon />
61
+ Unlock page
62
+ {:else}
63
+ <LockIcon />
64
+ Lock page
65
+ {/if}
66
+ <DropdownMenu.Shortcut>{isMac ? '⌥⇧L' : 'Alt+Shift+L'}</DropdownMenu.Shortcut>
67
+ </DropdownMenu.Item>
@@ -0,0 +1,9 @@
1
+ import type { PresentationEditor } from '../presentation-editor.svelte.js';
2
+ import type { Slide } from '../types.js';
3
+ interface Props {
4
+ editor: PresentationEditor;
5
+ slide: Slide;
6
+ }
7
+ declare const SlideMenuContent: import("svelte").Component<Props, {}, "">;
8
+ type SlideMenuContent = ReturnType<typeof SlideMenuContent>;
9
+ export default SlideMenuContent;