a good start

This commit is contained in:
Jesse Winton
2025-03-31 12:16:06 -04:00
parent 03333b0c2f
commit d7252d4d25
18 changed files with 643 additions and 201 deletions

View File

@@ -0,0 +1,98 @@
<script lang="ts">
import { classNames } from '$lib/utils/classnames';
import { emptyMeltElement, melt, type AnyMeltElement } from '@melt-ui/svelte';
import { cva, type VariantProps } from 'cva';
import type { Action } from 'svelte/action';
import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements';
import InlineTag from './inline-tag.svelte';
// TODO: replace _button.scss with Tailwind classes for maintainability
const button = cva(['web-button'], {
variants: {
variant: {
primary: [''],
secondary: ['is-secondary'],
text: ['is-text']
}
}
});
type ButtonProps =
| (HTMLButtonAttributes & { href?: undefined })
| (HTMLAnchorAttributes & { href: string });
type $$Props = ButtonProps &
VariantProps<typeof button> & {
use?:
| Action<HTMLButtonElement | HTMLAnchorElement, any>
| [Action<HTMLButtonElement | HTMLAnchorElement, any>, any];
} & { element?: AnyMeltElement };
export let href: $$Props['href'] = undefined;
export let variant: $$Props['variant'] = 'primary';
export let use: $$Props['use'] = undefined;
export let element: AnyMeltElement | undefined = undefined;
$: meltElement = element ?? emptyMeltElement;
const { class: classes, href: _, ...props } = $$restProps;
const buttonClasses = classNames(button({ variant }), classes);
const applyAction = (node: HTMLButtonElement | HTMLAnchorElement) => {
if (!use) return { destroy: () => {} };
if (typeof use === 'function') {
return use(node);
} else if (Array.isArray(use)) {
const [action, params] = use;
return action(node, params);
}
return { destroy: () => {} };
};
</script>
{#if href}
<a
{...props}
{href}
class={buttonClasses}
use:melt={$meltElement}
use:applyAction
on:click
on:dblclick
on:mousedown
on:mouseup
>
{#if $$slots.icon}
<slot name="icon" />
{/if}
<slot />
{#if $$slots.tag}
<InlineTag>
<slot name="tag" />
</InlineTag>
{/if}
</a>
{:else}
<button
{...props}
class={buttonClasses}
use:melt={$meltElement}
use:applyAction
on:click
on:dblclick
on:mousedown
on:mouseup
>
{#if $$slots.icon}
<slot name="icon" />
{/if}
<slot />
{#if $$slots.tag}
<InlineTag>
<slot name="tag" />
</InlineTag>
{/if}
</button>
{/if}