mirror of
https://github.com/immich-app/immich
synced 2025-11-14 17:36:12 +00:00
refactor: buttons (#18317)
* refactor: buttons * fix: woopsie --------- Co-authored-by: Daniel Dietzler <36593685+danieldietzler@users.noreply.github.com>
This commit is contained in:
parent
c1150fe7e3
commit
86d64f3483
26 changed files with 148 additions and 279 deletions
|
|
@ -1,20 +0,0 @@
|
|||
import Button from '$lib/components/elements/buttons/button.svelte';
|
||||
import { render, screen } from '@testing-library/svelte';
|
||||
|
||||
describe('Button component', () => {
|
||||
it('should render as a button', () => {
|
||||
render(Button);
|
||||
const button = screen.getByRole('button');
|
||||
expect(button).toBeInTheDocument();
|
||||
expect(button).toHaveAttribute('type', 'button');
|
||||
expect(button).not.toHaveAttribute('href');
|
||||
});
|
||||
|
||||
it('should render as a link if href prop is set', () => {
|
||||
render(Button, { props: { href: '/test' } });
|
||||
const link = screen.getByRole('link');
|
||||
expect(link).toBeInTheDocument();
|
||||
expect(link).toHaveAttribute('href', '/test');
|
||||
expect(link).not.toHaveAttribute('type');
|
||||
});
|
||||
});
|
||||
|
|
@ -1,123 +0,0 @@
|
|||
<script lang="ts" module>
|
||||
export type Color =
|
||||
| 'primary'
|
||||
| 'primary-inversed'
|
||||
| 'secondary'
|
||||
| 'transparent-primary'
|
||||
| 'text-primary'
|
||||
| 'light-red'
|
||||
| 'red'
|
||||
| 'green'
|
||||
| 'gray'
|
||||
| 'transparent-gray'
|
||||
| 'dark-gray'
|
||||
| 'overlay-primary';
|
||||
export type Size = 'tiny' | 'icon' | 'link' | 'sm' | 'base' | 'lg';
|
||||
export type Rounded = 'lg' | '3xl' | 'full' | 'none';
|
||||
export type Shadow = 'md' | false;
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import type { Snippet } from 'svelte';
|
||||
|
||||
interface Props {
|
||||
type?: string;
|
||||
href?: string;
|
||||
color?: Color;
|
||||
size?: Size;
|
||||
rounded?: Rounded;
|
||||
shadow?: Shadow;
|
||||
fullwidth?: boolean;
|
||||
border?: boolean;
|
||||
class?: string;
|
||||
children?: Snippet;
|
||||
onclick?: (event: MouseEvent) => void;
|
||||
onfocus?: () => void;
|
||||
onblur?: () => void;
|
||||
form?: string;
|
||||
disabled?: boolean;
|
||||
title?: string;
|
||||
'aria-current'?: 'page' | 'step' | 'location' | 'date' | 'time' | undefined | null;
|
||||
}
|
||||
|
||||
let {
|
||||
type = 'button',
|
||||
href = undefined,
|
||||
color = 'primary',
|
||||
size = 'base',
|
||||
rounded = '3xl',
|
||||
shadow = 'md',
|
||||
fullwidth = false,
|
||||
border = false,
|
||||
class: className = '',
|
||||
children,
|
||||
onclick,
|
||||
onfocus,
|
||||
onblur,
|
||||
...rest
|
||||
}: Props = $props();
|
||||
|
||||
const colorClasses: Record<Color, string> = {
|
||||
primary:
|
||||
'bg-immich-primary dark:bg-immich-dark-primary text-white dark:text-immich-dark-gray dark:hover:bg-immich-dark-primary/80 hover:bg-immich-primary/90',
|
||||
secondary:
|
||||
'bg-gray-500 dark:bg-gray-200 text-white dark:text-immich-dark-gray hover:bg-gray-500/90 dark:hover:bg-gray-200/90',
|
||||
'transparent-primary': 'text-gray-500 dark:text-immich-dark-primary hover:bg-gray-100 dark:hover:bg-gray-700',
|
||||
'text-primary':
|
||||
'text-immich-primary dark:text-immich-dark-primary dark:hover:bg-immich-dark-primary/10 hover:bg-immich-primary/10',
|
||||
'light-red': 'bg-[#F9DEDC] text-[#410E0B] hover:bg-red-50',
|
||||
red: 'bg-red-500 text-white hover:bg-red-400',
|
||||
green: 'bg-green-400 text-gray-800 hover:bg-green-400/90',
|
||||
gray: 'bg-gray-500 dark:bg-gray-200 hover:bg-gray-500/75 dark:hover:bg-gray-200/80 text-white dark:text-immich-dark-gray',
|
||||
'transparent-gray':
|
||||
'dark:text-immich-dark-fg hover:bg-immich-primary/5 hover:text-gray-700 hover:dark:text-immich-dark-fg dark:hover:bg-immich-dark-primary/25',
|
||||
'dark-gray':
|
||||
'dark:border-immich-dark-gray dark:bg-gray-500 dark:hover:bg-immich-dark-primary/50 hover:bg-immich-primary/10 dark:text-white',
|
||||
'overlay-primary': 'text-gray-500 hover:bg-gray-100',
|
||||
'primary-inversed':
|
||||
'bg-immich-dark-primary dark:bg-immich-primary text-black dark:text-white hover:bg-immich-dark-primary/80 dark:hover:bg-immich-primary/90',
|
||||
};
|
||||
|
||||
const sizeClasses: Record<Size, string> = {
|
||||
tiny: 'p-0 ms-2 me-0 align-top',
|
||||
icon: 'p-2.5',
|
||||
link: 'p-2 font-medium',
|
||||
sm: 'px-4 py-2 text-sm font-medium',
|
||||
base: 'px-6 py-3 font-medium',
|
||||
lg: 'px-6 py-4 font-semibold',
|
||||
};
|
||||
|
||||
const roundedClasses: Record<Rounded, string> = {
|
||||
none: '',
|
||||
lg: 'rounded-lg',
|
||||
'3xl': 'rounded-3xl',
|
||||
full: 'rounded-full',
|
||||
};
|
||||
|
||||
let computedClass = $derived(
|
||||
[
|
||||
className,
|
||||
colorClasses[color],
|
||||
sizeClasses[size],
|
||||
roundedClasses[rounded],
|
||||
shadow === 'md' && 'shadow-md',
|
||||
fullwidth && 'w-full',
|
||||
border && 'border',
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(' '),
|
||||
);
|
||||
</script>
|
||||
|
||||
<svelte:element
|
||||
this={href ? 'a' : 'button'}
|
||||
type={href ? undefined : type}
|
||||
{href}
|
||||
{onclick}
|
||||
{onfocus}
|
||||
{onblur}
|
||||
class="inline-flex items-center justify-center transition-colors disabled:cursor-not-allowed disabled:opacity-60 disabled:pointer-events-none {computedClass}"
|
||||
{...rest}
|
||||
>
|
||||
{@render children?.()}
|
||||
</svelte:element>
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { getTabbable } from '$lib/utils/focus-util';
|
||||
import { Button } from '@immich/ui';
|
||||
import { t } from 'svelte-i18n';
|
||||
import Button from './button.svelte';
|
||||
|
||||
interface Props {
|
||||
/**
|
||||
|
|
@ -58,8 +58,7 @@
|
|||
|
||||
<div class="absolute top-2 start-2 transition-transform {isFocused ? 'translate-y-0' : '-translate-y-10 sr-only'}">
|
||||
<Button
|
||||
size="sm"
|
||||
rounded="none"
|
||||
size="small"
|
||||
onclick={moveFocus}
|
||||
class={getBreakpoint()}
|
||||
onfocus={() => (isFocused = true)}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue