magicuidesign / magicui

UI Library for Design Engineers. Animated components and effects you can copy and paste into your apps. Free. Open Source.
https://magicui.design
MIT License
8.39k stars 323 forks source link

Border Beam + Shimmer Button for Svelte #74

Closed gursheyss closed 3 months ago

gursheyss commented 3 months ago

Borderbeam

<script lang="ts">
    import { cn } from '$lib/utils';

    interface Props {
        class?: string;
        size?: number;
        duration?: number;
        borderWidth?: number;
        anchor?: number;
        colorFrom?: string;
        colorTo?: string;
        delay?: number;
    }

    let {
        class: className,
        size = 200,
        duration = 15,
        anchor = 90,
        borderWidth = 1.5,
        colorFrom = '#ffaa40',
        colorTo = '#9c40ff',
        delay = 0
    }: Props = $props();

    let styleVars = $derived.by(() => {
        return `--size: ${size}; 
            --duration: ${duration}; 
            --anchor: ${anchor}; 
            --border-width: ${borderWidth}; 
            --color-from: ${colorFrom}; 
            --color-to: ${colorTo}; 
            --delay: -${delay}s;`;
    });
</script>

<div
    style={styleVars}
    class={cn(
        'absolute inset-[0] rounded-[inherit] [border:calc(var(--border-width)*1px)_solid_transparent]',

        // mask styles
        '![mask-clip:padding-box,border-box] ![mask-composite:intersect] [mask:linear-gradient(transparent,transparent),linear-gradient(white,white)]',

        // pseudo styles
        'after:absolute after:aspect-square after:w-[calc(var(--size)*1px)] after:animate-border-beam after:[animation-delay:var(--delay)] after:[background:linear-gradient(to_left,var(--color-from),var(--color-to),transparent)] after:[offset-anchor:calc(var(--anchor)*1%)_50%] after:[offset-path:rect(0_auto_auto_0_round_calc(var(--size)*1px))]',
        className
    )}
></div>

Shimmer Button

<script lang="ts">
    import { cn } from '$lib/utils';
    import type { Snippet } from 'svelte';
    import type { HTMLButtonAttributes } from 'svelte/elements';

    interface ShimmerButtonProps extends HTMLButtonAttributes {
        shimmerColor?: string;
        shimmerSize?: string;
        borderRadius?: string;
        shimmerDuration?: string;
        background?: string;
        class?: string;
        children?: Snippet;
    }

    let {
        shimmerColor = '#ffffff',
        shimmerSize = '0.05em',
        shimmerDuration = '3s',
        borderRadius = '100px',
        background = 'rgba(0, 0, 0, 1)',
        class: className,
        children,
        ...restProps
    }: ShimmerButtonProps = $props();

    let styleVars = $derived.by(() => {
        return `--spread: 90deg; 
            --shimmer-color:${shimmerColor}; 
            --radius: ${borderRadius}; 
            --speed: ${shimmerDuration}; 
            --cut: ${shimmerSize}; 
            --bg: ${background};`;
    });
</script>

<button
    style={styleVars}
    class={cn(
        'group relative z-0 flex cursor-pointer items-center justify-center overflow-hidden whitespace-nowrap border border-white/10 px-6 py-3 text-white [background:var(--bg)] [border-radius:var(--radius)] dark:text-black',
        'transform-gpu transition-transform duration-300 ease-in-out active:translate-y-[1px]',
        className
    )}
    {...restProps}
>
    <!-- spark container -->
    <div class={cn('-z-30 blur-[2px]', 'absolute inset-0 overflow-visible [container-type:size]')}>
        <!-- spark -->
        <div
            class="animate-slide absolute inset-0 h-[100cqh] [aspect-ratio:1] [border-radius:0] [mask:none]"
        >
            <!-- spark before -->
            <div
                class="animate-spin-around absolute inset-[-100%] w-auto rotate-0 [background:conic-gradient(from_calc(270deg-(var(--spread)*0.5)),transparent_0,var(--shimmer-color)_var(--spread),transparent_var(--spread))] [translate:0_0]"
            ></div>
        </div>
    </div>
    {#if children}
        {@render children()}
    {/if}

    <!-- Highlight -->
    <div
        class={cn(
            'insert-0 absolute h-full w-full',

            'rounded-2xl px-4 py-1.5 text-sm font-medium shadow-[inset_0_-8px_10px_#ffffff1f]',

            // transition
            'transform-gpu transition-all duration-300 ease-in-out',

            // on hover
            'group-hover:shadow-[inset_0_-6px_10px_#ffffff3f]',

            // on click
            'group-active:shadow-[inset_0_-10px_10px_#ffffff3f]'
        )}
    ></div>

    <!-- backdrop -->
    <div
        class={cn(
            'absolute -z-20 [background:var(--bg)] [border-radius:var(--radius)] [inset:var(--cut)]'
        )}
    ></div>
</button>
dillionverma commented 3 months ago

closing this issue since it is now being tracked in #76

engageintellect commented 2 months ago

@dillionverma

What does your /lib/utils.ts look like? I used the one provided in the instructions here, but keep getting a "no class value" error:

SyntaxError: [vite] The requested module 'clsx' does not provide an export named 'ClassValue'