@tableslayer/ui 0.1.3 → 0.1.4

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 (205) hide show
  1. package/package.json +2 -13
  2. package/src/lib/components/Avatar/Avatar.svelte +82 -0
  3. package/src/lib/components/Avatar/AvatarFileInput.svelte +85 -0
  4. package/src/lib/components/Avatar/AvatarPopover.svelte +34 -0
  5. package/src/lib/components/Avatar/index.ts +4 -0
  6. package/src/lib/components/Avatar/types.ts +24 -0
  7. package/src/lib/components/BrushSizeSlider/BrushSizeSlider.svelte +174 -0
  8. package/src/lib/components/BrushSizeSlider/index.ts +1 -0
  9. package/src/lib/components/Button/Button.svelte +182 -0
  10. package/src/lib/components/Button/ConfirmActionButton.svelte +98 -0
  11. package/src/lib/components/Button/IconButton.svelte +121 -0
  12. package/src/lib/components/Button/RadioButton.svelte +93 -0
  13. package/src/lib/components/Button/index.ts +5 -0
  14. package/src/lib/components/Button/types.ts +54 -0
  15. package/src/lib/components/CardFan/CardFan.svelte +165 -0
  16. package/src/lib/components/CardFan/index.ts +2 -0
  17. package/src/lib/components/CardFan/types.ts +6 -0
  18. package/src/lib/components/CodeBlock/Code.svelte +7 -0
  19. package/src/lib/components/CodeBlock/CodeBlock.svelte +102 -0
  20. package/src/lib/components/CodeBlock/index.ts +3 -0
  21. package/src/lib/components/CodeBlock/types.ts +10 -0
  22. package/src/lib/components/ColorMode/ColorMode.svelte +8 -0
  23. package/src/lib/components/ColorMode/index.ts +2 -0
  24. package/src/lib/components/ColorMode/types.ts +12 -0
  25. package/src/lib/components/ColorPicker/ColorPicker.svelte +838 -0
  26. package/src/lib/components/ColorPicker/ColorPickerSwatch.svelte +32 -0
  27. package/src/lib/components/ColorPicker/index.ts +3 -0
  28. package/src/lib/components/ColorPicker/types.ts +51 -0
  29. package/src/lib/components/ContextMenu/ContextMenu.svelte +86 -0
  30. package/src/lib/components/ContextMenu/index.ts +2 -0
  31. package/src/lib/components/ContextMenu/types.ts +15 -0
  32. package/src/lib/components/DrawingSliders/DrawingSliders.svelte +379 -0
  33. package/src/lib/components/DrawingSliders/index.ts +1 -0
  34. package/src/lib/components/Editor/Editor.svelte +825 -0
  35. package/src/lib/components/Editor/index.ts +1 -0
  36. package/src/lib/components/FogSliders/FogSliders.svelte +33 -0
  37. package/src/lib/components/FogSliders/index.ts +1 -0
  38. package/src/lib/components/Hr/Hr.svelte +15 -0
  39. package/src/lib/components/Hr/index.ts +1 -0
  40. package/src/lib/components/Icon/Icon.svelte +6 -0
  41. package/src/lib/components/Icon/index.ts +2 -0
  42. package/src/lib/components/Icon/types.ts +20 -0
  43. package/src/lib/components/Input/DualInputSlider.svelte +126 -0
  44. package/src/lib/components/Input/FileInput.svelte +176 -0
  45. package/src/lib/components/Input/FormControl.svelte +150 -0
  46. package/src/lib/components/Input/FormError.svelte +37 -0
  47. package/src/lib/components/Input/Input.svelte +56 -0
  48. package/src/lib/components/Input/InputCheckbox.svelte +99 -0
  49. package/src/lib/components/Input/InputSlider.svelte +86 -0
  50. package/src/lib/components/Input/Label.svelte +19 -0
  51. package/src/lib/components/Input/index.ts +9 -0
  52. package/src/lib/components/Input/types.ts +39 -0
  53. package/src/lib/components/Link/Link.svelte +41 -0
  54. package/src/lib/components/Link/LinkBox.svelte +20 -0
  55. package/src/lib/components/Link/LinkOverlay.svelte +23 -0
  56. package/src/lib/components/Link/index.ts +4 -0
  57. package/src/lib/components/Link/types.ts +17 -0
  58. package/src/lib/components/Loading/Loader.svelte +60 -0
  59. package/src/lib/components/Loading/Skeleton.svelte +9 -0
  60. package/src/lib/components/Loading/index.ts +2 -0
  61. package/src/lib/components/Logo/Logo.svelte +16 -0
  62. package/src/lib/components/Logo/index.ts +1 -0
  63. package/src/lib/components/MarkerTooltip/MarkerTooltip.svelte +435 -0
  64. package/src/lib/components/MarkerTooltip/index.ts +1 -0
  65. package/src/lib/components/Menu/SelectorMenu.svelte +280 -0
  66. package/src/lib/components/Menu/index.ts +2 -0
  67. package/src/lib/components/Menu/types.ts +17 -0
  68. package/src/lib/components/MyCounterButton.svelte +11 -0
  69. package/src/lib/components/Panel/index.ts +2 -0
  70. package/src/lib/components/Panel/panel.svelte +18 -0
  71. package/src/lib/components/Panel/types.ts +8 -0
  72. package/src/lib/components/PersistButton/PersistButton.svelte +100 -0
  73. package/src/lib/components/PersistButton/index.ts +1 -0
  74. package/src/lib/components/Popover/Popover.svelte +81 -0
  75. package/src/lib/components/Popover/index.ts +2 -0
  76. package/src/lib/components/Popover/types.ts +19 -0
  77. package/src/lib/components/PropsTable/PropsTable.svelte +107 -0
  78. package/src/lib/components/RadialMenu/EffectPreview.svelte +36 -0
  79. package/src/lib/components/RadialMenu/EffectPreviewScene.svelte +194 -0
  80. package/src/lib/components/RadialMenu/RadialMenu.svelte +503 -0
  81. package/src/lib/components/RadialMenu/RadialMenuItem.svelte +176 -0
  82. package/src/lib/components/RadialMenu/index.ts +2 -0
  83. package/src/lib/components/RadialMenu/types.ts +35 -0
  84. package/src/lib/components/Select/Select.svelte +342 -0
  85. package/src/lib/components/Select/index.ts +2 -0
  86. package/src/lib/components/Select/types.ts +22 -0
  87. package/src/lib/components/Spacer/Spacer.svelte +14 -0
  88. package/src/lib/components/Spacer/index.ts +2 -0
  89. package/src/lib/components/Spacer/types.ts +5 -0
  90. package/src/lib/components/Stage/components/AnnotationLayer/AnnotationLayer.svelte +445 -0
  91. package/src/lib/components/Stage/components/AnnotationLayer/AnnotationMaterial.svelte +167 -0
  92. package/src/lib/components/Stage/components/AnnotationLayer/types.ts +196 -0
  93. package/src/lib/components/Stage/components/CursorLayer/CursorLayer.svelte +148 -0
  94. package/src/lib/components/Stage/components/CursorLayer/cursor.svg +26 -0
  95. package/src/lib/components/Stage/components/CursorLayer/index.ts +2 -0
  96. package/src/lib/components/Stage/components/CursorLayer/types.ts +23 -0
  97. package/src/lib/components/Stage/components/DrawingLayer/DrawingMaterial.svelte +364 -0
  98. package/src/lib/components/Stage/components/DrawingLayer/types.ts +65 -0
  99. package/src/lib/components/Stage/components/EdgeOverlayLayer/EdgeOverlayLayer.svelte +72 -0
  100. package/src/lib/components/Stage/components/EdgeOverlayLayer/types.ts +34 -0
  101. package/src/lib/components/Stage/components/FogLayer/FogLayer.svelte +75 -0
  102. package/src/lib/components/Stage/components/FogLayer/types.ts +51 -0
  103. package/src/lib/components/Stage/components/FogOfWarLayer/FogOfWarLayer.svelte +249 -0
  104. package/src/lib/components/Stage/components/FogOfWarLayer/FogOfWarMaterial.svelte +200 -0
  105. package/src/lib/components/Stage/components/FogOfWarLayer/types.ts +116 -0
  106. package/src/lib/components/Stage/components/GridLayer/GridLayer.svelte +20 -0
  107. package/src/lib/components/Stage/components/GridLayer/GridMaterial.svelte +69 -0
  108. package/src/lib/components/Stage/components/GridLayer/types.ts +79 -0
  109. package/src/lib/components/Stage/components/LayerInput/LayerInput.svelte +300 -0
  110. package/src/lib/components/Stage/components/MapLayer/MapLayer.svelte +196 -0
  111. package/src/lib/components/Stage/components/MapLayer/dataSources/GifDataSource.ts +265 -0
  112. package/src/lib/components/Stage/components/MapLayer/dataSources/IMapDataSource.ts +55 -0
  113. package/src/lib/components/Stage/components/MapLayer/dataSources/ImageDataSource.ts +87 -0
  114. package/src/lib/components/Stage/components/MapLayer/dataSources/VideoDataSource.ts +150 -0
  115. package/src/lib/components/Stage/components/MapLayer/dataSources/dataSourceFactory.ts +48 -0
  116. package/src/lib/components/Stage/components/MapLayer/dataSources/index.ts +16 -0
  117. package/src/lib/components/Stage/components/MapLayer/types.ts +58 -0
  118. package/src/lib/components/Stage/components/MarkerLayer/MarkerLayer.svelte +398 -0
  119. package/src/lib/components/Stage/components/MarkerLayer/MarkerToken.svelte +262 -0
  120. package/src/lib/components/Stage/components/MarkerLayer/types.ts +126 -0
  121. package/src/lib/components/Stage/components/MeasurementLayer/MeasurementLayer.svelte +364 -0
  122. package/src/lib/components/Stage/components/MeasurementLayer/MeasurementManager.svelte +473 -0
  123. package/src/lib/components/Stage/components/MeasurementLayer/measurements/BaseMeasurement.ts +427 -0
  124. package/src/lib/components/Stage/components/MeasurementLayer/measurements/BeamMeasurement.ts +105 -0
  125. package/src/lib/components/Stage/components/MeasurementLayer/measurements/CircleMeasurement.ts +98 -0
  126. package/src/lib/components/Stage/components/MeasurementLayer/measurements/ConeMeasurement.ts +163 -0
  127. package/src/lib/components/Stage/components/MeasurementLayer/measurements/LineMeasurement.ts +102 -0
  128. package/src/lib/components/Stage/components/MeasurementLayer/measurements/RectangleMeasurement.ts +120 -0
  129. package/src/lib/components/Stage/components/MeasurementLayer/measurements/index.ts +7 -0
  130. package/src/lib/components/Stage/components/MeasurementLayer/types.ts +94 -0
  131. package/src/lib/components/Stage/components/MeasurementLayer/utils/canvasDrawing.ts +357 -0
  132. package/src/lib/components/Stage/components/MeasurementLayer/utils/distanceCalculations.ts +170 -0
  133. package/src/lib/components/Stage/components/ParticleSystem/ParticleSystem.svelte +220 -0
  134. package/src/lib/components/Stage/components/ParticleSystem/particles/atlases/ash.png +0 -0
  135. package/src/lib/components/Stage/components/ParticleSystem/particles/atlases/leaves.png +0 -0
  136. package/src/lib/components/Stage/components/ParticleSystem/particles/atlases/rain.png +0 -0
  137. package/src/lib/components/Stage/components/ParticleSystem/particles/atlases/snow.png +0 -0
  138. package/src/lib/components/Stage/components/ParticleSystem/rng.js +20 -0
  139. package/src/lib/components/Stage/components/ParticleSystem/types.ts +95 -0
  140. package/src/lib/components/Stage/components/PerformanceDebugger/PerformanceDebugger.svelte +144 -0
  141. package/src/lib/components/Stage/components/PerformanceDebugger/index.ts +1 -0
  142. package/src/lib/components/Stage/components/PerformanceOverlay/PerformanceOverlay.svelte +208 -0
  143. package/src/lib/components/Stage/components/PerformanceOverlay/index.ts +1 -0
  144. package/src/lib/components/Stage/components/PointerInputManager/PointerInputManager.svelte +201 -0
  145. package/src/lib/components/Stage/components/Scene/Scene.svelte +651 -0
  146. package/src/lib/components/Stage/components/Scene/luts.ts +24 -0
  147. package/src/lib/components/Stage/components/Scene/types.ts +225 -0
  148. package/src/lib/components/Stage/components/Stage/Stage.svelte +332 -0
  149. package/src/lib/components/Stage/components/Stage/types.ts +136 -0
  150. package/src/lib/components/Stage/components/WeatherLayer/WeatherLayer.svelte +135 -0
  151. package/src/lib/components/Stage/components/WeatherLayer/presets/AshPreset.ts +71 -0
  152. package/src/lib/components/Stage/components/WeatherLayer/presets/LeavesPreset.ts +70 -0
  153. package/src/lib/components/Stage/components/WeatherLayer/presets/RainPreset.ts +68 -0
  154. package/src/lib/components/Stage/components/WeatherLayer/presets/SnowPreset.ts +70 -0
  155. package/src/lib/components/Stage/components/WeatherLayer/presets/index.ts +6 -0
  156. package/src/lib/components/Stage/components/WeatherLayer/types.ts +35 -0
  157. package/src/lib/components/Stage/helpers/clippingPlaneStore.svelte.ts +28 -0
  158. package/src/lib/components/Stage/helpers/debugState.svelte.ts +18 -0
  159. package/src/lib/components/Stage/helpers/grid.ts +548 -0
  160. package/src/lib/components/Stage/helpers/lazyBrush.ts +171 -0
  161. package/src/lib/components/Stage/helpers/performanceMetrics.svelte.ts +220 -0
  162. package/src/lib/components/Stage/helpers/utils.ts +21 -0
  163. package/src/lib/components/Stage/index.ts +49 -0
  164. package/src/lib/components/Stage/shaders/AnnotationEffects.frag +1070 -0
  165. package/src/lib/components/Stage/shaders/Annotations.frag +29 -0
  166. package/src/lib/components/Stage/shaders/Drawing.frag +83 -0
  167. package/src/lib/components/Stage/shaders/Drawing.vert +5 -0
  168. package/src/lib/components/Stage/shaders/Fog.frag +147 -0
  169. package/src/lib/components/Stage/shaders/FractalNoise.frag +96 -0
  170. package/src/lib/components/Stage/shaders/GridShader.frag +174 -0
  171. package/src/lib/components/Stage/shaders/Overlay.frag +23 -0
  172. package/src/lib/components/Stage/shaders/Overlay.vert +0 -0
  173. package/src/lib/components/Stage/shaders/Particles.frag +27 -0
  174. package/src/lib/components/Stage/shaders/Particles.vert +51 -0
  175. package/src/lib/components/Stage/shaders/ToolOutline.frag +59 -0
  176. package/src/lib/components/Stage/shaders/default.vert +8 -0
  177. package/src/lib/components/Stage/types.ts +4 -0
  178. package/src/lib/components/Table/Table.svelte +16 -0
  179. package/src/lib/components/Table/Td.svelte +17 -0
  180. package/src/lib/components/Table/Th.svelte +18 -0
  181. package/src/lib/components/Table/index.ts +4 -0
  182. package/src/lib/components/Table/types.ts +14 -0
  183. package/src/lib/components/Text/Text.svelte +23 -0
  184. package/src/lib/components/Text/index.ts +2 -0
  185. package/src/lib/components/Text/types.ts +12 -0
  186. package/src/lib/components/Title/Title.svelte +54 -0
  187. package/src/lib/components/Title/index.ts +2 -0
  188. package/src/lib/components/Title/types.ts +9 -0
  189. package/src/lib/components/Toast/Toast.svelte +155 -0
  190. package/src/lib/components/Toast/index.ts +5 -0
  191. package/src/lib/components/Toast/toastCookie.ts +24 -0
  192. package/src/lib/components/Toast/types.ts +6 -0
  193. package/src/lib/components/ToolTip/ToolTip.svelte +70 -0
  194. package/src/lib/components/ToolTip/index.ts +2 -0
  195. package/src/lib/components/ToolTip/types.ts +14 -0
  196. package/src/lib/components/index.ts +32 -0
  197. package/src/lib/components/types.ts +0 -0
  198. package/src/lib/index.ts +2 -0
  199. package/src/lib/styles/globals.css +108 -0
  200. package/src/lib/styles/normalize.css +9 -0
  201. package/src/lib/styles/reset.css +133 -0
  202. package/src/lib/styles/utilities.css +179 -0
  203. package/src/lib/styles/vars.css +1103 -0
  204. package/src/lib/types/awareness.ts +17 -0
  205. package/src/lib/utils/rle.ts +217 -0
