167 lines
4.1 KiB
Plaintext
167 lines
4.1 KiB
Plaintext
---
|
|
type ButtonVariant = "default" | "big" | "dark";
|
|
|
|
interface Props {
|
|
link: string;
|
|
text: string;
|
|
iconName?: string;
|
|
variant?: ButtonVariant;
|
|
ariaLabel?: string;
|
|
disabled?: boolean;
|
|
isLoading?: boolean;
|
|
isExternal?: boolean;
|
|
isActive?: boolean;
|
|
class?: string;
|
|
}
|
|
|
|
const {
|
|
link,
|
|
text,
|
|
iconName,
|
|
variant = "default",
|
|
ariaLabel,
|
|
disabled = false,
|
|
isLoading = false,
|
|
isExternal = false,
|
|
isActive = false,
|
|
class: className = ""
|
|
} = Astro.props as Props;
|
|
import { Icon } from "astro-icon/components";
|
|
|
|
// Common base classes for all buttons
|
|
const baseClasses = `
|
|
z-2
|
|
text-center
|
|
cursor-pointer
|
|
leading-none
|
|
hover:scale-110
|
|
w-fit
|
|
font-medium
|
|
flex
|
|
gap-2
|
|
transition-all
|
|
ease-in-out
|
|
justify-center
|
|
items-center
|
|
rounded-full
|
|
disabled:opacity-50
|
|
disabled:cursor-not-allowed
|
|
disabled:hover:scale-100
|
|
disabled:hover:bg-none
|
|
disabled:hover:shadow-none
|
|
aria-disabled:opacity-50
|
|
aria-disabled:cursor-not-allowed
|
|
aria-disabled:hover:scale-100
|
|
aria-disabled:hover:bg-none
|
|
aria-disabled:hover:shadow-none
|
|
`;
|
|
|
|
// Specific classes for each variant
|
|
const variantClasses = {
|
|
default: `
|
|
text-blacktext/90
|
|
dark:text-mint-50
|
|
dark:hover:text-white
|
|
px-6
|
|
py-4
|
|
max-xl:px-5
|
|
max-sm:py-2
|
|
max-sm:px-3
|
|
text-lg
|
|
max-xl:text-base
|
|
max-sm:text-sm
|
|
hover:bg-gradient-to-l
|
|
bg-gradient-to-r
|
|
from-riptide-300
|
|
to-mint-300
|
|
dark:from-riptide-500
|
|
dark:to-mint-500
|
|
`,
|
|
big: `
|
|
font-normal
|
|
gap-3
|
|
max-md:gap-1
|
|
text-blacktext
|
|
dark:text-mint-50
|
|
dark:hover:text-white
|
|
px-8
|
|
max-sm:py-3
|
|
py-5
|
|
max-xl:px-6
|
|
max-sm:px-3
|
|
text-2xl
|
|
max-xl:text-xl
|
|
max-sm:text-lg
|
|
hover:bg-gradient-to-l
|
|
bg-gradient-to-r
|
|
from-riptide-200
|
|
to-mint-200
|
|
dark:from-riptide-500
|
|
dark:to-mint-500
|
|
`,
|
|
dark: `
|
|
group
|
|
dark:text-mint-50
|
|
text-blacktext
|
|
dark:hover:text-white
|
|
px-6
|
|
py-4
|
|
max-xl:px-5
|
|
max-sm:py-2
|
|
max-sm:px-3
|
|
text-lg
|
|
max-xl:text-base
|
|
max-sm:text-sm
|
|
dark:bg-zinc-800
|
|
bg-white
|
|
dark:hover:bg-mint-500
|
|
`,
|
|
};
|
|
|
|
// Icon classes for each variant
|
|
const iconClasses = {
|
|
default: "size-5",
|
|
big: "size-5",
|
|
dark: "size-5 dark:text-mint-300 text-blacktext group-hover:text-blacktext dark:group-hover:text-white transition-colors",
|
|
};
|
|
|
|
// Combine base classes with variant-specific classes
|
|
const buttonClasses = `${baseClasses} ${variantClasses[variant]}`;
|
|
|
|
// Generate aria-label if not provided
|
|
const buttonAriaLabel = ariaLabel || (iconName ? `${text} ${iconName}` : text);
|
|
|
|
// Determine if it's an external link
|
|
const isExternalLink = isExternal || link.startsWith('http');
|
|
|
|
// Additional attributes for external links
|
|
const externalAttributes = isExternalLink ? {
|
|
target: '_blank',
|
|
rel: 'noopener noreferrer'
|
|
} : {};
|
|
|
|
// Loading state
|
|
const loadingText = isLoading ? 'Loading...' : text;
|
|
const loadingAriaLabel = isLoading ? `${buttonAriaLabel} - Loading` : buttonAriaLabel;
|
|
---
|
|
|
|
<div
|
|
class="w-fit h-fit from-transparent via-riptide-300 to-transparent dark:from-transparent dark:via-mint-500 dark:to-transparent from-40% to-60% animate-rotate-border bg-conic/[from_var(--border-angle)] p-px hover:shadow-lg
|
|
hover:shadow-mint-500/30 rounded-full"
|
|
>
|
|
<a
|
|
class:list={[buttonClasses, className]}
|
|
href={disabled ? '#' : link}
|
|
aria-label={loadingAriaLabel}
|
|
role="button"
|
|
aria-disabled={disabled}
|
|
aria-busy={isLoading}
|
|
aria-pressed={isActive}
|
|
{...externalAttributes}
|
|
>
|
|
{iconName && <Icon name={iconName} class={iconClasses[variant]} aria-hidden="true" />}
|
|
{isLoading && <Icon name="mdi:loading" class="animate-spin" aria-hidden="true" />}
|
|
{loadingText}
|
|
</a>
|
|
</div>
|