fix: update slot syntax and runes implementation

Co-Authored-By: charis@supabase.io <charis@supabase.io>
This commit is contained in:
Devin AIandcharis@supabase.io committed 2024-12-18 19:00:49 +00:00
1 parent 86eb85ebf2
commit ffd64ca486
4 files changed
+78 -74

No files matched your search

@@ -2,19 +2,19 @@
<script lang="ts">
import '../styles.css'
import { invalidate } from '$app/navigation'
import { state, effect, props } from 'svelte'
let $data;
let $supabase;
let $session;
let { data } = props()
let { supabase, session } = data
$effect(() => {
const { data } = $supabase.auth.onAuthStateChange((event, _session) => {
if (_session?.expires_at !== $session?.expires_at) {
effect(() => {
const { data: authData } = supabase.auth.onAuthStateChange((event, _session) => {
if (_session?.expires_at !== session?.expires_at) {
invalidate('supabase:auth')
}
})
return () => data.subscription.unsubscribe()
return () => authData.subscription.unsubscribe()
})
</script>
@@ -23,5 +23,5 @@
</svelte:head>
<div class="container" style="padding: 50px 0 100px 0">
{@render $$slots.default()}
<slot />
</div>
@@ -1,16 +1,17 @@
<!-- src/routes/+page.svelte -->
<script lang="ts">
import { enhance } from '$app/forms'
import { state, props } from 'svelte'
import type { ActionData, SubmitFunction } from './$types.js'
let $form: ActionData;
let $loading = $state(false);
let { form } = props<{ form: ActionData }>()
let loading = state(false)
const handleSubmit: SubmitFunction = () => {
$loading = true;
loading = true
return async ({ update }) => {
update();
$loading = false;
update()
loading = false
}
}
</script>
@@ -23,9 +24,9 @@
<div class="col-6 form-widget">
<h1 class="header">Supabase + SvelteKit</h1>
<p class="description">Sign in via magic link with your email below</p>
{#if $form?.message !== undefined}
<div class="success {$form?.success ? '' : 'fail'}">
{$form?.message}
{#if form?.message !== undefined}
<div class="success {form?.success ? '' : 'fail'}">
{form?.message}
</div>
{/if}
<div>
@@ -36,17 +37,17 @@
class="inputField"
type="email"
placeholder="Your email"
value={$form?.email ?? ''}
value={form?.email ?? ''}
/>
</div>
{#if $form?.errors?.email}
{#if form?.errors?.email}
<span class="flex items-center text-sm error">
{$form?.errors?.email}
{form?.errors?.email}
</span>
{/if}
<div>
<button class="button primary block">
{ $loading ? 'Loading' : 'Send magic link' }
{ loading ? 'Loading' : 'Send magic link' }
</button>
</div>
</div>
@@ -1,32 +1,32 @@
<!-- src/routes/account/+page.svelte -->
<script lang="ts">
import { enhance } from '$app/forms';
import type { SubmitFunction } from '@sveltejs/kit';
import Avatar from './Avatar.svelte'
import { enhance } from '$app/forms'
import { state, props } from 'svelte'
import type { SubmitFunction } from '@sveltejs/kit'
import Avatar from './Avatar.svelte'
let $data;
let $form;
let { session, supabase, profile } = $data;
let { data, form } = $props()
let { session, supabase, profile } = data
let $profileForm = $state<HTMLFormElement | null>(null);
let $loading = $state(false);
let $fullName = $state(profile?.full_name ?? '');
let $username = $state(profile?.username ?? '');
let $website = $state(profile?.website ?? '');
let $avatarUrl = $state(profile?.avatar_url ?? '');
let profileForm = $state<HTMLFormElement | null>(null)
let loading = $state(false)
let fullName = $state(profile?.full_name ?? '')
let username = $state(profile?.username ?? '')
let website = $state(profile?.website ?? '')
let avatarUrl = $state(profile?.avatar_url ?? '')
const handleSubmit: SubmitFunction = () => {
$loading = true;
loading = true
return async () => {
$loading = false;
loading = false
}
}
const handleSignOut: SubmitFunction = () => {
$loading = true;
loading = true
return async ({ update }) => {
$loading = false;
update();
loading = false
update()
}
}
</script>
@@ -37,14 +37,14 @@
method="post"
action="?/update"
use:enhance={handleSubmit}
bind:this={$profileForm}
bind:this={profileForm}
>
<Avatar
{supabase}
bind:url={$avatarUrl}
bind:url={avatarUrl}
size={10}
on:upload={() => {
$profileForm.requestSubmit();
profileForm.requestSubmit();
}}
/>
<div>
@@ -54,32 +54,32 @@
<div>
<label for="fullName">Full Name</label>
<input id="fullName" name="fullName" type="text" value={$form?.fullName ?? $fullName} />
<input id="fullName" name="fullName" type="text" value={form?.fullName ?? fullName} />
</div>
<div>
<label for="username">Username</label>
<input id="username" name="username" type="text" value={$form?.username ?? $username} />
<input id="username" name="username" type="text" value={form?.username ?? username} />
</div>
<div>
<label for="website">Website</label>
<input id="website" name="website" type="url" value={$form?.website ?? $website} />
<input id="website" name="website" type="url" value={form?.website ?? website} />
</div>
<div>
<input
type="submit"
class="button block primary"
value={$loading ? 'Loading...' : 'Update'}
disabled={$loading}
value={loading ? 'Loading...' : 'Update'}
disabled={loading}
/>
</div>
</form>
<form method="post" action="?/signout" use:enhance={handleSignOut}>
<div>
<button class="button block" disabled={$loading}>Sign Out</button>
<button class="button block" disabled={loading}>Sign Out</button>
</div>
</form>
</div>
@@ -2,27 +2,30 @@
<script lang="ts">
import type { SupabaseClient } from '@supabase/supabase-js'
import { createEventDispatcher } from 'svelte'
import { state, effect, props } from 'svelte'
let $size = $state(10);
let $url = $state('');
let $supabase: SupabaseClient;
let { size = 10, url = '', supabase } = props<{
size?: number
url: string
supabase: SupabaseClient
}>()
let $avatarUrl = $state<string | null>(null);
let $uploading = $state(false);
let $files = $state<FileList | null>(null);
let avatarUrl = state<string | null>(null)
let uploading = state(false)
let files = state<FileList | null>(null)
const dispatch = createEventDispatcher();
const dispatch = createEventDispatcher()
const downloadImage = async (path: string) => {
try {
const { data, error } = await $supabase.storage.from('avatars').download(path)
const { data: imageData, error } = await supabase.storage.from('avatars').download(path)
if (error) {
throw error
}
const url = URL.createObjectURL(data)
$avatarUrl = url
const imageUrl = URL.createObjectURL(imageData)
avatarUrl = imageUrl
} catch (error) {
if (error instanceof Error) {
console.log('Error downloading image: ', error.message)
@@ -32,23 +35,23 @@
const uploadAvatar = async () => {
try {
$uploading = true
uploading = true
if (!$files || $files.length === 0) {
if (!files || files.length === 0) {
throw new Error('You must select an image to upload.')
}
const file = $files[0]
const file = files[0]
const fileExt = file.name.split('.').pop()
const filePath = `${Math.random()}.${fileExt}`
const { error } = await $supabase.storage.from('avatars').upload(filePath, file)
const { error } = await supabase.storage.from('avatars').upload(filePath, file)
if (error) {
throw error
}
$url = filePath
url = filePath
setTimeout(() => {
dispatch('upload')
}, 100)
@@ -57,31 +60,31 @@
alert(error.message)
}
} finally {
$uploading = false
uploading = false
}
}
$effect(() => {
if ($url) downloadImage($url);
});
effect(() => {
if (url) downloadImage(url)
})
</script>
<div>
{#if $avatarUrl}
{#if avatarUrl}
<img
src={$avatarUrl}
alt={$avatarUrl ? 'Avatar' : 'No image'}
src={avatarUrl}
alt={avatarUrl ? 'Avatar' : 'No image'}
class="avatar image"
style="height: {$size}em; width: {$size}em;"
style="height: {size}em; width: {size}em;"
/>
{:else}
<div class="avatar no-image" style="height: {$size}em; width: {$size}em;"></div>
<div class="avatar no-image" style="height: {size}em; width: {size}em;"></div>
{/if}
<input type="hidden" name="avatarUrl" value={$url} />
<input type="hidden" name="avatarUrl" value={url} />
<div style="width: {$size}em;">
<div style="width: {size}em;">
<label class="button primary block" for="single">
{$uploading ? 'Uploading ...' : 'Upload'}
{uploading ? 'Uploading ...' : 'Upload'}
</label>
<input
style="visibility: hidden; position:absolute;"
@@ -90,7 +93,7 @@
accept="image/*"
bind:files
on:change={uploadAvatar}
disabled={$uploading}
disabled={uploading}
/>
</div>
</div>