Skip to content

Instantly share code, notes, and snippets.

@navin-moorthy
Last active August 30, 2023 15:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save navin-moorthy/670eae0802376b6d85bd21c214002f48 to your computer and use it in GitHub Desktop.
Save navin-moorthy/670eae0802376b6d85bd21c214002f48 to your computer and use it in GitHub Desktop.
React Utils
import { twMerge, type ClassNameValue } from "tailwind-merge";
export function cn(...inputs: ClassNameValue[]) {
return twMerge(inputs);
}
"use client";
import {
createContext,
useContext,
useMemo,
type Dispatch,
type FC,
type ReactNode,
type SetStateAction,
} from "react";
import { cn } from "@/utils/cn";
import { noop } from "@/utils/noop";
import useLocalStorage from "@/hooks/use-local-storage";
import { defaultFontMapper, displayFontMapper } from "@/styles/fonts";
type DefaultFontType = keyof typeof defaultFontMapper;
type GlobalFontContextGetterType = DefaultFontType;
type GlobalFontContextSetterType = Dispatch<SetStateAction<DefaultFontType>>;
const GlobalFontContextGetter =
createContext<GlobalFontContextGetterType>("Default");
const GlobalFontContextSetter =
createContext<GlobalFontContextSetterType>(noop);
export const useGlobalFont = () => {
return useContext(GlobalFontContextGetter);
};
export const useSetGlobalFont = () => {
return useContext(GlobalFontContextSetter);
};
export type GlobalFontContextProviderProps = {
readonly children: ReactNode;
};
export const GlobalFontContextProvider: FC<GlobalFontContextProviderProps> = (
props,
) => {
const { children } = props;
const [globalFont, setGlobalFont] = useLocalStorage<DefaultFontType>(
"global-font",
{
defaultValue: "Default",
},
);
const getterValue = useMemo(() => {
return globalFont;
}, [globalFont]);
const setterValue = useMemo(() => {
return setGlobalFont;
}, [setGlobalFont]);
return (
<GlobalFontContextGetter.Provider value={getterValue}>
<GlobalFontContextSetter.Provider value={setterValue}>
<div
className={cn(
displayFontMapper[globalFont],
defaultFontMapper[globalFont],
)}
role="presentation"
>
{children}
</div>
</GlobalFontContextSetter.Provider>
</GlobalFontContextGetter.Provider>
);
};
import { Crimson_Text, Inconsolata, Inter } from "next/font/google";
import localFont from "next/font/local";
const cal = localFont({
src: "./CalSans-SemiBold.otf",
variable: "--font-display",
});
const crimsonBold = Crimson_Text({
weight: "700",
variable: "--font-display",
subsets: ["latin"],
});
const inter = Inter({
variable: "--font-default",
subsets: ["latin"],
});
const inconsolataBold = Inconsolata({
weight: "700",
variable: "--font-display",
subsets: ["latin"],
});
const crimson = Crimson_Text({
weight: "400",
variable: "--font-default",
subsets: ["latin"],
});
const inconsolata = Inconsolata({
variable: "--font-default",
subsets: ["latin"],
});
export const displayFontMapper = {
Default: cal.variable,
Serif: crimsonBold.variable,
Mono: inconsolataBold.variable,
};
export const defaultFontMapper = {
Default: inter.variable,
Serif: crimson.variable,
Mono: inconsolata.variable,
};
// https://www.jameskerr.blog/posts/use-data-transition/
export function useDataTransition<T>(
real: T,
inTransition: boolean,
timeout: number
) {
const [timeExpired, setTimeExpired] = useState(false);
const cache = useRef(real);
useEffect(() => {
if (!inTransition) cache.current = real;
}, [inTransition, real]);
useEffect(() => {
let id: number;
if (inTransition) {
id = setTimeout(() => setTimeExpired(true), timeout);
} else {
setTimeExpired(false);
}
return () => clearTimeout(id);
}, [inTransition]);
if (inTransition && !timeExpired) return cache.current;
else return real;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment