Skip to content

Commit

Permalink
feat: icon button (#14)
Browse files Browse the repository at this point in the history
  • Loading branch information
jrasm91 authored Nov 15, 2024
1 parent 3026dec commit f802f41
Show file tree
Hide file tree
Showing 7 changed files with 274 additions and 123 deletions.
105 changes: 105 additions & 0 deletions src/docs/examples/IconButtonExamples.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<script lang="ts">
import { IconButton, Card, CardBody, CardHeader, CardTitle } from '@immich/ui';
import type { Color, Shape, Size } from '@immich/ui';
import { mdiMagnify } from '@mdi/js';
const colors: Color[] = ['primary', 'secondary', 'success', 'danger', 'warning', 'info'];
const sizes: Size[] = ['tiny', 'small', 'medium', 'large', 'giant'];
const shapes: Shape[] = ['rectangle', 'semi-round', 'round'];
const icon = mdiMagnify;
</script>

<div class="flex flex-col gap-4">
<Card>
<CardHeader>
<CardTitle>Shapes</CardTitle>
</CardHeader>
<CardBody>
<div class="flex flex-wrap gap-4">
{#each shapes as shape}
<IconButton {icon} {shape} />
{/each}
</div>
</CardBody>
</Card>

<Card>
<CardHeader>
<CardTitle>Colors</CardTitle>
</CardHeader>
<CardBody>
<div class="flex flex-wrap gap-4">
{#each colors as color}
<IconButton {icon} {color}></IconButton>
{/each}
</div>
</CardBody>
</Card>

<Card>
<CardHeader>
<CardTitle>Outline</CardTitle>
</CardHeader>
<CardBody>
<div class="flex flex-wrap gap-4">
{#each colors as color}
<IconButton {icon} variant="outline" {color}></IconButton>
{/each}
</div>
</CardBody>
</Card>

<Card>
<CardHeader>
<CardTitle>Ghost</CardTitle>
</CardHeader>
<CardBody>
<div class="flex flex-wrap gap-4">
{#each colors as color}
<IconButton {icon} variant="ghost" {color}></IconButton>
{/each}
</div>
</CardBody>
</Card>

<Card>
<CardHeader>
<CardTitle>Hero</CardTitle>
</CardHeader>
<CardBody>
<div class="flex flex-wrap gap-4">
{#each colors as color}
<IconButton {icon} variant="hero" {color}></IconButton>
{/each}
</div>
</CardBody>
</Card>

<Card>
<CardHeader>
<CardTitle>Disabled</CardTitle>
</CardHeader>
<CardBody>
<div class="flex flex-wrap gap-4">
{#each colors as color}
<IconButton {icon} {color} disabled></IconButton>
{/each}
</div>
</CardBody>
</Card>

<Card>
<CardHeader>
<CardTitle>Sizes</CardTitle>
</CardHeader>
<CardBody>
<div class="flex flex-wrap gap-4">
{#each sizes as size}
<div>
<IconButton {icon} {size}></IconButton>
</div>
{/each}
</div>
</CardBody>
</Card>
</div>
2 changes: 2 additions & 0 deletions src/docs/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import ButtonExamples from '$docs/examples/ButtonExamples.svelte';
import CardExamples from '$docs/examples/CardExamples.svelte';
import CheckboxExamples from '$docs/examples/CheckboxExamples.svelte';
import LogoExamples from '$docs/examples/LogoExamples.svelte';
import IconButtonExamples from '$docs/examples/IconButtonExamples.svelte';
import type { Component } from 'svelte';

type Route = {
Expand All @@ -14,5 +15,6 @@ export const routes: Route[] = [
{ name: 'Button', link: '/examples/button', component: ButtonExamples },
{ name: 'Checkbox', link: '/examples/checkbox', component: CheckboxExamples },
{ name: 'Card', link: '/examples/card', component: CardExamples },
{ name: 'IconButton', link: '/examples/icon-button', component: IconButtonExamples },
{ name: 'Logo', link: '/examples/logo', component: LogoExamples },
];
127 changes: 4 additions & 123 deletions src/lib/components/Button.svelte
Original file line number Diff line number Diff line change
@@ -1,127 +1,8 @@
<script lang="ts">
import type { Color, Shape, Size } from '$lib/types.js';
import { cleanClass } from '$lib/utils.js';
import { Button as ButtonPrimitive } from 'bits-ui';
import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements';
import { tv } from 'tailwind-variants';
import InternalButton from '$lib/internal/InternalButton.svelte';
import type { ButtonProps } from '$lib/types.js';
type ButtonVariant = 'filled' | 'outline' | 'ghost' | 'hero';
type ButtonProps = {
class?: string;
color?: Color;
size?: Size;
shape?: Shape;
variant?: ButtonVariant;
fullWidth?: boolean;
} & (({ href?: never } & HTMLButtonAttributes) | ({ href: string } & HTMLAnchorAttributes));
const asOverride = (variant: ButtonVariant, colors: Record<Color, string>) =>
(Object.keys(colors) as Color[]).map((color) => ({ variant, color, class: colors[color] }));
const colorPlaceholder = {
primary: '',
secondary: '',
success: '',
danger: '',
warning: '',
info: '',
};
const variantPlaceholder = {
outline: '',
filled: '',
ghost: '',
hero: '',
};
const buttonVariants = tv({
base: 'ring-offset-background focus-visible:ring-ring flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
variants: {
shape: {
rectangle: 'rounded-none',
'semi-round': 'rounded-xl',
round: 'rounded-full',
},
size: {
tiny: 'px-2 py-1 text-xs',
small: 'px-2 py-1 text-sm',
medium: 'px-4 py-2 text-md',
large: 'px-4 py-2 text-lg',
giant: 'px-8 py-4 text-xl',
},
fullWidth: {
true: 'w-full',
},
color: colorPlaceholder,
variant: variantPlaceholder,
},
compoundVariants: [
...asOverride('filled', {
primary: 'bg-primary text-light hover:bg-primary/80',
secondary: 'bg-dark text-light hover:bg-dark/80',
success: 'bg-success text-light hover:bg-success/80',
danger: 'bg-danger text-light hover:bg-danger/80',
warning: 'bg-warning text-light hover:bg-warning/80',
info: 'bg-info text-light hover:bg-info/80',
}),
...asOverride('outline', {
primary: 'bg-primary/10 text-primary border border-primary hover:bg-primary/20',
secondary: 'bg-dark/10 text-dark border border-dark hover:bg-dark/20',
success: 'bg-success/10 text-success border border-success hover:bg-success/20',
danger: 'bg-danger/10 text-danger border border-danger hover:bg-danger/20',
warning: 'bg-warning/10 text-warning border border-warning hover:bg-warning/20',
info: 'bg-info/10 text-info border border-info hover:bg-info/20',
}),
...asOverride('ghost', {
primary: 'text-primary hover:bg-primary/10',
secondary: 'text-dark hover:bg-dark/10',
success: 'text-success hover:bg-success/10',
danger: 'text-danger hover:bg-danger/10',
warning: 'text-warning hover:bg-warning/10',
info: 'text-info hover:bg-info/10',
}),
...asOverride('hero', {
primary: 'bg-gradient-to-tr from-primary to-primary/60 text-light hover:bg-primary',
secondary: 'bg-gradient-to-tr from-dark to-dark/60 text-light hover:bg-dark',
success: 'bg-gradient-to-tr from-success to-success/60 text-light hover:bg-success',
danger: 'bg-gradient-to-tr from-danger to-danger/60 text-light hover:bg-danger',
warning: 'bg-gradient-to-tr from-warning to-warning/60 text-light hover:bg-warning',
info: 'bg-gradient-to-tr from-info to-info/60 text-light hover:bg-info',
}),
],
});
const {
type = 'button',
href,
variant = 'filled',
color = 'primary',
shape = 'semi-round',
size = 'medium',
fullWidth = false,
class: className = '',
children,
...restProps
}: ButtonProps = $props();
const classList = $derived(
cleanClass(buttonVariants({ variant, color, shape, size, fullWidth }), className),
);
const props: ButtonProps = $props();
</script>

{#if href}
<a {href} class={classList} {...restProps as HTMLAnchorAttributes}>
{@render children?.()}
</a>
{:else}
<ButtonPrimitive.Root
class={classList}
type={type as HTMLButtonAttributes['type']}
{...restProps as HTMLButtonAttributes}
>
{@render children?.()}
</ButtonPrimitive.Root>
{/if}
<InternalButton {...props} />
11 changes: 11 additions & 0 deletions src/lib/components/IconButton.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<script lang="ts">
import InternalButton from '$lib/internal/InternalButton.svelte';
import { Icon } from '$lib/components/index.js';
import type { IconButtonProps } from '$lib/types.js';
const { icon, ...buttonProps }: IconButtonProps = $props();
</script>

<InternalButton icon {...buttonProps}>
<Icon path={icon}></Icon>
</InternalButton>
1 change: 1 addition & 0 deletions src/lib/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export { default as CardHeader } from '$lib/components/CardHeader.svelte';
export { default as CardTitle } from '$lib/components/CardTitle.svelte';
export { default as Checkbox } from '$lib/components/Checkbox.svelte';
export { default as Icon } from '$lib/components/Icon.svelte';
export { default as IconButton } from '$lib/components/IconButton.svelte';
export { default as Input } from '$lib/components/Input.svelte';
export { default as Label } from '$lib/components/Label.svelte';
export { default as Logo } from '$lib/components/Logo.svelte';
Loading

0 comments on commit f802f41

Please sign in to comment.