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 / ButtonCard.svelte
3.3 kB 120 lines
1<script module lang="ts"> 2 import { tv, type VariantProps } from "tailwind-variants"; 3 4 export const buttonCard = tv({ 5 base: [ 6 "flex h-40 w-48 cursor-pointer gap-3 rounded-(--btn-radius) [--btn-radius:var(--radius-sm)] px-4 py-3 select-none no-underline", 7 "transition-colors duration-150 ease-in-out", 8 "hover:no-underline", 9 "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-border-focus", 10 "disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50" 11 ], 12 variants: { 13 variant: { 14 default: [ 15 "border border-border-default bg-background-default", 16 "hover:bg-background-subtle" 17 ], 18 ghost: [ 19 "border border-transparent bg-transparent", 20 "hover:bg-background-inset" 21 ] 22 }, 23 insetShadow: { 24 true: "", 25 false: "" 26 } 27 }, 28 compoundVariants: [ 29 // raised variants draw inset depth via a ::before layer. 30 { 31 variant: "default", 32 insetShadow: true, 33 class: [ 34 "relative z-0 before:absolute before:inset-0 before:-z-10 before:rounded-[max(calc(var(--btn-radius)-2px),0px)] before:content-[''] before:shadow-[inset_0_-2px_0_0_var(--color-shadow-inner-subtle)] before:transition-all before:duration-150", 35 "hover:before:shadow-[inset_0_-2px_0_0_var(--color-shadow-inner-strong-hover)]", 36 "active:translate-y-0.5 active:before:shadow-[inset_0_2px_2px_0_var(--color-shadow-inner-subtle)]", 37 "disabled:active:translate-y-0" 38 ] 39 } 40 ], 41 defaultVariants: { 42 variant: "default", 43 insetShadow: false 44 } 45 }); 46 47 export type ButtonCardVariants = VariantProps<typeof buttonCard>; 48</script> 49 50<script lang="ts"> 51 import type { ResolvedPathname } from "$app/types"; 52 import type { Component, Snippet } from "svelte"; 53 import type { 54 HTMLAnchorAttributes, 55 HTMLButtonAttributes, 56 SvelteHTMLElements 57 } from "svelte/elements"; 58 59 interface Props extends Omit<HTMLAnchorAttributes & HTMLButtonAttributes, "class" | "children"> { 60 variant?: ButtonCardVariants["variant"]; 61 insetShadow?: boolean; 62 href?: ResolvedPathname; 63 type?: "button" | "submit" | "reset"; 64 disabled?: boolean; 65 title?: string; 66 description?: string; 67 icon?: Component<SvelteHTMLElements["svg"]>; 68 class?: string; 69 children?: Snippet; 70 } 71 72 let { 73 variant = "default", 74 insetShadow = false, 75 href, 76 type = "button", 77 disabled = false, 78 title, 79 description, 80 icon, 81 class: className, 82 children, 83 ...rest 84 }: Props = $props(); 85 86 const classes = $derived(buttonCard({ variant, insetShadow, class: className })); 87 const Icon = $derived(icon); 88</script> 89 90{#snippet content()} 91 <div class="flex flex-col items-start gap-1.5"> 92 {#if title} 93 <div class="flex flex-row gap-2 items-center"> 94 {#if Icon} 95 <Icon class="size-4 shrink-0" aria-hidden="true" /> 96 {/if} 97 <span class="text-sm font-medium text-foreground-default">{title}</span> 98 </div> 99 {/if} 100 {#if description} 101 <span class="text-xs text-foreground-muted">{description}</span> 102 {/if} 103 </div> 104{/snippet} 105 106{#if href} 107 <a 108 {href} 109 class={classes} 110 aria-disabled={disabled ? "true" : undefined} 111 tabindex={disabled ? -1 : undefined} 112 {...rest} 113 > 114 {@render (children ?? content)()} 115 </a> 116{:else} 117 <button {type} {disabled} class={classes} {...rest}> 118 {@render (children ?? content)()} 119 </button> 120{/if}