learn and share notes on atproto (wip) 馃
malfestio.stormlightlabs.org/
readability
solid
axum
atproto
srs
1import { useDensity } from "$lib/density-context";
2import type { DensityMode } from "$lib/design-tokens";
3import { splitProps } from "solid-js";
4import type { Component, JSX } from "solid-js";
5
6type ButtonVariant = "primary" | "secondary" | "danger" | "ghost";
7type ButtonSize = "sm" | "md" | "lg";
8type ButtonProps = { variant?: ButtonVariant; size?: ButtonSize; density?: DensityMode };
9
10export const Button: Component<JSX.ButtonHTMLAttributes<HTMLButtonElement> & ButtonProps> = (props) => {
11 const [local, others] = splitProps(props, ["variant", "size", "density", "class", "children"]);
12 const globalDensity = useDensity();
13 const density = () => local.density || globalDensity;
14 const base = () => local.size || "md";
15
16 const variantClass = () => {
17 switch (local.variant) {
18 case "secondary":
19 return "bg-gray-800 text-white hover:bg-gray-700";
20 case "danger":
21 return "bg-red-600 text-white hover:bg-red-500";
22 case "ghost":
23 return "bg-transparent text-gray-300 hover:bg-gray-800 hover:text-white";
24 case "primary":
25 default:
26 return "bg-blue-600 text-white hover:bg-blue-500";
27 }
28 };
29
30 const sizeClass = () => {
31 const densityMode = density();
32 const baseSize = base();
33 if (baseSize === "sm") {
34 return densityMode === "compact"
35 ? "px-2 py-1 text-xs"
36 : densityMode === "spacious"
37 ? "px-4 py-2 text-sm"
38 : "px-3 py-1.5 text-sm";
39 }
40
41 if (baseSize === "lg") {
42 return densityMode === "compact"
43 ? "px-5 py-2 text-base"
44 : densityMode === "spacious"
45 ? "px-8 py-4 text-xl"
46 : "px-6 py-3 text-lg";
47 }
48
49 return densityMode === "compact"
50 ? "px-3 py-1.5 text-sm"
51 : densityMode === "spacious"
52 ? "px-6 py-3 text-base"
53 : "px-4 py-2";
54 };
55
56 return (
57 <button
58 class={`
59 inline-flex items-center justify-center rounded-sm transition-standard font-medium
60 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:ring-offset-gray-900
61 disabled:opacity-50 disabled:cursor-not-allowed
62 ${variantClass()}
63 ${sizeClass()}
64 ${local.class || ""}
65 `}
66 {...others}>
67 {local.children}
68 </button>
69 );
70};