This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / web / src / lib / components / ui / Button.svelte
3.8 kB 103 lines
1<script module lang="ts"> 2 import { tv, type VariantProps } from 'tailwind-variants'; 3 4 export const button = tv({ 5 base: 'inline-flex cursor-pointer select-none items-center justify-center overflow-hidden rounded no-underline transition-[background-color,border-color,color] duration-150 ease-[cubic-bezier(0.4,0,0.2,1)] hover:no-underline focus-visible:outline-2 focus-visible:outline-offset-2 disabled:pointer-events-none disabled:opacity-50', 6 variants: { 7 variant: { 8 default: 9 'border border-border bg-surface text-fg hover:bg-surface-hover focus-visible:outline-ring', 10 primary: 11 'border border-primary-border bg-primary text-primary-fg hover:bg-primary-hover focus-visible:outline-primary', 12 ghost: 'bg-transparent text-fg-muted hover:bg-surface-muted focus-visible:outline-ring', 13 danger: 14 'border border-danger-border bg-danger text-danger-fg hover:bg-danger-hover focus-visible:outline-danger', 15 success: 16 'border border-success-border bg-success text-success-fg hover:bg-success-hover focus-visible:outline-success' 17 }, 18 size: { 19 sm: 'min-h-8 gap-1.5 px-2 py-1.5 text-sm', 20 md: 'min-h-9 gap-2 px-4 py-2 text-sm', 21 lg: 'min-h-10 gap-2.5 px-6 py-2 text-base' 22 } 23 }, 24 compoundVariants: [ 25 // raised variants draw inset depth via a ::before layer. 26 { 27 variant: 'default', 28 class: 29 "relative z-0 before:absolute before:inset-0 before:-z-10 before:rounded-[inherit] before:content-[''] before:shadow-[inset_0_-2px_0_0_var(--color-raised-depth)] before:transition-all before:duration-150 hover:before:shadow-[inset_0_-2px_0_0_var(--color-raised-depth-hover)] active:translate-y-0.5 active:before:shadow-[inset_0_2px_2px_0_var(--color-raised-depth)] disabled:active:translate-y-0" 30 }, 31 { 32 variant: ['primary', 'danger', 'success'], 33 class: 34 "relative z-0 before:absolute before:inset-0 before:-z-10 before:rounded-[inherit] before:content-[''] before:shadow-[inset_0_-2px_0_0_var(--color-raised-accent-depth)] before:transition-all before:duration-150 active:translate-y-0.5 active:before:shadow-[inset_0_2px_2px_0_var(--color-raised-accent-depth-active)] disabled:active:translate-y-0" 35 } 36 ], 37 defaultVariants: { 38 variant: 'default', 39 size: 'md' 40 } 41 }); 42 43 export type ButtonVariants = VariantProps<typeof button>; 44</script> 45 46<script lang="ts"> 47 import { resolve } from '$app/paths'; 48 import type { Snippet } from 'svelte'; 49 import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements'; 50 import Spinner from './Spinner.svelte'; 51 52 interface Props extends Omit<HTMLAnchorAttributes & HTMLButtonAttributes, 'class' | 'children'> { 53 variant?: ButtonVariants['variant']; 54 size?: ButtonVariants['size']; 55 href?: string; 56 type?: 'button' | 'submit' | 'reset'; 57 disabled?: boolean; 58 class?: string; 59 loading?: boolean; 60 spinnerClass?: string; 61 children?: Snippet; 62 } 63 64 let { 65 variant = 'default', 66 size = 'md', 67 href, 68 type = 'button', 69 disabled = false, 70 class: className, 71 loading = false, 72 spinnerClass, 73 children, 74 ...rest 75 }: Props = $props(); 76 77 const classes = $derived(button({ variant, size, class: className })); 78 const spinnerSize = $derived(spinnerClass ?? (size === 'lg' ? 'size-5' : 'size-4')); 79</script> 80 81{#if href} 82 <a 83 href={resolve(href as '/')} 84 class={classes} 85 aria-disabled={disabled || loading ? 'true' : undefined} 86 tabindex={disabled ? -1 : undefined} 87 {...rest} 88 > 89 {#if loading} 90 <Spinner class={spinnerSize} /> 91 {:else if children} 92 {@render children()} 93 {/if} 94 </a> 95{:else} 96 <button {type} disabled={disabled || loading} class={classes} aria-busy={loading} {...rest}> 97 {#if loading} 98 <Spinner class={spinnerSize} /> 99 {:else if children} 100 {@render children()} 101 {/if} 102 </button> 103{/if}