refactor: memoize icons on export

This commit is contained in:
rusconn
2023-06-24 09:26:37 +09:00
parent 257080b00d
commit 240fba0e74
14 changed files with 74 additions and 101 deletions

View File

@@ -1,5 +1,3 @@
import { useMemo } from "react";
import { icons } from "@/components/icons";
import { BaseButton, BaseButtonProps } from "./base";
@@ -7,7 +5,5 @@ import { BaseButton, BaseButtonProps } from "./base";
export type ClearButtonProps = Omit<BaseButtonProps, "icon" | "labelText">;
export function ClearButton({ iconOnly, ...props }: ClearButtonProps) {
const icon = useMemo(() => <icons.X size={16} />, []);
return <BaseButton {...props} {...{ icon, iconOnly }} labelText="Clear" />;
return <BaseButton {...props} icon={<icons.X size={16} />} {...{ iconOnly }} labelText="Clear" />;
}

View File

@@ -1,4 +1,4 @@
import { useCallback, useMemo } from "react";
import { useCallback } from "react";
import { icons } from "@/components/icons";
@@ -18,7 +18,12 @@ export function CopyButton({ text, iconOnly, ...props }: CopyButtonProps) {
});
}, [text]);
const icon = useMemo(() => <icons.Copy size={16} />, []);
return <BaseButton {...props} {...{ icon, iconOnly, onClick }} labelText="Copy" />;
return (
<BaseButton
{...props}
icon={<icons.Copy size={16} />}
{...{ iconOnly, onClick }}
labelText="Copy"
/>
);
}

View File

@@ -1,4 +1,4 @@
import { useCallback, useMemo, useRef } from "react";
import { useCallback, useRef } from "react";
import { icons } from "@/components/icons";
@@ -55,11 +55,14 @@ export function FileButton({
[maxFileSizeMb, onFileRead]
);
const icon = useMemo(() => <icons.File size={16} />, []);
return (
<>
<BaseButton {...props} {...{ icon, iconOnly, onClick }} labelText="Load a file" />
<BaseButton
{...props}
icon={<icons.File size={16} />}
{...{ iconOnly, onClick }}
labelText="Load a file"
/>
<input hidden type="file" {...{ ref, accept, onChange }} />
</>
);

View File

@@ -1,4 +1,4 @@
import { useCallback, useMemo } from "react";
import { useCallback } from "react";
import { icons } from "@/components/icons";
@@ -21,7 +21,12 @@ export function PasteButton({ iconOnly, onClipboardRead, ...props }: PasteButton
});
}, [onClipboardRead]);
const icon = useMemo(() => <icons.Clipboard size={16} />, []);
return <BaseButton {...props} {...{ icon, iconOnly, onClick }} labelText="Paste" />;
return (
<BaseButton
{...props}
icon={<icons.Clipboard size={16} />}
{...{ iconOnly, onClick }}
labelText="Paste"
/>
);
}

View File

