Skip to content

Commit 346fbb6

Browse files
committed
Add SvelteKit to create-app
1 parent f2f3479 commit 346fbb6

39 files changed

Lines changed: 1282 additions & 11 deletions

client/packages/create-instant-app/scripts/copyExamples.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { copyRespectingGitignore } from '../src/scaffold.js';
66
const EXAMPLES_TO_COPY = [
77
'expo',
88
'next-js-app-dir',
9+
'sveltekit',
910
'vite-vanilla',
1011
'tanstack-start',
1112
] as const;

client/packages/create-instant-app/src/cli.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export type Project = {
1414
| 'tanstack-start-with-tanstack-query'
1515
| 'bun-react'
1616
| 'solidjs-vite'
17+
| 'sveltekit'
1718
| 'vercel-ai-sdk'
1819
| 'ai-chat';
1920
ruleFiles:
@@ -76,6 +77,7 @@ export const runCli = async (): Promise<{
7677
'tanstack-start',
7778
'tanstack-start-with-tanstack-query',
7879
'solidjs-vite',
80+
'sveltekit',
7981
'vercel-ai-sdk',
8082
'ai-chat',
8183
]),
@@ -96,6 +98,9 @@ export const runCli = async (): Promise<{
9698
false,
9799
),
98100
)
101+
.addOption(
102+
new Option('--sv', 'Use the SvelteKit starter template').default(false),
103+
)
99104
.addOption(
100105
new Option('--no-git', "Don't create a git repo in the new project"),
101106
)
@@ -199,6 +204,9 @@ export const runCli = async (): Promise<{
199204
if (flags.expo) {
200205
return 'expo';
201206
}
207+
if (flags.sv) {
208+
return 'sveltekit';
209+
}
202210

203211
if (results.prompt) {
204212
return renderUnwrap(
@@ -243,6 +251,11 @@ export const runCli = async (): Promise<{
243251
label: 'Vite: SolidJS',
244252
secondary: true,
245253
},
254+
{
255+
value: 'sveltekit',
256+
label: 'SvelteKit',
257+
secondary: true,
258+
},
246259
{
247260
value: 'vercel-ai-sdk',
248261
label: 'Vercel AI SDK App Builder + SSR',

client/packages/create-instant-app/src/env.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const envNames: Record<Project['base'], string> = {
99
'tanstack-start': 'VITE_INSTANT_APP_ID',
1010
'bun-react': 'BUN_PUBLIC_INSTANT_APP_ID',
1111
'solidjs-vite': 'VITE_INSTANT_APP_ID',
12+
sveltekit: 'VITE_INSTANT_APP_ID',
1213
'tanstack-start-with-tanstack-query': 'VITE_INSTANT_APP_ID',
1314
'vercel-ai-sdk': 'NEXT_PUBLIC_INSTANT_APP_ID',
1415
'ai-chat': 'NEXT_PUBLIC_INSTANT_APP_ID',
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
<script lang="ts" generics="RoomSchema extends RoomSchemaShape, RoomType extends string & keyof RoomSchema">
2+
import type { RoomSchemaShape } from '@instantdb/core';
3+
import type { InstantSvelteRoom } from './InstantSvelteRoom.svelte.js';
4+
import { usePresence } from './InstantSvelteRoom.svelte.js';
5+
import type { Snippet } from 'svelte';
6+
7+
let {
8+
room,
9+
spaceId: _spaceId,
10+
as = 'div',
11+
className,
12+
style,
13+
userCursorColor,
14+
children,
15+
renderCursor,
16+
propagate,
17+
zIndex,
18+
}: {
19+
room: InstantSvelteRoom<any, RoomSchema, RoomType>;
20+
spaceId?: string;
21+
as?: string;
22+
className?: string;
23+
style?: string;
24+
userCursorColor?: string;
25+
children?: Snippet;
26+
renderCursor?: Snippet<[{ color: string; presence: RoomSchema[RoomType]['presence'] }]>;
27+
propagate?: boolean;
28+
zIndex?: number;
29+
} = $props();
30+
31+
const spaceId = _spaceId || `cursors-space-default--${String(room.type)}-${room.id}`;
32+
33+
const cursorsPresence = usePresence(room, {
34+
keys: [spaceId] as (keyof RoomSchema[RoomType]['presence'])[],
35+
});
36+
37+
function publishCursor(rect: DOMRect, touch: { clientX: number; clientY: number }) {
38+
const x = touch.clientX;
39+
const y = touch.clientY;
40+
const xPercent = ((x - rect.left) / rect.width) * 100;
41+
const yPercent = ((y - rect.top) / rect.height) * 100;
42+
cursorsPresence.publishPresence({
43+
[spaceId]: { x, y, xPercent, yPercent, color: userCursorColor },
44+
} as RoomSchema[RoomType]['presence']);
45+
}
46+
47+
function onMouseMove(e: MouseEvent) {
48+
if (!propagate) {
49+
e.stopPropagation();
50+
}
51+
const rect = (e.currentTarget as Element).getBoundingClientRect();
52+
publishCursor(rect, e);
53+
}
54+
55+
function onMouseOut() {
56+
cursorsPresence.publishPresence({
57+
[spaceId]: undefined,
58+
} as RoomSchema[RoomType]['presence']);
59+
}
60+
61+
function onTouchMove(e: TouchEvent) {
62+
if (e.touches.length !== 1) return;
63+
const touch = e.touches[0];
64+
if (touch.target instanceof Element) {
65+
if (!propagate) {
66+
e.stopPropagation();
67+
}
68+
const rect = touch.target.getBoundingClientRect();
69+
publishCursor(rect, touch);
70+
}
71+
}
72+
73+
function onTouchEnd() {
74+
cursorsPresence.publishPresence({
75+
[spaceId]: undefined,
76+
} as RoomSchema[RoomType]['presence']);
77+
}
78+
79+
const defaultZ = 99999;
80+
81+
const peers = $derived(Object.entries(cursorsPresence.peers));
82+
const fullPresence = $derived(
83+
room.core._reactor.getPresence(room.type, room.id),
84+
);
85+
</script>
86+
87+
<!-- svelte-ignore a11y_no_static_element_interactions -->
88+
<svelte:element
89+
this={as}
90+
class={className}
91+
style="position: relative; {style ?? ''}"
92+
onmousemove={onMouseMove}
93+
onmouseout={onMouseOut}
94+
ontouchmove={onTouchMove}
95+
ontouchend={onTouchEnd}
96+
>
97+
{#if children}
98+
{@render children()}
99+
{/if}
100+
<div
101+
style="position: absolute; top: 0; left: 0; bottom: 0; right: 0; overflow: hidden; pointer-events: none; user-select: none; z-index: {zIndex ?? defaultZ};"
102+
>
103+
{#each peers as [peerId, presence] (peerId)}
104+
{@const cursor = presence[spaceId]}
105+
{#if cursor}
106+
<div
107+
style="position: absolute; top: 0; left: 0; bottom: 0; right: 0; transform: translate({cursor.xPercent}%, {cursor.yPercent}%); transform-origin: 0 0; transition: transform 100ms;"
108+
>
109+
{#if renderCursor}
110+
{@render renderCursor({
111+
color: cursor.color,
112+
presence: fullPresence?.peers[peerId],
113+
})}
114+
{:else}
115+
{@const fill = cursor.color || 'black'}
116+
<svg
117+
style="height: 35px; width: 35px;"
118+
viewBox="0 0 35 35"
119+
fill="none"
120+
xmlns="http://www.w3.org/2000/svg"
121+
>
122+
<g
123+
fill="rgba(0,0,0,.2)"
124+
transform="matrix(1, 0, 0, 1, -11.999999046325684, -8.406899452209473)"
125+
>
126+
<path d="m12 24.4219v-16.015l11.591 11.619h-6.781l-.411.124z" />
127+
<path d="m21.0845 25.0962-3.605 1.535-4.682-11.089 3.686-1.553z" />
128+
</g>
129+
<g
130+
fill="white"
131+
transform="matrix(1, 0, 0, 1, -11.999999046325684, -8.406899452209473)"
132+
>
133+
<path d="m12 24.4219v-16.015l11.591 11.619h-6.781l-.411.124z" />
134+
<path d="m21.0845 25.0962-3.605 1.535-4.682-11.089 3.686-1.553z" />
135+
</g>
136+
<g
137+
fill={fill}
138+
transform="matrix(1, 0, 0, 1, -11.999999046325684, -8.406899452209473)"
139+
>
140+
<path d="m19.751 24.4155-1.844.774-3.1-7.374 1.841-.775z" />
141+
<path d="m13 10.814v11.188l2.969-2.866.428-.139h4.768z" />
142+
</g>
143+
</svg>
144+
{/if}
145+
</div>
146+
{/if}
147+
{/each}
148+
</div>
149+
</svelte:element>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<script lang="ts">
2+
import type { InstantSchemaDef } from '@instantdb/core';
3+
import type { InstantSvelteDatabase } from './InstantSvelteDatabase.svelte.js';
4+
import type { Snippet } from 'svelte';
5+
6+
let { db, children }: {
7+
db: InstantSvelteDatabase<InstantSchemaDef<any, any, any>>;
8+
children: Snippet;
9+
} = $props();
10+
11+
const auth = db.useAuth();
12+
</script>
13+
14+
{#if !auth.isLoading && !auth.error && auth.user}
15+
{@render children()}
16+
{/if}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<script lang="ts">
2+
import type { InstantSchemaDef } from '@instantdb/core';
3+
import type { InstantSvelteDatabase } from './InstantSvelteDatabase.svelte.js';
4+
import type { Snippet } from 'svelte';
5+
6+
let { db, children }: {
7+
db: InstantSvelteDatabase<InstantSchemaDef<any, any, any>>;
8+
children: Snippet;
9+
} = $props();
10+
11+
const auth = db.useAuth();
12+
</script>
13+
14+
{#if !auth.isLoading && !auth.user}
15+
{@render children()}
16+
{/if}

client/packages/svelte/src/lib/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ import {
9191
import { InstantSvelteDatabase } from './InstantSvelteDatabase.svelte.js';
9292
import { init } from './InstantSvelteDatabase.svelte.js';
9393
import { InstantSvelteRoom } from './InstantSvelteRoom.svelte.js';
94+
import SignedIn from './SignedIn.svelte';
95+
import SignedOut from './SignedOut.svelte';
96+
import Cursors from './Cursors.svelte';
9497

9598
export {
9699
id,
@@ -99,6 +102,9 @@ export {
99102
init,
100103
InstantSvelteDatabase,
101104
InstantSvelteRoom,
105+
SignedIn,
106+
SignedOut,
107+
Cursors,
102108
i,
103109

104110
// error

0 commit comments

Comments
 (0)