Skip to content

Commit

Permalink
Enhancing the form with handling loading state
Browse files Browse the repository at this point in the history
  • Loading branch information
dejanvasic85 committed Jan 7, 2025
1 parent 1603461 commit c6e1fa9
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 23 deletions.
22 changes: 20 additions & 2 deletions src/components/Button.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
rounded?: boolean;
type?: 'button' | 'submit' | 'reset';
label?: string;
loading?: boolean;
onclick?: () => void;
};
Expand All @@ -18,12 +19,29 @@
rounded,
type = 'button',
label = '',
loading = false,
onclick
}: Props = $props();
const buttonClass = buildButtonClass(variant, rounded);
const buttonClass = $derived(buildButtonClass(variant, rounded, loading));
</script>

<button {type} class={buttonClass} {onclick} aria-label={label}>
<button {type} class={buttonClass} {onclick} aria-label={label} disabled={loading}>
{#if loading}
<svg
class="-ml-1 mr-3 h-5 w-5 animate-spin text-white"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"
></circle>
<path
class="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg>
{/if}
{@render children()}
</button>
17 changes: 4 additions & 13 deletions src/lib/button.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
export type Variant = 'primary' | 'secondary' | 'tertiary' | 'ghost';

const baseClasses = `flex
min-h-11
min-w-[44px]
items-center
justify-center
gap-2
px-4 py-2
transition-all
duration-150
hover:scale-105
focus:outline-none`;
const baseClasses = `flex min-h-11 min-w-[44px] items-center justify-center gap-2 px-4 py-2 transition-all duration-150 hover:scale-105 focus:outline-none`;

const variantClasses = {
primary: 'bg-primary hover:bg-primary/90 text-white border-none',
Expand All @@ -19,7 +9,8 @@ const variantClasses = {
ghost: 'dark:hover:bg-slate-800 hover:ring-2'
} as const;

export const buildButtonClass = (variant: Variant, round = false) => {
export const buildButtonClass = (variant: Variant, round = false, loading = false) => {
const roundedClass = round ? 'rounded-full' : 'rounded-xl';
return `${baseClasses} ${variantClasses[variant]} ${roundedClass}`;
const loadingClass = loading ? 'opacity-50 pointer-events-none' : '';
return `${loadingClass} ${baseClasses} ${variantClasses[variant]} ${roundedClass}`;
};
29 changes: 21 additions & 8 deletions src/routes/my/friends/add/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
<script lang="ts">
import { enhance } from '$app/forms';
import { createLabel, melt } from '@melt-ui/svelte';
import Input from '$components/Input.svelte';
import Button from '$components/Button.svelte';
import Icon from '$components/Icon.svelte';
let { form } = $props();
let loading = $state(false);
let error = $state('');
const {
elements: { root }
} = createLabel();
const formError = form?.status === 400;
</script>

<div class="mb-4">
Expand All @@ -20,17 +22,28 @@

<h1 class="text-2xl">Invite friend</h1>
<p>Adding a friend allows you select notes for them to see.</p>
<form method="POST">
<form
method="POST"
use:enhance={() => {
loading = true;
return async ({ result }) => {
loading = false;
if (result.type === 'failure') {
error = result.data?.message as string;
}
};
}}
>
<div class="mt-4 flex w-full flex-col gap-2 lg:w-1/2">
<label for="email" class:text-error={formError} use:melt={$root}>Email</label>
<label for="email" class:text-error={!!error} use:melt={$root}>Email</label>
<div class="flex-1">
<Input id="email" type="text" invalid={formError} name="email" />
<Input id="email" type="text" invalid={!!error} name="email" />
</div>
{#if formError}
<p class="mt-2 text-sm text-error">Email is required</p>
{#if error}
<p class="mt-2 text-sm text-error">{error}</p>
{/if}
<div class="flex justify-end">
<Button type="submit">Send invite</Button>
<Button type="submit" {loading}>Send invite</Button>
</div>
</div>
</form>

0 comments on commit c6e1fa9

Please sign in to comment.