@@ -0,0 +1,32 @@
1
+ <script lang="ts">
2
+ let { color }: { color: string } = $props();
3
+ </script>
4
+
5
+ <div class="colorPickerSwatch">
6
+ <div class="colorPickerSwatch__color" style="background-color: {color}"></div>
7
+ </div>
8
+
9
+ <style>
10
+ .colorPickerSwatch {
11
+ width: 1rem;
12
+ height: 1rem;
13
+ border-radius: var(--radius-2);
14
+ background-image:
15
+ linear-gradient(45deg, var(--contrastMedium) 26%, transparent 26%),
16
+ linear-gradient(135deg, var(--contrastMedium) 26%, transparent 26%),
17
+ linear-gradient(45deg, transparent 75%, var(--contrastMedium) 75%),
18
+ linear-gradient(135deg, transparent 75%, var(--contrastMedium) 75%);
19
+ background-size: 0.5rem 0.5rem; /* Must be a square */
20
+ background-position:
21
+ 0 0,
22
+ 0.25rem 0,
23
+ 0.25rem -0.25rem,
24
+ 0px 0.25rem;
25
+ overflow: hidden;
26
+ }
27
+ .colorPickerSwatch__color {
28
+ width: 100%;
29
+ height: 100%;
30
+ border-radius: var(--radius-2);
31
+ }
32
+ </style>
@@ -0,0 +1,3 @@
1
+ export { default as ColorPicker } from './ColorPicker.svelte';
2
+ export { default as ColorPickerSwatch } from './ColorPickerSwatch.svelte';
3
+ export * from './types';
@@ -0,0 +1,51 @@
1
+ export type RGBA = {
2
+ r: number;
3
+ g: number;
4
+ b: number;
5
+ a: number;
6
+ };
7
+
8
+ export type HSVA = {
9
+ h: number;
10
+ s: number;
11
+ v: number;
12
+ a: number;
13
+ };
14
+
15
+ export type HSLA = {
16
+ h: number;
17
+ s: number;
18
+ l: number;
19
+ a: number;
20
+ };
21
+
22
+ export type ColorPickerProps = {
23
+ id?: string;
24
+ hex?: string;
25
+ rgba?: RGBA;
26
+ hsva?: HSVA;
27
+ hsla?: HSLA;
28
+ showAlpha?: boolean;
29
+ showInputs?: boolean;
30
+ showOpacity?: boolean;
31
+ onUpdate?: (payload: ColorUpdatePayload) => void;
32
+ };
33
+
34
+ export type ColorUpdatePayload = {
35
+ hex: string;
36
+ rgba: { r: number; g: number; b: number; a: number };
37
+ hsva: { h: number; s: number; v: number; a: number };
38
+ hsla: { h: number; s: number; l: number; a: number };
39
+ };
40
+
41
+ export type ColorState = {
42
+ hue: number;
43
+ saturation: number;
44
+ value: number;
45
+ opacity: number;
46
+ isSelecting: boolean;
47
+ isAdjustingSV: boolean;
48
+ isAdjustingHue: boolean;
49
+ };
50
+
51
+ export type ColorPickerFormats = 'hex' | 'rgb' | 'hsv' | 'hsl';
@@ -0,0 +1,86 @@
1
+ <script lang="ts">
2
+ import { createContextMenu, melt } from '@melt-ui/svelte';
3
+ import type { ContextMenuProps, ContextMenuItem } from './types';
4
+ import { goto } from '$app/navigation';
5
+ let { items, trigger }: ContextMenuProps = $props();
6
+ import { fly } from 'svelte/transition';
7
+ import { Hr } from '../Hr';
8
+ import Spacer from '../Spacer/Spacer.svelte';
9
+ const {
10
+ elements: { menu, item: meltItem, trigger: meltTrigger }
11
+ } = createContextMenu();
12
+
13
+ const handleItemClick = (item: ContextMenuItem) => {
14
+ if (item.href) {
15
+ goto(item.href);
16
+ }
17
+ if (item.onclick) {
18
+ item.onclick();
19
+ }
20
+ };
21
+ </script>
22
+
23
+ <button use:melt={$meltTrigger} class="cMenuTrigger">
24
+ {@render trigger()}
25
+ </button>
26
+ <div use:melt={$menu} class="cMenu" transition:fly={{ duration: 50 }}>
27
+ {#each items as item}
28
+ {#if item.type === 'divider'}
29
+ <Spacer size="0.5rem" />
30
+ <Hr />
31
+ <Spacer size="0.5rem" />
32
+ {:else}
33
+ <button use:melt={$meltItem} onclick={() => handleItemClick(item)} class="cMenuItem">
34
+ {item.label}
35
+ {#if item.end}
36
+ <div class="cMenuItemEnd">
37
+ {@render item.end()}
38
+ </div>
39
+ {/if}
40
+ </button>
41
+ {/if}
42
+ {/each}
43
+ </div>
44
+
45
+ <style>
46
+ :global(.light) {
47
+ --cMenuItemHover: var(--primary-50);
48
+ --cMenuItemBorderHover: solid 2px var(--primary-600);
49
+ }
50
+ :global(.dark) {
51
+ --cMenuItemHover: var(--primary-950);
52
+ --cMenuItemBorderHover: solid 2px var(--primary-500);
53
+ }
54
+ .cMenu {
55
+ z-index: 1000;
56
+ background-color: var(--bg);
57
+ border: var(--borderThin);
58
+ border-radius: var(--radius-1);
59
+ box-shadow: var(--shadow-2);
60
+ padding: 0.5rem;
61
+ min-width: 10rem;
62
+ }
63
+ .cMenuItem {
64
+ cursor: pointer;
65
+ display: flex;
66
+ align-items: center;
67
+ padding: var(--size-1) var(--size-4);
68
+ gap: var(--size-4);
69
+ border-radius: var(--radius-1);
70
+ width: 100%;
71
+ border: solid 2px transparent;
72
+ justify-content: space-between;
73
+ }
74
+ .cMenuItem:hover,
75
+ .cMenuItem:focus,
76
+ .cMenuItem:active {
77
+ background-color: var(--menuItemHover);
78
+ border: var(--menuItemBorderHover);
79
+ }
80
+ .cMenuItemEnd {
81
+ justify-self: flex-end;
82
+ }
83
+ .cMenuTrigger {
84
+ display: block;
85
+ }
86
+ </style>
@@ -0,0 +1,2 @@
1
+ export { default as ContextMenu } from './ContextMenu.svelte';
2
+ export * from './types';
@@ -0,0 +1,15 @@
1
+ import type { ContextMenuItemProps, CreateContextMenuProps } from '@melt-ui/svelte';
2
+ import type { Snippet } from 'svelte';
3
+
4
+ export type ContextMenuItem = ContextMenuItemProps & {
5
+ type?: 'divider';
6
+ label?: string;
7
+ href?: string;
8
+ onclick?: () => void;
9
+ end?: Snippet;
10
+ };
11
+
12
+ export type ContextMenuProps = CreateContextMenuProps & {
13
+ items: ContextMenuItem[];
14
+ trigger: Snippet;
15
+ };
@@ -0,0 +1,379 @@
1
+ <script lang="ts">
2
+ import { Popover } from '../Popover';
3
+ import { Icon } from '../Icon';
4
+ import { IconButton } from '../Button';
5
+ import {
6
+ IconBoxMultiple,
7
+ IconBoxMultiple1,
8
+ IconBoxMultiple2,
9
+ IconBoxMultiple3,
10
+ IconBoxMultiple4,
11
+ IconBoxMultiple5,
12
+ IconBoxMultiple6,
13
+ IconBoxMultiple7,
14
+ IconBoxMultiple8,
15
+ IconBoxMultiple9
16
+ } from '@tabler/icons-svelte';
17
+ import type { ComponentType } from 'svelte';
18
+ import { AnnotationEffect } from '../Stage/components/AnnotationLayer/types';
19
+ import EffectPreview from '../RadialMenu/EffectPreview.svelte';
20
+
21
+ // Color palette - 10 colors
22
+ const COLORS = [
23
+ '#d73e2e', // red
24
+ '#ffa500', // orange
25
+ '#ffd93d', // yellow
26
+ '#6bcf7f', // green
27
+ '#2e86ab', // blue
28
+ '#b197fc', // purple
29
+ '#f06595', // pink
30
+ '#20c997', // turquoise
31
+ '#ffffff', // white
32
+ '#2a2a2a' // dark
33
+ ];
34
+
35
+ // Effects array
36
+ const EFFECTS = [
37
+ AnnotationEffect.Fire,
38
+ AnnotationEffect.Water,
39
+ AnnotationEffect.Ice,
40
+ AnnotationEffect.Magic,
41
+ AnnotationEffect.Grease,
42
+ AnnotationEffect.SpaceTear
43
+ ];
44
+
45
+ // Effect colors for the opacity slider gradient
46
+ const EFFECT_COLORS: Record<AnnotationEffect, string> = {
47
+ [AnnotationEffect.None]: '#ffffff',
48
+ [AnnotationEffect.Fire]: '#ff4d1a',
49
+ [AnnotationEffect.Water]: '#3380cc',
50
+ [AnnotationEffect.Ice]: '#b3d9ff',
51
+ [AnnotationEffect.Magic]: '#9333ea',
52
+ [AnnotationEffect.Grease]: '#4d3319',
53
+ [AnnotationEffect.SpaceTear]: '#330066'
54
+ };
55
+
56
+ interface Props {
57
+ opacity: number;
58
+ brushSize: number;
59
+ color: string;
60
+ activeLayerIndex: number;
61
+ currentEffect?: AnnotationEffect;
62
+ onOpacityChange: (value: number) => void;
63
+ onBrushSizeChange: (value: number) => void;
64
+ onColorChange: (color: string, opacity: number) => void;
65
+ onEffectChange?: (effect: AnnotationEffect) => void;
66
+ onLayersClick: () => void;
67
+ }
68
+
69
+ let {
70
+ opacity,
71
+ brushSize,
72
+ color,
73
+ activeLayerIndex,
74
+ currentEffect = AnnotationEffect.None,
75
+ onOpacityChange,
76
+ onBrushSizeChange,
77
+ onColorChange,
78
+ onEffectChange,
79
+ onLayersClick
80
+ }: Props = $props();
81
+
82
+ // Select the appropriate icon based on layer count
83
+ const layerIcons: ComponentType[] = [
84
+ IconBoxMultiple1,
85
+ IconBoxMultiple2,
86
+ IconBoxMultiple3,
87
+ IconBoxMultiple4,
88
+ IconBoxMultiple5,
89
+ IconBoxMultiple6,
90
+ IconBoxMultiple7,
91
+ IconBoxMultiple8,
92
+ IconBoxMultiple9
93
+ ];
94
+
95
+ const layerIcon = $derived.by(() => {
96
+ // activeLayerIndex is 1-based (1st layer, 2nd layer, etc.)
97
+ return activeLayerIndex <= 9 && activeLayerIndex > 0 ? layerIcons[activeLayerIndex - 1] : IconBoxMultiple;
98
+ });
99
+
100
+ // Check if current selection is an effect
101
+ const hasEffect = $derived(currentEffect !== AnnotationEffect.None);
102
+
103
+ // Brush size is now stored as a percentage (0.01% to 5%)
104
+ // Use quadratic curve for slider to give more precision to lower values
105
+ // Slider range: 0-100, maps to percentage range: 0.01-5.0
106
+ // At 50% slider we want 2%, so we use: percentage = 0.0008 * slider^2
107
+ // This gives: 10% → 0.08%, 50% → 2%, 100% → 8% (capped at 5%)
108
+ const percentageToSlider = (percentage: number): number => {
109
+ // Inverse: slider = sqrt(percentage / 0.0008)
110
+ // Clamp to minimum of 0.01
111
+ const clampedPercentage = Math.max(0.01, percentage);
112
+ return Math.sqrt(clampedPercentage / 0.0008);
113
+ };
114
+
115
+ const sliderToPercentage = (slider: number): number => {
116
+ // Quadratic curve: percentage = 0.0008 * slider^2
117
+ const percentage = 0.0008 * slider * slider;
118
+ return Math.max(0.01, Math.min(5.0, percentage));
119
+ };
120
+
121
+ let brushSliderValue = $derived(percentageToSlider(brushSize));
122
+
123
+ const handleBrushSliderChange = (value: number) => {
124
+ const actualPercentage = sliderToPercentage(value);
125
+ onBrushSizeChange(actualPercentage);
126
+ };
127
+
128
+ const handleColorSelect = (selectedColor: string, close?: () => void) => {
129
+ onColorChange(selectedColor, opacity);
130
+ // Clear any active effect when selecting a color
131
+ onEffectChange?.(AnnotationEffect.None);
132
+ close?.();
133
+ };
134
+
135
+ const handleEffectSelect = (effect: AnnotationEffect, close?: () => void) => {
136
+ // Set color to match the effect for the opacity slider gradient
137
+ onColorChange(EFFECT_COLORS[effect], opacity);
138
+ onEffectChange?.(effect);
139
+ close?.();
140
+ };
141
+
142
+ // Touch event handlers for better mobile support
143
+ const handleTouchStart = (e: TouchEvent) => {
144
+ // Prevent default to avoid conflicts with other touch interactions
145
+ e.stopPropagation();
146
+ };
147
+
148
+ const handleTouchMove = (e: TouchEvent) => {
149
+ // Prevent scrolling while adjusting sliders
150
+ e.preventDefault();
151
+ e.stopPropagation();
152
+ };
153
+ </script>
154
+
155
+ <div class="drawingSliders">
156
+ <div class="drawingSliders__slider">
157
+ <Popover portal="body" positioning={{ placement: 'left', gutter: 12 }}>
158
+ {#snippet trigger()}
159
+ <button class="drawingSliders__colorSwatch" aria-label="Change annotation color or effect">
160
+ {#if hasEffect}
161
+ <EffectPreview effectType={currentEffect} size="2rem" shape="rounded" />
162
+ {:else}
163
+ <span class="drawingSliders__colorSwatchInner" style:background-color={color} style:opacity></span>
164
+ {/if}
165
+ </button>
166
+ {/snippet}
167
+ {#snippet content({ contentProps })}
168
+ <div class="drawingSliders__swatchGrid">
169
+ {#each COLORS as swatchColor}
170
+ <button
171
+ class="drawingSliders__gridItem"
172
+ onclick={() => handleColorSelect(swatchColor, contentProps.close)}
173
+ aria-label="Select color {swatchColor}"
174
+ >
175
+ <span class="drawingSliders__gridSwatch" style:background-color={swatchColor}></span>
176
+ </button>
177
+ {/each}
178
+ {#each EFFECTS as effect}
179
+ <button
180
+ class="drawingSliders__gridItem"
181
+ onclick={() => handleEffectSelect(effect, contentProps.close)}
182
+ aria-label="Select effect"
183
+ >
184
+ <EffectPreview effectType={effect} size="2rem" shape="rounded" />
185
+ </button>
186
+ {/each}
187
+ </div>
188
+ {/snippet}
189
+ </Popover>
190
+ <input
191
+ id="opacity-slider"
192
+ type="range"
193
+ class="drawingSliders__input drawingSliders__input--opacity"
194
+ style="--slider-color: {color}"
195
+ min="0"
196
+ max="1"
197
+ step="0.01"
198
+ value={opacity}
199
+ oninput={(e) => onOpacityChange(Number(e.currentTarget.value))}
200
+ ontouchstart={handleTouchStart}
201
+ ontouchmove={handleTouchMove}
202
+ />
203
+ <div class="drawingSliders__value">{Math.round(opacity * 100)}%</div>
204
+ </div>
205
+
206
+ <div class="drawingSliders__slider">
207
+ <input
208
+ id="brush-size-slider"
209
+ type="range"
210
+ class="drawingSliders__input"
211
+ min="0"
212
+ max="100"
213
+ step="0.1"
214
+ value={brushSliderValue}
215
+ oninput={(e) => handleBrushSliderChange(Number(e.currentTarget.value))}
216
+ ontouchstart={handleTouchStart}
217
+ ontouchmove={handleTouchMove}
218
+ />
219
+ <div class="drawingSliders__value">{brushSize.toFixed(2)}%</div>
220
+ </div>
221
+
222
+ <IconButton
223
+ variant="ghost"
224
+ onclick={onLayersClick}
225
+ aria-label="Toggle annotation layers panel"
226
+ title="Manage drawing layers"
227
+ >
228
+ <Icon Icon={layerIcon} size="1.25rem" />
229
+ </IconButton>
230
+ </div>
231
+
232
+ <style>
233
+ .drawingSliders {
234
+ position: absolute;
235
+ top: 50%;
236
+ right: 1rem;
237
+ transform: translateY(-50%);
238
+ display: flex;
239
+ flex-direction: column;
240
+ gap: 1rem;
241
+ z-index: 10;
242
+ pointer-events: auto;
243
+ background-color: var(--bg);
244
+ border: var(--borderThin);
245
+ border-radius: var(--radius-2);
246
+ padding: 0.5rem 0rem;
247
+ align-items: center;
248
+ }
249
+
250
+ .drawingSliders__slider {
251
+ display: flex;
252
+ flex-direction: column;
253
+ align-items: center;
254
+ gap: 1rem;
255
+ }
256
+
257
+ .drawingSliders__input {
258
+ writing-mode: vertical-lr;
259
+ direction: rtl;
260
+ width: 32px;
261
+ height: 120px;
262
+ -webkit-appearance: none;
263
+ appearance: none;
264
+ background: var(--contrastLow);
265
+ border-radius: var(--radius-1);
266
+ cursor: pointer;
267
+ touch-action: none; /* Prevent default touch behaviors */
268
+ outline: none;
269
+ }
270
+
271
+ .drawingSliders__input--opacity {
272
+ background: linear-gradient(to top, transparent, var(--slider-color));
273
+ }
274
+
275
+ /* Webkit browsers (Chrome, Safari, Edge) */
276
+ .drawingSliders__input::-webkit-slider-track {
277
+ width: 32px;
278
+ height: 120px;
279
+ background: transparent;
280
+ border: none;
281
+ }
282
+
283
+ .drawingSliders__input::-webkit-slider-thumb {
284
+ -webkit-appearance: none;
285
+ appearance: none;
286
+ width: 32px;
287
+ height: 14px;
288
+ background: var(--contrastHigh);
289
+ border: none;
290
+ border-radius: var(--radius-1);
291
+ cursor: grab;
292
+ box-shadow: 0 0px 2px rgba(0, 0, 0, 0.2);
293
+ }
294
+
295
+ .drawingSliders__input::-webkit-slider-thumb:active {
296
+ cursor: grabbing;
297
+ }
298
+
299
+ /* Firefox */
300
+ .drawingSliders__input::-moz-range-track {
301
+ width: 32px;
302
+ height: 120px;
303
+ background: var(--contrastLow);
304
+ border-radius: var(--radius-2);
305
+ }
306
+
307
+ .drawingSliders__input--opacity::-moz-range-track {
308
+ background: linear-gradient(to top, transparent, var(--slider-color));
309
+ }
310
+
311
+ .drawingSliders__input::-moz-range-thumb {
312
+ width: 32px;
313
+ height: 14px;
314
+ background: var(--contrastHigh);
315
+ border: none;
316
+ border-radius: var(--radius-2);
317
+ cursor: grab;
318
+ box-shadow: 0 0px 2px rgba(0, 0, 0, 0.2);
319
+ }
320
+
321
+ .drawingSliders__input::-moz-range-thumb:active {
322
+ cursor: grabbing;
323
+ }
324
+
325
+ .drawingSliders__value {
326
+ font-size: 0.875rem;
327
+ font-weight: 600;
328
+ color: var(--fg);
329
+ min-width: 3rem;
330
+ text-align: center;
331
+ }
332
+
333
+ .drawingSliders__colorSwatch {
334
+ width: 2rem;
335
+ height: 2rem;
336
+ border-radius: var(--radius-2);
337
+ cursor: pointer;
338
+ transition: border-color 0.2s;
339
+ padding: 0;
340
+ border: none;
341
+ background: transparent;
342
+ overflow: hidden;
343
+ }
344
+
345
+ .drawingSliders__colorSwatchInner {
346
+ display: block;
347
+ width: 100%;
348
+ height: 100%;
349
+ border-radius: var(--radius-2);
350
+ }
351
+
352
+ .drawingSliders__swatchGrid {
353
+ display: grid;
354
+ grid-template-columns: repeat(4, 1fr);
355
+ gap: 0.5rem;
356
+ background-color: var(--bg);
357
+ border-radius: var(--radius-2);
358
+ }
359
+
360
+ .drawingSliders__gridItem {
361
+ width: 2rem;
362
+ height: 2rem;
363
+ border-radius: var(--radius-2);
364
+ cursor: pointer;
365
+ border: none;
366
+ padding: 0;
367
+ background: transparent;
368
+ display: flex;
369
+ align-items: center;
370
+ justify-content: center;
371
+ overflow: hidden;
372
+ }
373
+
374
+ .drawingSliders__gridSwatch {
375
+ width: 2rem;
376
+ height: 2rem;
377
+ border-radius: var(--radius-1);
378
+ }
379
+ </style>
@@ -0,0 +1 @@
1
+ export { default as DrawingSliders } from './DrawingSliders.svelte';