mirror of
https://github.com/pheralb/svgl.git
synced 2025-02-11 17:50:32 +08:00
🎨 Add new badge, button & input UI components
This commit is contained in:
parent
21cbb24f17
commit
b9db482f0c
18
src/ui/badge/badge.svelte
Normal file
18
src/ui/badge/badge.svelte
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { type Variant, badgeVariants } from '.';
|
||||||
|
import { cn } from '@/utils/cn';
|
||||||
|
|
||||||
|
let className: string | undefined | null = undefined;
|
||||||
|
export let href: string | undefined = undefined;
|
||||||
|
export let variant: Variant = 'default';
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:element
|
||||||
|
this={href ? 'a' : 'span'}
|
||||||
|
{href}
|
||||||
|
class={cn(badgeVariants({ variant, className }))}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</svelte:element>
|
17
src/ui/badge/index.ts
Normal file
17
src/ui/badge/index.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { type VariantProps, tv } from 'tailwind-variants';
|
||||||
|
export { default as Badge } from './badge.svelte';
|
||||||
|
|
||||||
|
export const badgeVariants = tv({
|
||||||
|
base: 'inline-flex items-center px-2.5 py-0.5 rounded-full font-medium text-xs font-mono hover:underline transition-colors duration-100',
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
default:
|
||||||
|
'bg-neutral-100 dark:bg-neutral-800/50 border border-neutral-200 dark:border-neutral-800 text-neutral-600 dark:text-neutral-400 hover:bg-neutral-200 dark:hover:bg-neutral-700/50'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: 'default'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export type Variant = VariantProps<typeof badgeVariants>['variant'];
|
25
src/ui/button/button.svelte
Normal file
25
src/ui/button/button.svelte
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Button as ButtonPrimitive } from 'bits-ui';
|
||||||
|
import { type Events, type Props, buttonVariants } from '.';
|
||||||
|
import { cn } from '@/utils/cn';
|
||||||
|
|
||||||
|
type $$Props = Props;
|
||||||
|
type $$Events = Events;
|
||||||
|
|
||||||
|
let className: $$Props['class'] = undefined;
|
||||||
|
export let variant: $$Props['variant'] = 'default';
|
||||||
|
export let size: $$Props['size'] = 'default';
|
||||||
|
export let builders: $$Props['builders'] = [];
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ButtonPrimitive.Root
|
||||||
|
{builders}
|
||||||
|
class={cn(buttonVariants({ variant, size }), className)}
|
||||||
|
type="button"
|
||||||
|
{...$$restProps}
|
||||||
|
on:click
|
||||||
|
on:keydown
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</ButtonPrimitive.Root>
|
53
src/ui/button/index.ts
Normal file
53
src/ui/button/index.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import type { Button as ButtonPrimitive } from 'bits-ui';
|
||||||
|
import { type VariantProps, tv } from 'tailwind-variants';
|
||||||
|
|
||||||
|
import Root from './button.svelte';
|
||||||
|
|
||||||
|
const buttonVariants = tv({
|
||||||
|
base: 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-neutral-300 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 dark:focus-visible:ring-neutral-700',
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
default:
|
||||||
|
'bg-neutral-900 text-neutral-50 shadow hover:bg-neutral-900/90 dark:bg-neutral-800 dark:text-neutral-50 dark:hover:bg-neutral-800/70',
|
||||||
|
destructive:
|
||||||
|
'bg-red-500 text-neutral-50 shadow-sm hover:bg-red-500/90 dark:bg-red-900 dark:text-neutral-50 dark:hover:bg-red-900/90',
|
||||||
|
outline:
|
||||||
|
'border border-neutral-200 bg-white shadow-sm hover:bg-neutral-100 hover:text-neutral-900 dark:border-neutral-800 dark:bg-neutral-900 dark:hover:bg-neutral-800 dark:hover:text-neutral-50',
|
||||||
|
secondary:
|
||||||
|
'bg-neutral-100 text-neutral-900 shadow-sm hover:bg-neutral-100/80 dark:bg-neutral-800 dark:text-neutral-50 dark:hover:bg-neutral-800/80',
|
||||||
|
ghost:
|
||||||
|
'hover:bg-neutral-100 hover:text-neutral-900 dark:hover:bg-neutral-800 dark:hover:text-neutral-50',
|
||||||
|
link: 'text-neutral-900 underline-offset-4 hover:underline dark:text-neutral-50'
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
default: 'h-9 px-4 py-2',
|
||||||
|
sm: 'h-8 rounded-md px-3 text-xs',
|
||||||
|
lg: 'h-10 rounded-md px-8',
|
||||||
|
icon: 'h-9 w-9'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: 'default',
|
||||||
|
size: 'default'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
type Variant = VariantProps<typeof buttonVariants>['variant'];
|
||||||
|
type Size = VariantProps<typeof buttonVariants>['size'];
|
||||||
|
|
||||||
|
type Props = ButtonPrimitive.Props & {
|
||||||
|
variant?: Variant;
|
||||||
|
size?: Size;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Events = ButtonPrimitive.Events;
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
type Props,
|
||||||
|
type Events,
|
||||||
|
Root as Button,
|
||||||
|
type Props as ButtonProps,
|
||||||
|
type Events as ButtonEvents,
|
||||||
|
buttonVariants
|
||||||
|
};
|
31
src/ui/input/index.ts
Normal file
31
src/ui/input/index.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { cn } from '@/utils/cn';
|
||||||
|
import Root from './input.svelte';
|
||||||
|
|
||||||
|
export type FormInputEvent<T extends Event = Event> = T & {
|
||||||
|
currentTarget: EventTarget & HTMLInputElement;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const InputStyles = cn(
|
||||||
|
'flex h-9 w-full rounded-md border border-neutral-200 bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-neutral-500 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-neutral-300 disabled:cursor-not-allowed disabled:opacity-50 dark:border-neutral-800 dark:placeholder:text-neutral-400 dark:focus-visible:ring-neutral-700'
|
||||||
|
);
|
||||||
|
|
||||||
|
export type InputEvents = {
|
||||||
|
blur: FormInputEvent<FocusEvent>;
|
||||||
|
change: FormInputEvent<Event>;
|
||||||
|
click: FormInputEvent<MouseEvent>;
|
||||||
|
focus: FormInputEvent<FocusEvent>;
|
||||||
|
focusin: FormInputEvent<FocusEvent>;
|
||||||
|
focusout: FormInputEvent<FocusEvent>;
|
||||||
|
keydown: FormInputEvent<KeyboardEvent>;
|
||||||
|
keypress: FormInputEvent<KeyboardEvent>;
|
||||||
|
keyup: FormInputEvent<KeyboardEvent>;
|
||||||
|
mouseover: FormInputEvent<MouseEvent>;
|
||||||
|
mouseenter: FormInputEvent<MouseEvent>;
|
||||||
|
mouseleave: FormInputEvent<MouseEvent>;
|
||||||
|
mousemove: FormInputEvent<MouseEvent>;
|
||||||
|
paste: FormInputEvent<ClipboardEvent>;
|
||||||
|
input: FormInputEvent<InputEvent>;
|
||||||
|
wheel: FormInputEvent<WheelEvent>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export { Root, Root as Input };
|
36
src/ui/input/input.svelte
Normal file
36
src/ui/input/input.svelte
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { HTMLInputAttributes } from 'svelte/elements';
|
||||||
|
import { InputStyles, type InputEvents } from '.';
|
||||||
|
import { cn } from '@/utils/cn';
|
||||||
|
|
||||||
|
type $$Props = HTMLInputAttributes;
|
||||||
|
type $$Events = InputEvents;
|
||||||
|
|
||||||
|
let className: $$Props['class'] = undefined;
|
||||||
|
export let value: $$Props['value'] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
export let readonly: $$Props['readonly'] = undefined;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<input
|
||||||
|
class={cn(InputStyles, className)}
|
||||||
|
bind:value
|
||||||
|
{readonly}
|
||||||
|
on:blur
|
||||||
|
on:change
|
||||||
|
on:click
|
||||||
|
on:focus
|
||||||
|
on:focusin
|
||||||
|
on:focusout
|
||||||
|
on:keydown
|
||||||
|
on:keypress
|
||||||
|
on:keyup
|
||||||
|
on:mouseover
|
||||||
|
on:mouseenter
|
||||||
|
on:mouseleave
|
||||||
|
on:mousemove
|
||||||
|
on:paste
|
||||||
|
on:input
|
||||||
|
on:wheel|passive
|
||||||
|
{...$$restProps}
|
||||||
|
/>
|
Loading…
x
Reference in New Issue
Block a user