Skip to content

Instantly share code, notes, and snippets.

@acorn1010
Created October 8, 2024 23:35
Show Gist options
  • Save acorn1010/656dd3287c0a5852ab5d10cd878b71b6 to your computer and use it in GitHub Desktop.
Save acorn1010/656dd3287c0a5852ab5d10cd878b71b6 to your computer and use it in GitHub Desktop.
base Icon.tsx
/** This is from acorn1010's MUI alternative, Base. It's a very light FontAwesome Icon replacement. */
import React, {CSSProperties} from "react";
import {IconDefinition} from "@fortawesome/pro-regular-svg-icons";
import {cn} from "~/lib/utils";
export type IconProp = IconDefinition;
type IconSize = 'xs' | 'sm' | '1x' | 'lg' | '2x' | '3x' | '4x';
const SIZE_CLASSES = {
xs: 'text-[.75em]',
sm: 'text-[.875em]',
'1x': 'text-[1em]',
lg: 'text-lg',
'2x': 'text-[2em]',
'3x': 'text-[3em]',
'4x': 'text-[4em]',
} satisfies {[key in IconSize]: string};
const FIXED_WIDTH_CLASSES = {
xs: 'w-[.8em] h-[.8em]',
sm: 'w-[1em] h-[1em]',
'1x': 'w-[1.25em] h-[1.25em]',
lg: 'w-[1.5em] h-[1.5em]',
'2x': 'w-[2.5em] h-[2.5em]',
'3x': 'w-[3.75em] h-[3.75em]',
'4x': 'w-[5em] h-[5em]',
} satisfies {[key in IconSize]: string};
type IconProps = {
className?: string,
/** Classes to apply to the secondary path for duotone icons. */
secondaryClassName?: string,
/** The text-color to apply to the icon. */
color?: string,
icon: IconProp,
style?: CSSProperties,
fixedWidth?: boolean,
spin?: boolean,
size?: IconSize,
};
/**
* Displays a FontAwesome icon. We use this wrapper exclusively instead of using <FontAwesomeIcon />
* because FontAwesomeIcon adds 20 KB of gzip size--wtf?!
*/
export function Icon(props: IconProps) {
const {className, secondaryClassName, color, icon, fixedWidth, spin, size, style} = props;
const [width, height, _, _2, d] = icon.icon;
const paths = Array.isArray(d) ? d : [d];
return (
<svg
className={cn(
'h-[1em] inline-block box-content',
fixedWidth && FIXED_WIDTH_CLASSES[size || '1x'],
spin && 'animate-spin',
SIZE_CLASSES[size || '1x'],
className,
)}
style={style}
role='img'
xmlns='http://www.w3.org/2000/svg'
data-prefix={icon.prefix}
data-icon={icon.iconName}
viewBox={`0 0 ${width} ${height}`}>
{paths.length > 1
? <g>{paths.map((pathData, i) => <path key={i} className={cn(i === 0 && 'opacity-40', i === 0 && secondaryClassName)} fill={color || 'currentColor'} d={pathData} style={style} />)}</g>
: paths.map((pathData, i) => <path key={i} fill={color || 'currentColor'} d={pathData} style={style} />)}
</svg>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment