Spaces:
Runtime error
Runtime error
UI improvements
Browse files- frontend/src/lib/App.svelte +2 -2
- frontend/src/lib/Buttons/DragButton.svelte +2 -0
- frontend/src/lib/Buttons/MaskButton.svelte +2 -0
- frontend/src/lib/Buttons/PPButton.svelte +17 -8
- frontend/src/lib/Buttons/UndoButton.svelte +2 -0
- frontend/src/lib/Frame.svelte +9 -24
- frontend/src/lib/Icons/LoadingIcon.svelte +2 -2
- frontend/src/lib/PaintCanvas.svelte +2 -2
- frontend/src/lib/PaintFrame.svelte +25 -18
frontend/src/lib/App.svelte
CHANGED
@@ -177,9 +177,9 @@
|
|
177 |
<!-- When others connected, iterate through others and show their cursors -->
|
178 |
{#if $others}
|
179 |
{#each [...$others] as { connectionId, presence } (connectionId)}
|
180 |
-
{#if (presence?.status === Status.prompting || presence?.status === Status.masking) && presence?.frame}
|
181 |
<Frame
|
182 |
-
|
183 |
position={presence?.frame}
|
184 |
prompt={presence?.currentPrompt}
|
185 |
transform={$currZoomTransform}
|
|
|
177 |
<!-- When others connected, iterate through others and show their cursors -->
|
178 |
{#if $others}
|
179 |
{#each [...$others] as { connectionId, presence } (connectionId)}
|
180 |
+
{#if (presence?.status === Status.loading || presence?.status === Status.prompting || presence?.status === Status.masking) && presence?.frame}
|
181 |
<Frame
|
182 |
+
isLoading={presence?.status === Status.loading}
|
183 |
position={presence?.frame}
|
184 |
prompt={presence?.currentPrompt}
|
185 |
transform={$currZoomTransform}
|
frontend/src/lib/Buttons/DragButton.svelte
CHANGED
@@ -1,10 +1,12 @@
|
|
1 |
<script lang="ts">
|
2 |
import Move from '$lib/Icons/Move.svelte';
|
3 |
export let isActive = false;
|
|
|
4 |
</script>
|
5 |
|
6 |
<button
|
7 |
on:click
|
|
|
8 |
class="bg-white rounded-full p-2 {isActive ? 'text-blue-700' : 'text-gray-800'}"
|
9 |
title="Enable Dragging"
|
10 |
>
|
|
|
1 |
<script lang="ts">
|
2 |
import Move from '$lib/Icons/Move.svelte';
|
3 |
export let isActive = false;
|
4 |
+
export let isLoading = false;
|
5 |
</script>
|
6 |
|
7 |
<button
|
8 |
on:click
|
9 |
+
disabled={isLoading}
|
10 |
class="bg-white rounded-full p-2 {isActive ? 'text-blue-700' : 'text-gray-800'}"
|
11 |
title="Enable Dragging"
|
12 |
>
|
frontend/src/lib/Buttons/MaskButton.svelte
CHANGED
@@ -1,10 +1,12 @@
|
|
1 |
<script lang="ts">
|
2 |
import Mask from '$lib/Icons/Mask.svelte';
|
3 |
export let isActive = false;
|
|
|
4 |
</script>
|
5 |
|
6 |
<button
|
7 |
on:click
|
|
|
8 |
class="bg-white rounded-full p-2 {isActive ? 'text-blue-700' : 'text-gray-800'}"
|
9 |
title="Enable Masking"
|
10 |
>
|
|
|
1 |
<script lang="ts">
|
2 |
import Mask from '$lib/Icons/Mask.svelte';
|
3 |
export let isActive = false;
|
4 |
+
export let isLoading = false;
|
5 |
</script>
|
6 |
|
7 |
<button
|
8 |
on:click
|
9 |
+
disabled={isLoading}
|
10 |
class="bg-white rounded-full p-2 {isActive ? 'text-blue-700' : 'text-gray-800'}"
|
11 |
title="Enable Masking"
|
12 |
>
|
frontend/src/lib/Buttons/PPButton.svelte
CHANGED
@@ -1,13 +1,22 @@
|
|
1 |
<script lang="ts">
|
|
|
2 |
</script>
|
3 |
|
4 |
-
<button
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
</button>
|
12 |
|
13 |
<style lang="postcss" scoped>
|
@@ -15,6 +24,6 @@
|
|
15 |
@apply disabled:opacity-50 dark:bg-white dark:text-black bg-black text-white rounded-2xl text-xs shadow-sm focus:outline-none focus:border-gray-400;
|
16 |
} */
|
17 |
.button-paint {
|
18 |
-
@apply font-mono flex justify-center items-center disabled:opacity-
|
19 |
}
|
20 |
</style>
|
|
|
1 |
<script lang="ts">
|
2 |
+
export let isLoading = false;
|
3 |
</script>
|
4 |
|
5 |
+
<button
|
6 |
+
on:click
|
7 |
+
disabled={isLoading}
|
8 |
+
class="button-paint bg-violet-100 text-violet-900 min-w-[25ch] "
|
9 |
+
title="New Paint Frame"
|
10 |
+
>
|
11 |
+
{#if isLoading}
|
12 |
+
<span class="font-mono">paiting... </span>{:else}
|
13 |
+
<span
|
14 |
+
class="rounded-sm h-6 w-6 flex justify-center items-center border-2 border-dashed border-violet-700 mr-2"
|
15 |
+
>
|
16 |
+
+
|
17 |
+
</span>
|
18 |
+
<span>Prompt + Paint</span>
|
19 |
+
{/if}
|
20 |
</button>
|
21 |
|
22 |
<style lang="postcss" scoped>
|
|
|
24 |
@apply disabled:opacity-50 dark:bg-white dark:text-black bg-black text-white rounded-2xl text-xs shadow-sm focus:outline-none focus:border-gray-400;
|
25 |
} */
|
26 |
.button-paint {
|
27 |
+
@apply font-mono flex justify-center items-center disabled:opacity-80 dark:bg-white dark:text-black rounded-2xl px-3 py-1 shadow-sm focus:outline-none focus:border-gray-400;
|
28 |
}
|
29 |
</style>
|
frontend/src/lib/Buttons/UndoButton.svelte
CHANGED
@@ -1,10 +1,12 @@
|
|
1 |
<script lang="ts">
|
2 |
import Undo from '$lib/Icons/Undo.svelte';
|
3 |
export let isActive = false;
|
|
|
4 |
</script>
|
5 |
|
6 |
<button
|
7 |
on:click
|
|
|
8 |
class="bg-white rounded-full p-2 {isActive ? 'text-blue-700' : 'text-gray-800'}"
|
9 |
title="Clear Masking"
|
10 |
>
|
|
|
1 |
<script lang="ts">
|
2 |
import Undo from '$lib/Icons/Undo.svelte';
|
3 |
export let isActive = false;
|
4 |
+
export let isLoading = false;
|
5 |
</script>
|
6 |
|
7 |
<button
|
8 |
on:click
|
9 |
+
disabled={isLoading}
|
10 |
class="bg-white rounded-full p-2 {isActive ? 'text-blue-700' : 'text-gray-800'}"
|
11 |
title="Clear Masking"
|
12 |
>
|
frontend/src/lib/Frame.svelte
CHANGED
@@ -4,12 +4,8 @@
|
|
4 |
import type { ZoomTransform } from 'd3-zoom';
|
5 |
|
6 |
export let transform: ZoomTransform;
|
7 |
-
export let color = '';
|
8 |
export let position = { x: 0, y: 0 };
|
9 |
export let prompt = '';
|
10 |
-
export let loadingState = '';
|
11 |
-
export let interactive = false;
|
12 |
-
export let isDragging = false;
|
13 |
export let isLoading = false;
|
14 |
$: coord = {
|
15 |
x: transform.applyX(position.x),
|
@@ -18,29 +14,18 @@
|
|
18 |
</script>
|
19 |
|
20 |
<div
|
21 |
-
class="frame
|
22 |
-
style={`transform: translateX(${coord.x}px) translateY(${coord.y}px) scale(${transform.k});
|
23 |
>
|
24 |
-
<div class=
|
25 |
-
|
26 |
-
<div class="col-span-2 row-start-1">
|
27 |
-
<span class="text-white drop-shadow-lg">{loadingState}</span>
|
28 |
-
</div>
|
29 |
-
{/if}
|
30 |
-
{#if isLoading}
|
31 |
-
<div class="col-start-2 row-start-2">
|
32 |
-
<LoadingIcon />
|
33 |
-
</div>
|
34 |
-
{/if}
|
35 |
-
|
36 |
-
<h2 class="text-lg"></h2>
|
37 |
-
<div class="absolute bottom-0 font-bold text-lg">{prompt}</div>
|
38 |
</div>
|
|
|
|
|
|
|
|
|
|
|
39 |
</div>
|
40 |
|
41 |
<style lang="postcss" scoped>
|
42 |
-
.frame {
|
43 |
-
@apply absolute top-0 left-0 grid grid-cols-3 grid-rows-3 border-2 border-spacing-3 border-sky-500 w-[512px] h-[512px];
|
44 |
-
transform-origin: 0 0;
|
45 |
-
}
|
46 |
</style>
|
|
|
4 |
import type { ZoomTransform } from 'd3-zoom';
|
5 |
|
6 |
export let transform: ZoomTransform;
|
|
|
7 |
export let position = { x: 0, y: 0 };
|
8 |
export let prompt = '';
|
|
|
|
|
|
|
9 |
export let isLoading = false;
|
10 |
$: coord = {
|
11 |
x: transform.applyX(position.x),
|
|
|
14 |
</script>
|
15 |
|
16 |
<div
|
17 |
+
class="frame @apply absolute top-0 left-0 ring-8 ring-[#EC8E65] w-[512px] h-[512px]"
|
18 |
+
style={`transform: translateX(${coord.x}px) translateY(${coord.y}px) scale(${transform.k}); transform-origin: 0 0;`}
|
19 |
>
|
20 |
+
<div class="pointer-events-none touch-none">
|
21 |
+
<div class="font-bold text-xl text-[#EC8E65] text-center px-2 line-clamp-4">{prompt}</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
</div>
|
23 |
+
{#if isLoading}
|
24 |
+
<div class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2">
|
25 |
+
<LoadingIcon />
|
26 |
+
</div>
|
27 |
+
{/if}
|
28 |
</div>
|
29 |
|
30 |
<style lang="postcss" scoped>
|
|
|
|
|
|
|
|
|
31 |
</style>
|
frontend/src/lib/Icons/LoadingIcon.svelte
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
<svg
|
2 |
-
class="animate-spin
|
3 |
width="51"
|
4 |
height="51"
|
5 |
viewBox="0 0 21 21"
|
@@ -12,6 +12,6 @@
|
|
12 |
/>
|
13 |
<path
|
14 |
d="M10.5006 17C9.6233 17 8.77136 16.8286 7.97021 16.4896C7.19572 16.1621 6.50122 15.6924 5.90448 15.0957C5.30774 14.499 4.83797 13.8046 4.5104 13.0302C4.1714 12.2291 4 11.3772 4 10.5C4 10.2474 4.20441 10.043 4.45708 10.043C4.70974 10.043 4.91415 10.2474 4.91415 10.5C4.91415 11.2541 5.06143 11.9854 5.35345 12.6747C5.63532 13.3399 6.0378 13.9379 6.55074 14.4508C7.06368 14.9637 7.66169 15.3674 8.32698 15.6479C9.01514 15.9387 9.74646 16.0859 10.5006 16.0859C11.2548 16.0859 11.9861 15.9387 12.6756 15.6467C13.3409 15.3648 13.9389 14.9624 14.4518 14.4495C14.9647 13.9366 15.3685 13.3387 15.6491 12.6734C15.9398 11.9854 16.0871 11.2541 16.0871 10.5C16.0871 9.7459 15.9398 9.01465 15.6478 8.32529C15.3669 7.66166 14.9604 7.05857 14.4505 6.54922C13.9417 6.03876 13.3384 5.63215 12.6743 5.35205C11.9861 5.06133 11.2548 4.91406 10.5006 4.91406C10.248 4.91406 10.0436 4.70967 10.0436 4.45703C10.0436 4.20439 10.248 4 10.5006 4C11.378 4 12.2299 4.17139 13.0311 4.51035C13.8055 4.83789 14.5 5.30762 15.0968 5.9043C15.6935 6.50098 16.162 7.19668 16.4896 7.96982C16.8286 8.7709 17 9.62275 17 10.5C17 11.3772 16.8286 12.2291 16.4896 13.0302C16.1633 13.8046 15.6935 14.499 15.0968 15.0957C14.5 15.6924 13.8043 16.1608 13.0311 16.4884C12.2299 16.8286 11.378 17 10.5006 17Z"
|
15 |
-
fill="
|
16 |
/>
|
17 |
</svg>
|
|
|
1 |
<svg
|
2 |
+
class="animate-spin"
|
3 |
width="51"
|
4 |
height="51"
|
5 |
viewBox="0 0 21 21"
|
|
|
12 |
/>
|
13 |
<path
|
14 |
d="M10.5006 17C9.6233 17 8.77136 16.8286 7.97021 16.4896C7.19572 16.1621 6.50122 15.6924 5.90448 15.0957C5.30774 14.499 4.83797 13.8046 4.5104 13.0302C4.1714 12.2291 4 11.3772 4 10.5C4 10.2474 4.20441 10.043 4.45708 10.043C4.70974 10.043 4.91415 10.2474 4.91415 10.5C4.91415 11.2541 5.06143 11.9854 5.35345 12.6747C5.63532 13.3399 6.0378 13.9379 6.55074 14.4508C7.06368 14.9637 7.66169 15.3674 8.32698 15.6479C9.01514 15.9387 9.74646 16.0859 10.5006 16.0859C11.2548 16.0859 11.9861 15.9387 12.6756 15.6467C13.3409 15.3648 13.9389 14.9624 14.4518 14.4495C14.9647 13.9366 15.3685 13.3387 15.6491 12.6734C15.9398 11.9854 16.0871 11.2541 16.0871 10.5C16.0871 9.7459 15.9398 9.01465 15.6478 8.32529C15.3669 7.66166 14.9604 7.05857 14.4505 6.54922C13.9417 6.03876 13.3384 5.63215 12.6743 5.35205C11.9861 5.06133 11.2548 4.91406 10.5006 4.91406C10.248 4.91406 10.0436 4.70967 10.0436 4.45703C10.0436 4.20439 10.248 4 10.5006 4C11.378 4 12.2299 4.17139 13.0311 4.51035C13.8055 4.83789 14.5 5.30762 15.0968 5.9043C15.6935 6.50098 16.162 7.19668 16.4896 7.96982C16.8286 8.7709 17 9.62275 17 10.5C17 11.3772 16.8286 12.2291 16.4896 13.0302C16.1633 13.8046 15.6935 14.499 15.0968 15.0957C14.5 15.6924 13.8043 16.1608 13.0311 16.4884C12.2299 16.8286 11.378 17 10.5006 17Z"
|
15 |
+
fill="currentColor"
|
16 |
/>
|
17 |
</svg>
|
frontend/src/lib/PaintCanvas.svelte
CHANGED
@@ -12,8 +12,8 @@
|
|
12 |
const myPresence = useMyPresence();
|
13 |
const promptImgStorage = useObject('promptImgStorage');
|
14 |
|
15 |
-
const height = 512 *
|
16 |
-
const width = 512 *
|
17 |
|
18 |
let containerEl: HTMLDivElement;
|
19 |
let canvasCtx: CanvasRenderingContext2D;
|
|
|
12 |
const myPresence = useMyPresence();
|
13 |
const promptImgStorage = useObject('promptImgStorage');
|
14 |
|
15 |
+
const height = 512 * 5;
|
16 |
+
const width = 512 * 5;
|
17 |
|
18 |
let containerEl: HTMLDivElement;
|
19 |
let canvasCtx: CanvasRenderingContext2D;
|
frontend/src/lib/PaintFrame.svelte
CHANGED
@@ -35,8 +35,8 @@
|
|
35 |
let dragEnabled = true;
|
36 |
let isDragging = false;
|
37 |
$: prompt = $myPresence?.currentPrompt;
|
38 |
-
$: isLoading = $myPresence?.status === Status.loading || false;
|
39 |
-
|
40 |
$: coord = {
|
41 |
x: transform.applyX(position.x),
|
42 |
y: transform.applyY(position.y)
|
@@ -95,6 +95,7 @@
|
|
95 |
let lastx: number;
|
96 |
let lasty: number;
|
97 |
function dragstarted(event: Event) {
|
|
|
98 |
const x = event.x / transform.k;
|
99 |
const y = event.y / transform.k;
|
100 |
lastx = x;
|
@@ -102,6 +103,7 @@
|
|
102 |
}
|
103 |
|
104 |
function dragged(event: Event) {
|
|
|
105 |
const x = event.x / transform.k;
|
106 |
const y = event.y / transform.k;
|
107 |
drawLine({ x, y, lastx, lasty });
|
@@ -114,6 +116,8 @@
|
|
114 |
}
|
115 |
function dragMoveHandler() {
|
116 |
function dragstarted(event: Event) {
|
|
|
|
|
117 |
const rect = (event.sourceEvent.target as HTMLElement).getBoundingClientRect();
|
118 |
if (event.sourceEvent instanceof TouchEvent) {
|
119 |
offsetX = event.sourceEvent.targetTouches[0].pageX - rect.left;
|
@@ -126,6 +130,8 @@
|
|
126 |
}
|
127 |
|
128 |
function dragged(event: Event) {
|
|
|
|
|
129 |
const x = round(transform.invertX(event.x - offsetX));
|
130 |
const y = round(transform.invertY(event.y - offsetY));
|
131 |
position = {
|
@@ -142,6 +148,8 @@
|
|
142 |
}
|
143 |
|
144 |
function dragended(event: Event) {
|
|
|
|
|
145 |
isDragging = false;
|
146 |
|
147 |
const x = round(transform.invertX(event.x - offsetX));
|
@@ -184,34 +192,33 @@
|
|
184 |
<div class="frame">
|
185 |
<canvas class={dragEnabled ? '' : 'bg-white'} bind:this={$maskEl} width="512" height="512" />
|
186 |
<div class="pointer-events-none touch-none">
|
187 |
-
{#if
|
188 |
-
<div class="
|
189 |
-
<
|
190 |
-
|
191 |
-
|
192 |
-
{#if isLoading}
|
193 |
-
<div class="col-start-2 row-start-2">
|
194 |
-
<LoadingIcon />
|
195 |
</div>
|
196 |
{/if}
|
197 |
-
|
198 |
-
<h2 class="text-lg" />
|
199 |
-
<div class="absolute bottom-0 font-bold text-lg">{prompt}</div>
|
200 |
</div>
|
|
|
|
|
|
|
|
|
|
|
201 |
{#if !isDragging}
|
202 |
<div class="absolute top-full ">
|
203 |
<div class="py-2">
|
204 |
-
<PPButton on:click={() => dispatch('prompt')} />
|
205 |
</div>
|
206 |
</div>
|
207 |
<div class="absolute left-full bottom-0">
|
208 |
<div class="px-2">
|
209 |
-
<DragButton isActive={dragEnabled} on:click={toggleDrag} />
|
210 |
<div class="flex bg-white rounded-full mt-3">
|
211 |
-
<MaskButton isActive={!dragEnabled} on:click={toggleDrawMask} />
|
212 |
{#if !dragEnabled}
|
213 |
<span class="border-gray-800 border-opacity-50 border-r-2 my-2" />
|
214 |
-
<UndoButton on:click={cleanMask} />
|
215 |
{/if}
|
216 |
</div>
|
217 |
</div>
|
@@ -229,7 +236,7 @@
|
|
229 |
|
230 |
<style lang="postcss" scoped>
|
231 |
.frame {
|
232 |
-
@apply relative grid grid-cols-3 grid-rows-3 ring-8 ring-
|
233 |
}
|
234 |
.hand {
|
235 |
cursor: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAAUCAYAAABvVQZ0AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAHSSURBVHgBzVQ9LENRFD4VozZWP4ku/jqJAYNoEQaWNpEwIYJFBINY6UCn6mKTKhYNSTuwVFBiaEgai9bP4CWKUftqv845vU+k7evr2C/5cu6799zvnHvOvQ+gUmEqNimEsKLZQ3YgA0j6TiNXeJPJlIZygEK1yFAmo4rj0Kkg0Jj4DyHyMxKyIt/I+zH5LJrau8V76lPMLa6KjU2vyKhZsbHl1YTX8/dX5X071eyPdX5xDRrr68BiNsNJ+AxsrS1sCf6DIEQub2hoNxJjxO7ivHnMNZqzzlHAIJBIvkBPV6cm7JC11RULWMw1LELRhwf6IPXxxSSRyMU1ztk5mKpmyX9aV0x2KUoitMHW1sxHjd3HWYQyGh7sY1+Z3ZTRMfcpCxLxHwZhZnIc63TEC3TU3iEXj2XdqGGOomKyBhxNq1fi6ZVF3J5tyK+rPGqHXmZX6OAgR61eVCc9UBDE332rzlu3uj0+WRs7GKGxoY5MWi8zZWZygp1KZUSg6yIR1RNzYQeV2/MQLC/MQqmM5HoYb8CDNl/w0GUTlpFLVDPfzi5myZ0DW3szX5Ex5whYLGYFp/pRTAEjyHcaFoX4RvqKPXRTOaJoHJDrmoKMlv0Lqhj8AlEeE/77ZUZMAAAAAElFTkSuQmCC')
|
|
|
35 |
let dragEnabled = true;
|
36 |
let isDragging = false;
|
37 |
$: prompt = $myPresence?.currentPrompt;
|
38 |
+
$: isLoading = $myPresence?.status === Status.loading || $myPresence?.status === Status.prompting || false;
|
39 |
+
|
40 |
$: coord = {
|
41 |
x: transform.applyX(position.x),
|
42 |
y: transform.applyY(position.y)
|
|
|
95 |
let lastx: number;
|
96 |
let lasty: number;
|
97 |
function dragstarted(event: Event) {
|
98 |
+
if (isLoading) return;
|
99 |
const x = event.x / transform.k;
|
100 |
const y = event.y / transform.k;
|
101 |
lastx = x;
|
|
|
103 |
}
|
104 |
|
105 |
function dragged(event: Event) {
|
106 |
+
if (isLoading) return;
|
107 |
const x = event.x / transform.k;
|
108 |
const y = event.y / transform.k;
|
109 |
drawLine({ x, y, lastx, lasty });
|
|
|
116 |
}
|
117 |
function dragMoveHandler() {
|
118 |
function dragstarted(event: Event) {
|
119 |
+
if (isLoading) return;
|
120 |
+
|
121 |
const rect = (event.sourceEvent.target as HTMLElement).getBoundingClientRect();
|
122 |
if (event.sourceEvent instanceof TouchEvent) {
|
123 |
offsetX = event.sourceEvent.targetTouches[0].pageX - rect.left;
|
|
|
130 |
}
|
131 |
|
132 |
function dragged(event: Event) {
|
133 |
+
if (isLoading) return;
|
134 |
+
|
135 |
const x = round(transform.invertX(event.x - offsetX));
|
136 |
const y = round(transform.invertY(event.y - offsetY));
|
137 |
position = {
|
|
|
148 |
}
|
149 |
|
150 |
function dragended(event: Event) {
|
151 |
+
if (isLoading) return;
|
152 |
+
|
153 |
isDragging = false;
|
154 |
|
155 |
const x = round(transform.invertX(event.x - offsetX));
|
|
|
192 |
<div class="frame">
|
193 |
<canvas class={dragEnabled ? '' : 'bg-white'} bind:this={$maskEl} width="512" height="512" />
|
194 |
<div class="pointer-events-none touch-none">
|
195 |
+
{#if prompt}
|
196 |
+
<div class="pointer-events-none touch-none">
|
197 |
+
<div class="font-bold text-xl text-[#387CFF] text-center px-2 line-clamp-4">
|
198 |
+
{prompt}
|
199 |
+
</div>
|
|
|
|
|
|
|
200 |
</div>
|
201 |
{/if}
|
|
|
|
|
|
|
202 |
</div>
|
203 |
+
{#if isLoading}
|
204 |
+
<div class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2">
|
205 |
+
<LoadingIcon />
|
206 |
+
</div>
|
207 |
+
{/if}
|
208 |
{#if !isDragging}
|
209 |
<div class="absolute top-full ">
|
210 |
<div class="py-2">
|
211 |
+
<PPButton {isLoading} on:click={() => dispatch('prompt')} />
|
212 |
</div>
|
213 |
</div>
|
214 |
<div class="absolute left-full bottom-0">
|
215 |
<div class="px-2">
|
216 |
+
<DragButton {isLoading} isActive={dragEnabled} on:click={toggleDrag} />
|
217 |
<div class="flex bg-white rounded-full mt-3">
|
218 |
+
<MaskButton {isLoading} isActive={!dragEnabled} on:click={toggleDrawMask} />
|
219 |
{#if !dragEnabled}
|
220 |
<span class="border-gray-800 border-opacity-50 border-r-2 my-2" />
|
221 |
+
<UndoButton {isLoading} on:click={cleanMask} />
|
222 |
{/if}
|
223 |
</div>
|
224 |
</div>
|
|
|
236 |
|
237 |
<style lang="postcss" scoped>
|
238 |
.frame {
|
239 |
+
@apply relative grid grid-cols-3 grid-rows-3 ring-8 ring-[#387CFF] w-[512px] h-[512px];
|
240 |
}
|
241 |
.hand {
|
242 |
cursor: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAAUCAYAAABvVQZ0AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAHSSURBVHgBzVQ9LENRFD4VozZWP4ku/jqJAYNoEQaWNpEwIYJFBINY6UCn6mKTKhYNSTuwVFBiaEgai9bP4CWKUftqv845vU+k7evr2C/5cu6799zvnHvOvQ+gUmEqNimEsKLZQ3YgA0j6TiNXeJPJlIZygEK1yFAmo4rj0Kkg0Jj4DyHyMxKyIt/I+zH5LJrau8V76lPMLa6KjU2vyKhZsbHl1YTX8/dX5X071eyPdX5xDRrr68BiNsNJ+AxsrS1sCf6DIEQub2hoNxJjxO7ivHnMNZqzzlHAIJBIvkBPV6cm7JC11RULWMw1LELRhwf6IPXxxSSRyMU1ztk5mKpmyX9aV0x2KUoitMHW1sxHjd3HWYQyGh7sY1+Z3ZTRMfcpCxLxHwZhZnIc63TEC3TU3iEXj2XdqGGOomKyBhxNq1fi6ZVF3J5tyK+rPGqHXmZX6OAgR61eVCc9UBDE332rzlu3uj0+WRs7GKGxoY5MWi8zZWZygp1KZUSg6yIR1RNzYQeV2/MQLC/MQqmM5HoYb8CDNl/w0GUTlpFLVDPfzi5myZ0DW3szX5Ex5whYLGYFp/pRTAEjyHcaFoX4RvqKPXRTOaJoHJDrmoKMlv0Lqhj8AlEeE/77ZUZMAAAAAElFTkSuQmCC')
|