personal web client for Bluesky
typescript
solidjs
bluesky
atcute
1import type { Component, JSX } from 'solid-js';
2
3import { useFieldset } from './fieldset';
4
5export interface IconButtonProps {
6 icon: Component;
7 title: string;
8 // href?: string;
9 disabled?: boolean;
10 onClick?: JSX.EventHandler<HTMLButtonElement, MouseEvent>;
11
12 variant?: 'ghost' | 'outline' | 'accent' | 'danger' | 'black';
13 size?: 'md' | 'sm';
14 class?: string;
15}
16
17const IconButton = (props: IconButtonProps) => {
18 const fieldset = useFieldset();
19 const isDisabled = (): boolean => fieldset.disabled || !!props.disabled;
20
21 return (
22 <button
23 type="button"
24 disabled={isDisabled()}
25 title={props.title}
26 onClick={props.onClick}
27 class={iconButtonClasses(isDisabled, props)}
28 >
29 {(() => {
30 const Icon = props.icon;
31 return <Icon />;
32 })()}
33 </button>
34 );
35};
36
37const iconButtonClasses = (
38 isDisabled: () => boolean,
39 { variant = 'ghost', size = 'md', class: className }: IconButtonProps,
40) => {
41 var cn = `grid shrink-0 place-items-center`;
42
43 if (variant === 'ghost') {
44 cn += ` rounded-full text-contrast`;
45
46 if (!isDisabled()) {
47 cn += ` hover:bg-contrast-hinted/md active:bg-contrast-hinted/md-pressed`;
48 } else {
49 cn += ` opacity-50`;
50 }
51 } else if (variant === 'outline') {
52 cn += ` rounded border border-outline-lg text-contrast`;
53
54 if (!isDisabled()) {
55 cn += ` hover:bg-contrast-hinted/md active:bg-contrast-hinted/md-pressed`;
56 } else {
57 cn += ` opacity-50`;
58 }
59 } else if (variant === 'accent') {
60 cn += ` rounded-full text-accent`;
61
62 if (!isDisabled()) {
63 cn += ` hover:bg-accent/md active:bg-accent/md-pressed`;
64 } else {
65 cn += ` opacity-50`;
66 }
67 } else if (variant === 'black') {
68 cn += ` rounded-full bg-p-neutral-950/75 text-white`;
69
70 if (!isDisabled()) {
71 cn += ` hover:bg-p-neutral-800/75 active:bg-p-neutral-700/75`;
72 } else {
73 cn += ` opacity-50`;
74 }
75 } else if (variant === 'danger') {
76 cn += ` rounded-full text-error`;
77
78 if (!isDisabled()) {
79 cn += ` hover:bg-error/md active:bg-error/md-pressed`;
80 } else {
81 cn += ` opacity-50`;
82 }
83 }
84
85 if (size === 'md') {
86 cn += ` h-9 w-9 text-lg`;
87 } else if (size === 'sm') {
88 cn += ` h-8 w-8 text-lg`;
89 }
90
91 if (className) {
92 return `${cn} ${className}`;
93 } else {
94 return cn;
95 }
96};
97
98export default IconButton;