@@ -1,3 +1,4 @@
import { memo, MemoExoticComponent } from "react";
import {
AlignLeft,
ArrowRightLeft,
@@ -29,37 +30,38 @@ import {
X,
type Icon as LucideIcon,
} from "lucide-react";
import equal from "react-fast-compare";
export type Icon = LucideIcon;
export type Icon = LucideIcon | MemoExoticComponent<LucideIcon>;
export const icons = {
AlignLeft,
ArrowRightLeft,
Binary,
Braces,
CaseSensitive,
Check,
ChevronDown,
Clipboard,
Code: Code2,
Copy,
Equal,
File: FileIcon,
Fingerprint,
Hash,
Home,
Key,
Link: Link2,
PackagePlus,
Paintbrush: Paintbrush2,
Search,
Settings,
Settings2,
Space,
Sun: SunMedium,
Minus,
Moon,
X,
AlignLeft: memo(AlignLeft, equal),
ArrowRightLeft: memo(ArrowRightLeft, equal),
Binary: memo(Binary, equal),
Braces: memo(Braces, equal),
CaseSensitive: memo(CaseSensitive, equal),
Check: memo(Check, equal),
ChevronDown: memo(ChevronDown, equal),
Clipboard: memo(Clipboard, equal),
Code: memo(Code2, equal),
Copy: memo(Copy, equal),
Equal: memo(Equal, equal),
File: memo(FileIcon, equal),
Fingerprint: memo(Fingerprint, equal),
Hash: memo(Hash, equal),
Home: memo(Home, equal),
Key: memo(Key, equal),
Link: memo(Link2, equal),
PackagePlus: memo(PackagePlus, equal),
Paintbrush: memo(Paintbrush2, equal),
Search: memo(Search, equal),
Settings: memo(Settings, equal),
Settings2: memo(Settings2, equal),
Space: memo(Space, equal),
Sun: memo(SunMedium, equal),
Minus: memo(Minus, equal),
Moon: memo(Moon, equal),
X: memo(X, equal),
GitHub: (props: LucideProps) => (
<svg viewBox="0 0 438.549 438.549" {...props}>
<path

View File

@@ -1,6 +1,6 @@
"use client";
import { useEffect, useMemo, useRef, useState } from "react";
import { useEffect, useRef, useState } from "react";
import { useRouter } from "next/navigation";
import { useSetSearchText } from "@/contexts/search-text";
@@ -40,13 +40,6 @@ export function SearchBar() {
inputRef.current?.focus();
};
const clearIcon = useMemo(() => <icons.X className="p-1 text-muted-foreground" />, []);
const searchIcon = useMemo(
() => <icons.Search className="-scale-x-100 p-1 text-muted-foreground" />,
[]
);
return (
<div className="relative flex w-full items-center">
<Input
@@ -59,11 +52,11 @@ export function SearchBar() {
/>
<div className="absolute right-1 flex gap-1">
<Button className={cn("h-6 p-0", !text && "hidden")} variant="ghost" onClick={clearText}>
{clearIcon}
<icons.X className="p-1 text-muted-foreground" />
<span className="sr-only">Clear search text</span>
</Button>
<Button className="h-6 p-0" variant="ghost" onClick={search} aria-label="search">
{searchIcon}
<icons.Search className="-scale-x-100 p-1 text-muted-foreground" />
<span className="sr-only">Search tools</span>
</Button>
</div>

View File

@@ -1,6 +1,6 @@
"use client";
import { useCallback, useMemo, useRef } from "react";
import { useCallback, useRef } from "react";
import { usePathname } from "next/navigation";
import * as Accordion from "@radix-ui/react-accordion";
@@ -20,11 +20,6 @@ export function ToolGroup({ Icon, title, href, tools, isOpend }: Props) {
const onClick = useCallback(() => triggerRef.current?.click(), []);
const chevronIcon = useMemo(
() => <icons.ChevronDown className="h-4 w-4 transition-transform duration-200" />,
[]
);
return (
<Accordion.AccordionItem value={href}>
<Accordion.Header asChild>
@@ -46,7 +41,7 @@ export function ToolGroup({ Icon, title, href, tools, isOpend }: Props) {
className="absolute right-0 flex h-10 w-10 items-center justify-center rounded transition-all duration-0 hover:bg-accent [&[data-state=open]>svg]:rotate-180"
aria-label="toggle open/close state of the tool group"
>
{chevronIcon}
<icons.ChevronDown className="h-4 w-4 transition-transform duration-200" />
</Accordion.Trigger>
</div>
</Accordion.Header>

View File

@@ -1,6 +1,6 @@
"use client";
import { memo, useMemo } from "react";
import { memo } from "react";
import Link, { LinkProps } from "next/link";
import { Tool } from "@/config/tools";
@@ -13,8 +13,6 @@ type Props = Pick<Tool, "Icon" | "shortTitle"> &
};
function RawToolLink({ Icon, shortTitle: title, href, onClick, className, highlight }: Props) {
const icon = useMemo(() => <Icon size={16} />, [Icon]);
return (
<Link
className={cn(
@@ -28,7 +26,7 @@ function RawToolLink({ Icon, shortTitle: title, href, onClick, className, highli
<Indicator />
</span>
<span className="flex select-none items-center">
{icon}
<Icon size={16} />
<span className="ml-4">{title}</span>
</span>
</Link>

View File

@@ -1,6 +1,5 @@
"use client";
import { useMemo } from "react";
import { useTheme } from "next-themes";
import { Button } from "@/components/ui/button";
@@ -9,27 +8,14 @@ import { icons } from "@/components/icons";
export function ThemeToggle() {
const { resolvedTheme, setTheme } = useTheme();
const sunIcon = useMemo(
() => (
<icons.Sun className="h-7 w-7 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
),
[]
);
const moonIcon = useMemo(
() => (
<icons.Moon className="absolute h-7 w-7 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
),
[]
);
return (
<Button
className="h-10 w-10 p-0"
variant="ghost"
onClick={() => setTheme(resolvedTheme === "light" ? "dark" : "light")}
>
{sunIcon}
{moonIcon}
<icons.Sun className="h-7 w-7 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
<icons.Moon className="absolute h-7 w-7 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
<span className="sr-only">Toggle theme</span>
</Button>
);