Skip to content

Commit

Permalink
🎨 Add light/dark theme + custom theme switcher & update UI components…
Browse files Browse the repository at this point in the history
… with new theme mode
  • Loading branch information
pheralb committed Oct 26, 2024
1 parent 8ff9fdd commit fe9a43d
Show file tree
Hide file tree
Showing 21 changed files with 537 additions and 44 deletions.
7 changes: 5 additions & 2 deletions website/app/components/card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,17 @@ const Card = (props: iCard) => {
};

return (
<div className="group flex flex-col items-center justify-center space-y-1 rounded-lg border border-zinc-800 px-4 pb-2 pt-4 transition-colors hover:bg-zinc-800/50">
<div className="group flex flex-col items-center justify-center space-y-1 rounded-lg border border-zinc-200 px-4 pb-2 pt-4 hover:bg-zinc-200/50 dark:border-zinc-800 dark:hover:bg-zinc-800/50">
<props.icon width={props.iconSize} height={props.iconSize} />
<p className="text-sm tracking-tight text-white">{props.name}</p>
<p className="text-sm tracking-tight text-black dark:text-white">
{props.name}
</p>
<div className="flex items-center space-x-1">
<Button
variant="ghost"
size="icon"
onClick={handleCopy}
className="transition-none"
title="Copy to clipboard"
>
<CopyIcon width={17} height={17} strokeWidth={1.5} />
Expand Down
14 changes: 7 additions & 7 deletions website/app/components/footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,37 @@ import { containerClasses } from "@/ui/container";

const Footer = () => {
return (
<footer className="animate-in slide-in-from-bottom-3 fade-in-30 fixed bottom-0 w-full bg-zinc-900/80 py-4 text-sm text-zinc-400 backdrop-blur-sm duration-500">
<footer className="animate-in slide-in-from-bottom-3 fade-in-30 fixed bottom-0 w-full bg-zinc-50 py-4 text-sm text-zinc-600 backdrop-blur-sm dark:bg-zinc-900/80 dark:text-zinc-400">
<div
className={cn(containerClasses, "flex items-center justify-between")}
>
<ExternalLink
title="Miguel Solorio"
href="https://www.miguelsolorio.com/"
className="group flex items-center space-x-2 transition-colors hover:text-white"
className="group flex items-center space-x-2 transition-colors hover:text-black dark:hover:text-white"
>
<span className="hidden md:block">Icons crafted by </span>
<img
className="h-6 w-6 rounded-full transition-shadow group-hover:ring-2 group-hover:ring-react-symbol-pink"
className="group-hover:ring-react-symbol-pink h-6 w-6 rounded-full transition-shadow group-hover:ring-2"
src="https://avatars.githubusercontent.com/u/35271042?v=4"
alt="Miguel Solorio"
/>
<span className="underline decoration-zinc-500 decoration-wavy underline-offset-[4px] group-hover:decoration-react-symbol-pink">
<span className="group-hover:decoration-react-symbol-pink underline decoration-zinc-500 decoration-wavy underline-offset-[4px]">
Miguel Solorio
</span>
</ExternalLink>
<ExternalLink
title="Pablo Hernández"
href="https://pheralb.dev"
className="group flex items-center space-x-2 transition-colors hover:text-white"
className="group flex items-center space-x-2 transition-colors hover:text-black dark:hover:text-white"
>
<span className="hidden md:block">Website by</span>
<img
className="h-6 w-6 rounded-full transition-shadow group-hover:ring-2 group-hover:ring-react-symbol-aqua"
className="group-hover:ring-react-symbol-aqua h-6 w-6 rounded-full transition-shadow group-hover:ring-2"
src="https://avatars.githubusercontent.com/u/62877300?v=4"
alt="Pablo Hernández"
/>
<span className="underline decoration-zinc-500 decoration-wavy underline-offset-[4px] group-hover:decoration-react-symbol-aqua">
<span className="group-hover:decoration-react-symbol-aqua underline decoration-zinc-500 decoration-wavy underline-offset-[4px]">
Pablo Hernández
</span>
</ExternalLink>
Expand Down
7 changes: 4 additions & 3 deletions website/app/components/getCode/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ const GetCode = (props: iGetCode) => {
variant="ghost"
size="icon"
onClick={() => handleGetCode()}
className="transition-none"
title="Get React Component"
>
<CodeIcon width={17} height={17} strokeWidth={1.5} />
Expand All @@ -95,11 +96,11 @@ const GetCode = (props: iGetCode) => {
</div>
) : fileContent ? (
<div className="my-1 flex flex-col space-y-1 overflow-hidden">
<div className="mr-1 flex items-center justify-end space-x-2 font-mono text-[12px] text-zinc-400">
<div className="mr-1 flex items-center justify-end space-x-2 font-mono text-[12px] text-zinc-600 dark:text-zinc-400">
<Reactjs width={16} height={16} />
<span>{camelCase(props.componentName)}.tsx</span>
</div>
<div className="max-h-80 rounded-lg border border-zinc-800 p-3 font-mono text-sm hover:overflow-auto">
<div className="max-h-80 rounded-lg border border-zinc-200 p-3 font-mono text-sm hover:overflow-auto dark:border-zinc-800">
<pre
className="select-all"
dangerouslySetInnerHTML={{ __html: highlight(fileContent) }}
Expand All @@ -109,7 +110,7 @@ const GetCode = (props: iGetCode) => {
) : (
<div className="my-4 flex flex-col items-center justify-center gap-2">
<AlertIcon
height={25}
height={30}
className="flex items-center justify-center"
/>
<p className="text-sm text-zinc-400">
Expand Down
20 changes: 12 additions & 8 deletions website/app/components/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ const linkClasses = buttonVariants({
className: "rounded-3xl w-auto group",
});

const arrowClasses = cn(
"text-zinc-400 transition-transform group-hover:translate-x-[0.1rem] group-hover:text-black dark:group-hover:text-white",
);

interface iHeaderProps {
npmVersion: string;
}
Expand All @@ -38,7 +42,7 @@ const Header = (props: iHeaderProps) => {
<section
className={cn(
"pb-4 pt-8 md:py-10",
"flex flex-col space-y-6",
"flex flex-col space-y-5",
containerClasses,
)}
>
Expand All @@ -51,17 +55,17 @@ const Header = (props: iHeaderProps) => {
>
React-Symbols
</Link>
<div className="flex flex-col items-start space-x-0 space-y-2 text-sm text-zinc-400 md:flex-row md:space-x-2 md:space-y-0 md:text-[16px]">
<div className="flex flex-col items-start space-x-0 space-y-2 text-sm text-zinc-600 md:flex-row md:space-x-2 md:space-y-0 md:text-[16px] dark:text-zinc-400">
<span>
Beautifully File & Folder Icons for your React projects.
</span>
</div>
</div>
</div>
<div className="flex w-full flex-col items-center space-x-0 space-y-4 md:w-auto md:flex-row md:space-x-4 md:space-y-0">
<div className="mb-1 flex w-full flex-col items-center space-x-0 space-y-4 md:w-auto md:flex-row md:space-x-4 md:space-y-0">
<InstallCommand className="w-full md:w-auto" />
<Divider className="hidden md:block" />
<nav className="container flex items-center space-x-2 overflow-y-auto md:w-auto">
<nav className="container flex items-center space-x-2 overflow-y-auto pb-1 md:w-auto">
<ExternalLink
title="NPM Package"
href="https://www.npmjs.com/package/@react-symbols/icons"
Expand All @@ -73,7 +77,7 @@ const Header = (props: iHeaderProps) => {
height={13}
width={13}
strokeWidth={2}
className="text-zinc-400 transition-transform duration-200 group-hover:translate-x-[0.1rem] group-hover:text-white"
className={arrowClasses}
/>
</ExternalLink>
<ExternalLink
Expand All @@ -87,7 +91,7 @@ const Header = (props: iHeaderProps) => {
height={13}
width={13}
strokeWidth={2}
className="text-zinc-400 transition-transform duration-200 group-hover:translate-x-[0.07rem] group-hover:text-white"
className={arrowClasses}
/>
</ExternalLink>
<ExternalLink
Expand All @@ -101,7 +105,7 @@ const Header = (props: iHeaderProps) => {
height={13}
width={13}
strokeWidth={2}
className="text-zinc-400 transition-transform duration-200 group-hover:translate-x-[0.07rem] group-hover:text-white"
className={arrowClasses}
/>
</ExternalLink>
<ExternalLink
Expand All @@ -115,7 +119,7 @@ const Header = (props: iHeaderProps) => {
height={13}
width={13}
strokeWidth={2}
className="text-zinc-400 transition-transform duration-200 group-hover:translate-x-[0.07rem] group-hover:text-white"
className={arrowClasses}
/>
</ExternalLink>
</nav>
Expand Down
3 changes: 2 additions & 1 deletion website/app/components/installCommand.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,9 @@ const InstallCommand = (props: iInstallCommandProps) => {
className={cn(
buttonVariants({
variant: "outline",
className: "active:scale-100",
}),
"select-all space-x-3 rounded-3xl text-zinc-400 transition-colors hover:bg-transparent hover:text-white dark:hover:bg-transparent",
"select-all space-x-3 rounded-3xl text-zinc-600 transition-colors hover:bg-transparent dark:text-zinc-400 dark:hover:bg-transparent dark:hover:text-white",
props.className,
)}
>
Expand Down
2 changes: 1 addition & 1 deletion website/app/components/loading.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ interface iLoading {
const Loading = (props: iLoading) => (
<div
className={cn(
"animate-in animate-out fade-in-40 flex flex-col space-y-2 duration-1000",
"animate-in animate-out fade-in-40 flex flex-col space-y-2 ",
props.className,
)}
>
Expand Down
11 changes: 6 additions & 5 deletions website/app/components/navbar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const NavIconsRoutes = [
const Navbar = () => {
const location = useLocation();
return (
<nav className="sticky -top-1 z-50 border-y border-zinc-800 bg-zinc-900/80 py-[10px] backdrop-blur-sm">
<nav className="sticky -top-1 z-40 border-y border-zinc-200 bg-zinc-100/80 py-[10px] backdrop-blur-sm dark:border-zinc-800 dark:bg-zinc-900/80">
<div
className={cn(
containerClasses,
Expand All @@ -46,7 +46,7 @@ const Navbar = () => {
? `Search ${totalFolders} folder icons...`
: `Search ${totalLibraryIcons} icons...`
}
className="rounded-none border-b border-l-0 border-r-0 border-t-0 pl-[34px] text-[16px] placeholder:text-[16px] focus:border-none focus:ring-0 md:border-none md:pl-[38px] dark:focus:border-none"
className="rounded-none border-b border-l-0 border-r-0 border-t-0 pl-[34px] text-[16px] shadow-none placeholder:text-[16px] focus:border-none focus:ring-0 focus-visible:ring-0 md:border-none md:pl-[38px] dark:focus:border-none dark:focus:ring-0"
/>
</div>
<Divider className="hidden md:block" />
Expand All @@ -61,11 +61,12 @@ const Navbar = () => {
className={cn(
buttonVariants({
variant: "outline",
className: "shadow-none",
}),
"w-full md:w-auto",
location.pathname === link.href
? "border-zinc-400 text-white"
: "border-none bg-transparent text-zinc-400 hover:text-white dark:bg-transparent",
? "border-zinc-200 text-black dark:border-zinc-800 dark:text-white"
: "border-none bg-transparent text-zinc-600 hover:text-black dark:bg-transparent dark:text-zinc-400 dark:hover:text-white",
)}
>
{location.pathname === link.href ? (
Expand All @@ -78,7 +79,7 @@ const Navbar = () => {
))}
</div>
<Divider className="hidden md:block" />
<div className="flex w-full flex-col space-y-1 pb-1 text-zinc-400 transition-colors hover:text-white md:w-56 md:pb-0">
<div className="flex w-full flex-col space-y-1 pb-1 text-zinc-600 hover:text-black md:w-56 md:pb-0 dark:text-zinc-400 dark:hover:text-white">
<p className="select-none text-xs font-medium uppercase">Size</p>
<IconSize />
</div>
Expand Down
11 changes: 11 additions & 0 deletions website/app/components/settings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import ThemeSwitcher from "./themeSwitcher";

const Settings = () => {
return (
<nav className="fixed right-3 top-2 z-50 md:top-3">
<ThemeSwitcher />
</nav>
);
};

export default Settings;
41 changes: 41 additions & 0 deletions website/app/components/themeSwitcher.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { type Theme, useTheme } from "@/theme/themeProvider";
import { MoonIcon, SunIcon } from "@/ui/icons/feather";
import { cn } from "@/utils";

const ThemeSwitcher = () => {
const [theme, setTheme] = useTheme();

const buttons = [
{
label: "dark" as const,
icon: <MoonIcon width={14} />,
active: theme === "dark",
},
{
label: "light" as const,
icon: <SunIcon width={14} />,
active: theme === "light",
},
];

return (
<span className="flex w-fit items-center gap-0.5 overflow-hidden rounded-md border border-zinc-200 bg-white dark:border-zinc-800 dark:bg-zinc-800/80">
{buttons.map(({ label, icon, active }) => (
<button
type="button"
title={`Switch to ${label} theme`}
key={label}
onClick={() => setTheme(() => label as Theme)}
className={cn(
"flex h-6 w-6 items-center justify-center rounded-none transition-all hover:opacity-50",
active && "bg-zinc-200 dark:bg-zinc-900",
)}
>
{icon}
</button>
))}
</span>
);
};

export default ThemeSwitcher;
5 changes: 3 additions & 2 deletions website/app/providers/sonner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ const Toaster = ({ ...props }: ToasterProps) => {
toastOptions={{
classNames: {
toast:
"group toast group-[.toaster]:bg-zinc-900 group-[.toaster]:text-zinc-50 group-[.toaster]:border-zinc-800 group-[.toaster]:shadow-lg",
description: "group-[.toaster]:text-zinc-400 font-mono",
"group toast group-[.toaster]:bg-zinc-100 dark:group-[.toaster]:bg-zinc-900 group-[.toaster]:text-zinc-950 dark:group-[.toaster]:text-zinc-50 group-[.toaster]:border-zinc-200 dark:group-[.toaster]:border-zinc-800 group-[.toaster]:shadow-lg",
description:
"group-[.toaster]:text-zinc-600 dark:group-[.toaster]:text-zinc-400 font-mono",
icon: "group-[.toaster]:mr-3",
},
}}
Expand Down
42 changes: 34 additions & 8 deletions website/app/root.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import type { ReactNode } from "react";
import type { LinksFunction, MetaFunction } from "@vercel/remix";
import type {
LinksFunction,
LoaderFunctionArgs,
MetaFunction,
} from "@vercel/remix";

import {
json,
Expand All @@ -25,6 +29,16 @@ import Navbar from "./components/navbar";
// Providers:
import { Toaster } from "./providers/sonner";

// Theme:
import {
ThemeBody,
ThemeHead,
ThemeProvider,
useTheme,
} from "./theme/themeProvider";
import { getThemeSession } from "./theme/themeServer";
import Settings from "./components/settings";

// Links:
export const links: LinksFunction = () => [
{ rel: "stylesheet", href: tailwind },
Expand Down Expand Up @@ -82,16 +96,18 @@ export const meta: MetaFunction = () => {
];
};

export async function loader() {
export async function loader({ request }: LoaderFunctionArgs) {
const metadata = await getLatestVersion(globals.npmPackageName);
return json({ version: metadata.version });
const themeSession = await getThemeSession(request);
return json({ version: metadata.version, theme: themeSession.getTheme() });
}

// App Layout:
export function Layout({ children }: { children: ReactNode }) {
function App({ children }: { children: ReactNode }) {
const data = useLoaderData<typeof loader>();
const [theme] = useTheme();
return (
<html lang="en" className="dark" style={{ colorScheme: "dark" }}>
<html lang="en" className={cn(theme)} style={{ colorScheme: theme! }}>
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
Expand Down Expand Up @@ -125,18 +141,21 @@ export function Layout({ children }: { children: ReactNode }) {
<meta name="twitter:title" content="React-Symbols" />
<Meta />
<Links />
<ThemeHead ssrTheme={Boolean(data.theme)} />
</head>
<body
className={cn(
"font-sans antialiased",
"bg-zinc-50 text-black dark:bg-zinc-900 dark:text-white",
"selection:bg-zinc-300 selection:text-zinc-900 dark:selection:bg-zinc-700 dark:selection:text-zinc-50",
"scroll-smooth",
"relative",
)}
>
<Header npmVersion={data.version!} />
<Settings />
<Navbar />
{children}
<ThemeBody ssrTheme={Boolean(data.theme)} />
<Footer />
<Toaster />
<ScrollRestoration />
Expand All @@ -146,6 +165,13 @@ export function Layout({ children }: { children: ReactNode }) {
);
}

export default function App() {
return <Outlet />;
export default function AppWithProviders() {
const data = useLoaderData<typeof loader>();
return (
<ThemeProvider specifiedTheme={data.theme}>
<App>
<Outlet />
</App>
</ThemeProvider>
);
}
2 changes: 1 addition & 1 deletion website/app/routes/_index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export default function Index() {
) as iIcons[];

return (
<main className="animate-in fade-in-60 duration-700">
<main className="animate-in fade-in-60">
{filteredIcons.length === 0 ? (
<NotFound input={search} />
) : (
Expand Down
Loading

0 comments on commit fe9a43d

Please sign in to comment.