radames commited on
Commit
70b8e47
·
unverified ·
1 Parent(s): 142f91b

liveblocks

Browse files
frontend/package.json CHANGED
@@ -36,6 +36,7 @@
36
  },
37
  "type": "module",
38
  "dependencies": {
39
- "@fontsource/fira-mono": "^4.5.0"
 
40
  }
41
  }
 
36
  },
37
  "type": "module",
38
  "dependencies": {
39
+ "@fontsource/fira-mono": "^4.5.0",
40
+ "@liveblocks/client": "^0.18.2"
41
  }
42
  }
frontend/src/lib/Canvas.svelte ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import Cursor from '$lib/Cursor.svelte';
3
+ import type { Room } from '@liveblocks/client';
4
+ import { onDestroy } from 'svelte';
5
+ /**
6
+ * The main Liveblocks code for the example.
7
+ * Check in src/routes/index.svelte to see the setup code.
8
+ */
9
+
10
+ export let room: Room;
11
+
12
+ // Get initial values for presence and others
13
+ let myPresence = room.getPresence();
14
+ let others = room.getOthers();
15
+
16
+ // Subscribe to further changes
17
+ const unsubscribeMyPresence = room.subscribe('my-presence', (presence) => {
18
+ myPresence = presence;
19
+ });
20
+
21
+ const unsubscribeOthers = room.subscribe('others', (otherUsers) => {
22
+ others = otherUsers;
23
+ });
24
+
25
+ // Unsubscribe when unmounting
26
+ onDestroy(() => {
27
+ unsubscribeMyPresence();
28
+ unsubscribeOthers();
29
+ });
30
+
31
+ // Update cursor presence to current pointer location
32
+ function handlePointerMove(event: PointerEvent) {
33
+ event.preventDefault();
34
+ room.updatePresence({
35
+ cursor: {
36
+ x: Math.round(event.clientX),
37
+ y: Math.round(event.clientY)
38
+ }
39
+ });
40
+ }
41
+
42
+ // When the pointer leaves the page, set cursor presence to null
43
+ function handlePointerLeave() {
44
+ room.updatePresence({
45
+ cursor: null
46
+ });
47
+ }
48
+
49
+ const COLORS = [
50
+ '#E57373',
51
+ '#9575CD',
52
+ '#4FC3F7',
53
+ '#81C784',
54
+ '#FFF176',
55
+ '#FF8A65',
56
+ '#F06292',
57
+ '#7986CB'
58
+ ];
59
+ </script>
60
+
61
+ <main on:pointerleave={handlePointerLeave} on:pointermove={handlePointerMove}>
62
+ <!-- Show the current user's cursor location -->
63
+ <div class="text">
64
+ {myPresence?.cursor
65
+ ? `${myPresence.cursor.x} × ${myPresence.cursor.y}`
66
+ : 'Move your cursor to broadcast its position to other people in the room.'}
67
+ </div>
68
+
69
+ <!-- When others connected, iterate through others and show their cursors -->
70
+ {#if others}
71
+ {#each [...others] as { connectionId, presence } (connectionId)}
72
+ {#if presence?.cursor}
73
+ <Cursor
74
+ color={COLORS[connectionId % COLORS.length]}
75
+ x={presence.cursor.x}
76
+ y={presence.cursor.y}
77
+ />
78
+ {/if}
79
+ {/each}
80
+ {/if}
81
+ </main>
82
+
83
+ <style lang="postcss" scoped>
84
+ main {
85
+ @apply fixed top-0 left-0 w-screen h-screen flex flex-col items-center justify-center touch-none bg-white;
86
+ /* position: absolute;
87
+ top: 0;
88
+ left: 0;
89
+ width: 100vw;
90
+ height: 100vh;
91
+ display: flex;
92
+ place-content: center;
93
+ place-items: center;
94
+ touch-action: none;
95
+ background-color: white; */
96
+ }
97
+
98
+ .text {
99
+ max-width: 380px;
100
+ margin: 0 16px;
101
+ text-align: center;
102
+ }
103
+ </style>
frontend/src/lib/Cursor.svelte ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { spring } from 'svelte/motion';
3
+
4
+ export let color = '';
5
+ export let x = 0;
6
+ export let y = 0;
7
+
8
+ // Spring animation for cursor
9
+ const coords = spring(
10
+ { x, y },
11
+ {
12
+ stiffness: 0.07,
13
+ damping: 0.35
14
+ }
15
+ );
16
+
17
+ // Update spring when x and y change
18
+ $: coords.set({ x, y });
19
+ </script>
20
+
21
+ <svg
22
+ class="cursor"
23
+ fill="none"
24
+ height="36"
25
+ style={`transform: translateX(${$coords.x}px) translateY(${$coords.y}px)`}
26
+ viewBox="0 0 24 36"
27
+ width="24"
28
+ xmlns="http://www.w3.org/2000/svg"
29
+ >
30
+ <path
31
+ d="M5.65376 12.3673H5.46026L5.31717 12.4976L0.500002 16.8829L0.500002 1.19841L11.7841 12.3673H5.65376Z"
32
+ fill={color}
33
+ />
34
+ </svg>
35
+
36
+ <style lang="postcss" scoped>
37
+ .cursor {
38
+ @apply absolute top-0 left-0;
39
+ }
40
+ </style>
frontend/src/lib/store.ts CHANGED
@@ -1,3 +1,17 @@
1
  import { writable } from 'svelte/store';
 
 
 
2
  export const loadingState = writable<string>('');
3
  export const isLoading = writable<boolean>(false);
 
 
 
 
 
 
 
 
 
 
 
 
1
  import { writable } from 'svelte/store';
2
+ import type { User } from '$lib/types';
3
+ import { browser } from '$app/environment';
4
+
5
  export const loadingState = writable<string>('');
6
  export const isLoading = writable<boolean>(false);
7
+
8
+ const initialUser: User = crypto.randomUUID();
9
+
10
+ export const currentUser = writable<User>(
11
+ browser ? JSON.parse(localStorage['user'] || JSON.stringify(initialUser)) : initialUser
12
+ );
13
+ currentUser.subscribe((value) => {
14
+ if (browser) {
15
+ return (localStorage['user'] = JSON.stringify(value));
16
+ }
17
+ });
frontend/src/lib/types.ts CHANGED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export type Presence = {
2
+ cursor: {
3
+ x: number;
4
+ y: number;
5
+ } | null;
6
+ };
7
+
8
+ export type Storage = {
9
+ // animals: LiveList<string>,
10
+ // ...
11
+ };
12
+
13
+ export type User = string;
frontend/src/lib/utils.ts CHANGED
@@ -39,4 +39,4 @@ function slugify(text: string) {
39
  .replace(/\-\-+/g, '-')
40
  .replace(/^-+/, '')
41
  .replace(/-+$/, '');
42
- }
 
39
  .replace(/\-\-+/g, '-')
40
  .replace(/^-+/, '')
41
  .replace(/-+$/, '');
42
+ }
frontend/src/routes/+page.svelte CHANGED
@@ -1,11 +1,45 @@
1
  <script lang="ts">
 
2
  import { isLoading, loadingState } from '$lib/store';
3
  import { PUBLIC_WS_ENDPOINT, PUBLIC_DEV_MODE } from '$env/static/public';
 
 
 
 
 
 
4
 
5
  const apiUrl =
6
  PUBLIC_DEV_MODE === 'DEV'
7
  ? 'http://localhost:7860'
8
  : '/embed/huggingface-projects/color-palette-generator-sd';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  </script>
10
 
11
  <div class="max-w-screen-md mx-auto px-3 py-8 relative z-0">
@@ -26,6 +60,11 @@
26
  </button>
27
  </form>
28
  </div>
 
 
 
 
 
29
  </div>
30
 
31
  <style lang="postcss" scoped>
 
1
  <script lang="ts">
2
+ import { onMount } from 'svelte';
3
  import { isLoading, loadingState } from '$lib/store';
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 Canvas from '$lib/Canvas.svelte';
10
+ import type { Presence, Storage } from '$lib/types';
11
 
12
  const apiUrl =
13
  PUBLIC_DEV_MODE === 'DEV'
14
  ? 'http://localhost:7860'
15
  : '/embed/huggingface-projects/color-palette-generator-sd';
16
+
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: 'pk_live_6o9jIg1m7lFJp5kc7HgYgE3S'
28
+ });
29
+
30
+ room = client.enter<Presence, Storage /* UserMeta, RoomEvent */>(roomId, {
31
+ initialPresence: {
32
+ cursor: null
33
+ },
34
+ initialStorage: {}
35
+ });
36
+ console.log('room', room);
37
+ return () => {
38
+ if (client && room) {
39
+ client.leave(roomId);
40
+ }
41
+ };
42
+ });
43
  </script>
44
 
45
  <div class="max-w-screen-md mx-auto px-3 py-8 relative z-0">
 
60
  </button>
61
  </form>
62
  </div>
63
+ <div class="relative">
64
+ {#if room}
65
+ <Canvas {room} />
66
+ {/if}
67
+ </div>
68
  </div>
69
 
70
  <style lang="postcss" scoped>