Spaces:
Runtime error
Runtime error
menu
Browse files- frontend/src/app.html +2 -1
- frontend/src/lib/App.svelte +44 -30
- frontend/src/lib/Canvas.svelte +45 -24
- frontend/src/lib/Frame.svelte +32 -0
- frontend/src/lib/Menu.svelte +39 -0
- frontend/src/lib/store.ts +2 -19
- frontend/src/routes/+page.svelte +2 -7
- frontend/vite.config.dev.ts +1 -1
- package.json +3 -0
frontend/src/app.html
CHANGED
@@ -7,7 +7,8 @@
|
|
7 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.3.1/iframeResizer.contentWindow.min.js"></script>
|
8 |
%sveltekit.head%
|
9 |
</head>
|
10 |
-
<body class="dark:bg-[rgb(11,15,25)] bg-white dark:text-white text-black">
|
|
|
11 |
<div>%sveltekit.body%</div>
|
12 |
</body>
|
13 |
</html>
|
|
|
7 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/4.3.1/iframeResizer.contentWindow.min.js"></script>
|
8 |
%sveltekit.head%
|
9 |
</head>
|
10 |
+
<!-- <body class="dark:bg-[rgb(11,15,25)] bg-white dark:text-white text-black"> -->
|
11 |
+
<body>
|
12 |
<div>%sveltekit.body%</div>
|
13 |
</body>
|
14 |
</html>
|
frontend/src/lib/App.svelte
CHANGED
@@ -1,8 +1,12 @@
|
|
1 |
<script lang="ts">
|
2 |
import Cursor from '$lib/Cursor.svelte';
|
|
|
3 |
import Canvas from '$lib/Canvas.svelte';
|
|
|
4 |
import type { Room } from '@liveblocks/client';
|
5 |
import { onDestroy } from 'svelte';
|
|
|
|
|
6 |
/**
|
7 |
* The main Liveblocks code for the example.
|
8 |
* Check in src/routes/index.svelte to see the setup code.
|
@@ -15,13 +19,13 @@
|
|
15 |
let others = room.getOthers();
|
16 |
|
17 |
// Subscribe to further changes
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
|
26 |
// Unsubscribe when unmounting
|
27 |
onDestroy(() => {
|
@@ -34,8 +38,8 @@
|
|
34 |
event.preventDefault();
|
35 |
room.updatePresence({
|
36 |
cursor: {
|
37 |
-
x: Math.round(event.
|
38 |
-
y: Math.round(event.
|
39 |
}
|
40 |
});
|
41 |
}
|
@@ -59,31 +63,41 @@
|
|
59 |
];
|
60 |
</script>
|
61 |
|
62 |
-
<
|
63 |
-
|
64 |
-
|
65 |
-
{myPresence?.cursor
|
66 |
-
? `${myPresence.cursor.x} × ${myPresence.cursor.y}`
|
67 |
-
: 'Move your cursor to broadcast its position to other people in the room.'}
|
68 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
69 |
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
|
|
|
|
|
|
|
|
|
|
84 |
|
85 |
-
<Canvas />
|
86 |
-
<h3 class="text-xl">TESTS</h3>
|
87 |
<style lang="postcss" scoped>
|
88 |
main {
|
89 |
/* @apply fixed top-0 left-0 w-screen h-screen flex flex-col items-center justify-center touch-none bg-white; */
|
|
|
1 |
<script lang="ts">
|
2 |
import Cursor from '$lib/Cursor.svelte';
|
3 |
+
import Frame from '$lib/Frame.svelte';
|
4 |
import Canvas from '$lib/Canvas.svelte';
|
5 |
+
import Menu from '$lib/Menu.svelte';
|
6 |
import type { Room } from '@liveblocks/client';
|
7 |
import { onDestroy } from 'svelte';
|
8 |
+
import { currZoomTransform } from '$lib/store';
|
9 |
+
|
10 |
/**
|
11 |
* The main Liveblocks code for the example.
|
12 |
* Check in src/routes/index.svelte to see the setup code.
|
|
|
19 |
let others = room.getOthers();
|
20 |
|
21 |
// Subscribe to further changes
|
22 |
+
const unsubscribeMyPresence = room.subscribe('my-presence', (presence) => {
|
23 |
+
myPresence = presence;
|
24 |
+
});
|
25 |
|
26 |
+
const unsubscribeOthers = room.subscribe('others', (otherUsers) => {
|
27 |
+
others = otherUsers;
|
28 |
+
});
|
29 |
|
30 |
// Unsubscribe when unmounting
|
31 |
onDestroy(() => {
|
|
|
38 |
event.preventDefault();
|
39 |
room.updatePresence({
|
40 |
cursor: {
|
41 |
+
x: Math.round(event.layerX),
|
42 |
+
y: Math.round(event.layerY)
|
43 |
}
|
44 |
});
|
45 |
}
|
|
|
63 |
];
|
64 |
</script>
|
65 |
|
66 |
+
<div class="relative">
|
67 |
+
<div class="z-0">
|
68 |
+
<h3 class="text-xl">TESTS</h3>
|
|
|
|
|
|
|
69 |
</div>
|
70 |
+
<main class="z-10 relative">
|
71 |
+
<!-- Show the current user's cursor location -->
|
72 |
+
<div class="text">
|
73 |
+
{myPresence?.cursor
|
74 |
+
? `${myPresence.cursor.x} × ${myPresence.cursor.y}`
|
75 |
+
: 'Move your cursor to broadcast its position to other people in the room.'}
|
76 |
+
</div>
|
77 |
+
{#if myPresence?.cursor}
|
78 |
+
<Frame x={myPresence.cursor.x} y={myPresence.cursor.y} transform={$currZoomTransform} />
|
79 |
+
{/if}
|
80 |
|
81 |
+
<!-- When others connected, iterate through others and show their cursors -->
|
82 |
+
{#if others}
|
83 |
+
{#each [...others] as { connectionId, presence } (connectionId)}
|
84 |
+
{#if presence?.cursor}
|
85 |
+
<Cursor
|
86 |
+
color={COLORS[connectionId % COLORS.length]}
|
87 |
+
x={presence.cursor.x}
|
88 |
+
y={presence.cursor.y}
|
89 |
+
/>
|
90 |
+
<Frame x={presence.cursor.x} y={presence.cursor.y} transform={$currZoomTransform} />
|
91 |
+
{/if}
|
92 |
+
{/each}
|
93 |
+
{/if}
|
94 |
+
<Canvas />
|
95 |
+
</main>
|
96 |
+
</div>
|
97 |
+
<div class="fixed bottom-0 left-0 right-0 z-50">
|
98 |
+
<Menu />
|
99 |
+
</div>
|
100 |
|
|
|
|
|
101 |
<style lang="postcss" scoped>
|
102 |
main {
|
103 |
/* @apply fixed top-0 left-0 w-screen h-screen flex flex-col items-center justify-center touch-none bg-white; */
|
frontend/src/lib/Canvas.svelte
CHANGED
@@ -1,47 +1,68 @@
|
|
1 |
<script lang="ts">
|
2 |
-
import { zoom, zoomIdentity } from 'd3-zoom';
|
3 |
-
import { select
|
4 |
-
import { onMount
|
5 |
-
|
6 |
-
const
|
7 |
-
const
|
8 |
|
9 |
let canvasEl: HTMLCanvasElement;
|
|
|
10 |
let canvasCtx: CanvasRenderingContext2D;
|
11 |
|
12 |
-
|
|
|
|
|
|
|
13 |
const extent = [
|
14 |
-
[margin.left, margin.top],
|
15 |
-
[width
|
16 |
] as [[number, number], [number, number]];
|
17 |
-
|
18 |
-
const zoomHandler = zoom()
|
19 |
-
.scaleExtent([0.5, 2])
|
20 |
-
// .translateExtent(extent)
|
21 |
-
.extent(extent)
|
22 |
-
.on('zoom', zoomed);
|
23 |
-
|
24 |
onMount(() => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
select(canvasEl.parentElement)
|
26 |
.call(zoomHandler as any)
|
27 |
-
.call(zoomHandler.
|
|
|
|
|
|
|
28 |
canvasCtx = canvasEl.getContext('2d') as CanvasRenderingContext2D;
|
29 |
canvasCtx.fillStyle = 'red';
|
30 |
-
canvasCtx.rect(
|
31 |
canvasCtx.fill();
|
|
|
|
|
|
|
32 |
});
|
33 |
|
34 |
function zoomed(e: Event) {
|
35 |
-
const transform = e.transform;
|
36 |
console.log(canvasEl.style.transform, transform);
|
37 |
-
|
38 |
-
|
39 |
-
|
|
|
|
|
|
|
|
|
40 |
}
|
41 |
</script>
|
42 |
|
43 |
-
<div
|
44 |
-
|
|
|
|
|
|
|
45 |
</div>
|
46 |
|
47 |
<style lang="postcss" scoped>
|
|
|
1 |
<script lang="ts">
|
2 |
+
import { zoom, type ZoomTransform, zoomIdentity } from 'd3-zoom';
|
3 |
+
import { select } from 'd3-selection';
|
4 |
+
import { onMount } from 'svelte';
|
5 |
+
import { currZoomTransform } from '$lib/store';
|
6 |
+
const height = 512 * 5;
|
7 |
+
const width = 512 * 5;
|
8 |
|
9 |
let canvasEl: HTMLCanvasElement;
|
10 |
+
let containerEl: HTMLDivElement;
|
11 |
let canvasCtx: CanvasRenderingContext2D;
|
12 |
|
13 |
+
$:{
|
14 |
+
console.log($currZoomTransform)
|
15 |
+
}
|
16 |
+
const margin = { top: 100, right: 100, bottom: 100, left: 100 };
|
17 |
const extent = [
|
18 |
+
[-margin.left, -margin.top],
|
19 |
+
[width + margin.right, height + margin.bottom]
|
20 |
] as [[number, number], [number, number]];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
onMount(() => {
|
22 |
+
const scale = width / containerEl.clientWidth;
|
23 |
+
const zoomHandler = zoom()
|
24 |
+
.scaleExtent([1 / scale / 2, 2])
|
25 |
+
.translateExtent([
|
26 |
+
[0, 0],
|
27 |
+
[width, height]
|
28 |
+
])
|
29 |
+
// .translateExtent(extent)
|
30 |
+
.clickDistance(2)
|
31 |
+
.on('zoom', zoomed);
|
32 |
+
|
33 |
select(canvasEl.parentElement)
|
34 |
.call(zoomHandler as any)
|
35 |
+
.call(zoomHandler.scaleTo as any, 1 / scale)
|
36 |
+
.on('pointermove', handlePointerMove)
|
37 |
+
.on('pointerleave', handlePointerLeave);
|
38 |
+
|
39 |
canvasCtx = canvasEl.getContext('2d') as CanvasRenderingContext2D;
|
40 |
canvasCtx.fillStyle = 'red';
|
41 |
+
canvasCtx.rect(10, 10, 160, 90);
|
42 |
canvasCtx.fill();
|
43 |
+
canvasCtx.strokeStyle = 'blue';
|
44 |
+
canvasCtx.lineWidth = 5;
|
45 |
+
canvasCtx.strokeRect(0, 0, width, height);
|
46 |
});
|
47 |
|
48 |
function zoomed(e: Event) {
|
49 |
+
const transform = ($currZoomTransform = e.transform);
|
50 |
console.log(canvasEl.style.transform, transform);
|
51 |
+
canvasEl.style.transform = `translate(${transform.x}px, ${transform.y}px) scale(${transform.k})`;
|
52 |
+
}
|
53 |
+
function handlePointerMove(e: PointerEvent) {
|
54 |
+
// console.log(e);
|
55 |
+
}
|
56 |
+
function handlePointerLeave(e: PointerEvent) {
|
57 |
+
// console.log(e);
|
58 |
}
|
59 |
</script>
|
60 |
|
61 |
+
<div
|
62 |
+
bind:this={containerEl}
|
63 |
+
class="fixed w-screen h-screen top-0 left-0 overflow-hidden border-4 border-black"
|
64 |
+
>
|
65 |
+
<canvas bind:this={canvasEl} {width} {height} class="absolute top-0 left-0" />
|
66 |
</div>
|
67 |
|
68 |
<style lang="postcss" scoped>
|
frontend/src/lib/Frame.svelte
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
import { spring } from 'svelte/motion';
|
3 |
+
import type { ZoomTransform } from 'd3-zoom';
|
4 |
+
|
5 |
+
export let transform: ZoomTransform;
|
6 |
+
export let color = '';
|
7 |
+
export let x = 0;
|
8 |
+
export let y = 0;
|
9 |
+
|
10 |
+
// Spring animation for cursor
|
11 |
+
const coords = spring(
|
12 |
+
{ x, y },
|
13 |
+
{
|
14 |
+
stiffness: 0.07,
|
15 |
+
damping: 0.35
|
16 |
+
}
|
17 |
+
);
|
18 |
+
// Update spring when x and y change
|
19 |
+
$: coords.set({ x, y });
|
20 |
+
</script>
|
21 |
+
|
22 |
+
<div
|
23 |
+
class="frame"
|
24 |
+
style={`transform: translateX(${$coords.x}px) translateY(${$coords.y}px) scale(${transform.k})`}
|
25 |
+
/>
|
26 |
+
|
27 |
+
<style lang="postcss" scoped>
|
28 |
+
.frame {
|
29 |
+
@apply absolute top-0 left-0 border-2 border-sky-500 bg-gradient-to-b from-sky-200 w-[512px] h-[512px];
|
30 |
+
transform-origin: 0 0;
|
31 |
+
}
|
32 |
+
</style>
|
frontend/src/lib/Menu.svelte
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
import { currZoomTransform } from '$lib/store';
|
3 |
+
</script>
|
4 |
+
|
5 |
+
<div class="grid grid-cols-3 gap-3 text-sm w-max mx-auto">
|
6 |
+
<div class="flex items-center">
|
7 |
+
<input
|
8 |
+
id="showframes"
|
9 |
+
type="checkbox"
|
10 |
+
class="w-4 h-4 text-blue-600 bg-gray-100 rounded border-gray-300 focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600 cursor-pointer"
|
11 |
+
/>
|
12 |
+
<label for="showframes" class="text-black dark:text-white cursor-pointer ml-2"
|
13 |
+
>Show Frames</label
|
14 |
+
>
|
15 |
+
</div>
|
16 |
+
<button class="button" title="Add Prompt"> Add Prompt </button>
|
17 |
+
<button class="button-paint bg-violet-100 text-violet-900" title="New Paint Frame">
|
18 |
+
<span
|
19 |
+
class="rounded-sm h-5 w-5 m-1 flex justify-center items-center border-2 border-dashed border-violet-700 mr-2"
|
20 |
+
>+</span
|
21 |
+
>
|
22 |
+
Paint
|
23 |
+
</button>
|
24 |
+
</div>
|
25 |
+
|
26 |
+
<style lang="postcss" scoped>
|
27 |
+
.link {
|
28 |
+
@apply text-xs underline font-bold hover:no-underline hover:text-gray-500 visited:text-gray-500;
|
29 |
+
}
|
30 |
+
.input {
|
31 |
+
@apply disabled:opacity-50 italic dark:placeholder:text-black placeholder:text-white text-white dark:text-black placeholder:text-opacity-30 dark:placeholder:text-opacity-10 dark:bg-white bg-slate-900 border-2 border-black rounded-2xl px-2 shadow-sm focus:outline-none focus:border-gray-400 focus:ring-1;
|
32 |
+
}
|
33 |
+
.button {
|
34 |
+
@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;
|
35 |
+
}
|
36 |
+
.button-paint {
|
37 |
+
@apply flex justify-center items-center disabled:opacity-50 dark:bg-white dark:text-black rounded-2xl shadow-sm focus:outline-none focus:border-gray-400;
|
38 |
+
}
|
39 |
+
</style>
|
frontend/src/lib/store.ts
CHANGED
@@ -1,24 +1,7 @@
|
|
1 |
import { writable } from 'svelte/store';
|
2 |
-
import type
|
3 |
-
import { browser } from '$app/environment';
|
4 |
|
5 |
export const loadingState = writable<string>('');
|
6 |
export const isLoading = writable<boolean>(false);
|
7 |
|
8 |
-
|
9 |
-
if (typeof crypto['randomUUID'] === 'undefined') {
|
10 |
-
initialUser = (1e7 + '').replace(/\d/g, (c) =>
|
11 |
-
(c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16)
|
12 |
-
);
|
13 |
-
} else {
|
14 |
-
initialUser = crypto.randomUUID();
|
15 |
-
}
|
16 |
-
|
17 |
-
export const currentUser = writable<User>(
|
18 |
-
browser ? JSON.parse(localStorage['user'] || JSON.stringify(initialUser)) : initialUser
|
19 |
-
);
|
20 |
-
currentUser.subscribe((value) => {
|
21 |
-
if (browser) {
|
22 |
-
return (localStorage['user'] = JSON.stringify(value));
|
23 |
-
}
|
24 |
-
});
|
|
|
1 |
import { writable } from 'svelte/store';
|
2 |
+
import { type ZoomTransform, zoomIdentity } from 'd3-zoom';
|
|
|
3 |
|
4 |
export const loadingState = writable<string>('');
|
5 |
export const isLoading = writable<boolean>(false);
|
6 |
|
7 |
+
export const currZoomTransform = writable<ZoomTransform>(zoomIdentity);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/src/routes/+page.svelte
CHANGED
@@ -4,7 +4,6 @@
|
|
4 |
import { PUBLIC_WS_ENDPOINT, PUBLIC_DEV_MODE } from '$env/static/public';
|
5 |
import type { Client, Room } from '@liveblocks/client';
|
6 |
import { createClient } from '@liveblocks/client';
|
7 |
-
import { currentUser } from '$lib/store';
|
8 |
|
9 |
import App from '$lib/App.svelte';
|
10 |
import type { Presence, Storage } from '$lib/types';
|
@@ -14,17 +13,14 @@
|
|
14 |
? 'http://localhost:7860'
|
15 |
: '/embed/huggingface-projects/color-palette-generator-sd';
|
16 |
console.log(apiUrl);
|
|
|
17 |
let client: Client;
|
18 |
let room: Room;
|
19 |
let roomId = 'sveltekit-live-cursors';
|
20 |
|
21 |
-
$: {
|
22 |
-
console.log('whoami', $currentUser);
|
23 |
-
}
|
24 |
-
|
25 |
onMount(() => {
|
26 |
client = createClient({
|
27 |
-
publicApiKey: '
|
28 |
});
|
29 |
|
30 |
room = client.enter<Presence, Storage /* UserMeta, RoomEvent */>(roomId, {
|
@@ -33,7 +29,6 @@
|
|
33 |
},
|
34 |
initialStorage: {}
|
35 |
});
|
36 |
-
console.log('room', room);
|
37 |
return () => {
|
38 |
if (client && room) {
|
39 |
client.leave(roomId);
|
|
|
4 |
import { PUBLIC_WS_ENDPOINT, PUBLIC_DEV_MODE } from '$env/static/public';
|
5 |
import type { Client, Room } from '@liveblocks/client';
|
6 |
import { createClient } from '@liveblocks/client';
|
|
|
7 |
|
8 |
import App from '$lib/App.svelte';
|
9 |
import type { Presence, Storage } from '$lib/types';
|
|
|
13 |
? 'http://localhost:7860'
|
14 |
: '/embed/huggingface-projects/color-palette-generator-sd';
|
15 |
console.log(apiUrl);
|
16 |
+
|
17 |
let client: Client;
|
18 |
let room: Room;
|
19 |
let roomId = 'sveltekit-live-cursors';
|
20 |
|
|
|
|
|
|
|
|
|
21 |
onMount(() => {
|
22 |
client = createClient({
|
23 |
+
publicApiKey: 'pk_test_JlUZGH3kQmhmZQiqU2l8eIi5'
|
24 |
});
|
25 |
|
26 |
room = client.enter<Presence, Storage /* UserMeta, RoomEvent */>(roomId, {
|
|
|
29 |
},
|
30 |
initialStorage: {}
|
31 |
});
|
|
|
32 |
return () => {
|
33 |
if (client && room) {
|
34 |
client.leave(roomId);
|
frontend/vite.config.dev.ts
CHANGED
@@ -4,7 +4,7 @@ import type { UserConfig } from 'vite';
|
|
4 |
const config: UserConfig = {
|
5 |
plugins: [sveltekit()],
|
6 |
server: {
|
7 |
-
host: "0.0.0.0",
|
8 |
proxy: {
|
9 |
'/moon': {
|
10 |
target: 'https://huggingface.co',
|
|
|
4 |
const config: UserConfig = {
|
5 |
plugins: [sveltekit()],
|
6 |
server: {
|
7 |
+
// host: "0.0.0.0",
|
8 |
proxy: {
|
9 |
'/moon': {
|
10 |
target: 'https://huggingface.co',
|
package.json
CHANGED
@@ -1,5 +1,8 @@
|
|
1 |
{
|
2 |
"devDependencies": {
|
3 |
"@types/smoothscroll-polyfill": "^0.3.1"
|
|
|
|
|
|
|
4 |
}
|
5 |
}
|
|
|
1 |
{
|
2 |
"devDependencies": {
|
3 |
"@types/smoothscroll-polyfill": "^0.3.1"
|
4 |
+
},
|
5 |
+
"dependencies": {
|
6 |
+
"d3-scale": "^4.0.2"
|
7 |
}
|
8 |
}
|