feat(app): major refactorings and details footer updates
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
export { default as useCSSVariables } from "./useCSSVariables";
|
||||
export { default as useDebounce } from "./useDebounce";
|
||||
export { default as useEvent } from "./useEvent";
|
||||
export { default as useIconParameters } from "./useIconParameters";
|
||||
export { default as useMediaQuery } from "./useMediaQuery";
|
||||
export { default as usePersistSettings } from "./usePersistSettings";
|
||||
export { default as useSessionState } from "./useSessionState";
|
||||
export { default as useThrottle } from "./useThrottle";
|
||||
export { default as useThrottled } from "./useThrottled";
|
||||
export { default as useTimeoutFn } from "./useTimeoutFn";
|
||||
|
||||
40
src/hooks/useCSSVariables.ts
Normal file
40
src/hooks/useCSSVariables.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { useEffect, useRef } from "react";
|
||||
|
||||
type CSSCustomPropertyName = `--${string}`;
|
||||
|
||||
type CSSCustomProperties = {
|
||||
[property: CSSCustomPropertyName]: string | null;
|
||||
};
|
||||
|
||||
function simpleDiff(prev: CSSCustomProperties, next: CSSCustomProperties) {
|
||||
const merge = { ...prev, ...next };
|
||||
return Object.entries(merge).reduce<
|
||||
[property: CSSCustomPropertyName, value: string | null][]
|
||||
>((acc, [k, val]) => {
|
||||
let key = k as CSSCustomPropertyName;
|
||||
|
||||
if (
|
||||
!prev[key as CSSCustomPropertyName] ||
|
||||
prev[key as CSSCustomPropertyName] !== val
|
||||
) {
|
||||
acc.push([key, val]);
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
}
|
||||
|
||||
export default function useCSSVariables(properties: CSSCustomProperties) {
|
||||
const p = useRef<CSSCustomProperties>({});
|
||||
|
||||
useEffect(() => {
|
||||
const diff = simpleDiff(p.current, properties);
|
||||
|
||||
if (diff.length > 0) {
|
||||
diff.forEach(([key, value]) => {
|
||||
document.documentElement.style.setProperty(key, value);
|
||||
});
|
||||
|
||||
p.current = properties;
|
||||
}
|
||||
}, [properties]);
|
||||
}
|
||||
@@ -18,7 +18,7 @@ export type UseEventType<E extends UseEventTarget> = keyof UseEventMap<E>;
|
||||
* provided event name (currently supports {@link Window}, {@link Document},
|
||||
* and subclasses of {@link HTMLElement} and {@link SVGElement}).
|
||||
*
|
||||
* @param type an {@link https://developer.mozilla.org/en-US/docs/Web/Events#event_listing event type}
|
||||
* @param type an {@link https://developer.mozilla.org/en-US/docs/Web/Events#event_listing event type}
|
||||
* @param listener a callback to be fired on the event
|
||||
* @param options {@link AddEventListenerOptions}
|
||||
* @param el the target element to attack the listener. Defaults to
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import { useWindowSize } from "react-use";
|
||||
|
||||
const MOBILE_BREAKPOINT = 536;
|
||||
|
||||
const GRID_PADDING = 32; // .grid-container { padding }
|
||||
const TOOLBAR_WIDTH = 17; // IS THIS BROWSER-SPECIFIC?
|
||||
const MAX_GRID_WIDTH = 1120; // .grid { max-width }
|
||||
const ITEM_WIDTH = 168; // .grid-item { width; height; margin }
|
||||
const ITEM_WIDTH_MOBILE = 108; // .grid-item { width; height; margin }
|
||||
|
||||
export default (): number => {
|
||||
const { width } = useWindowSize();
|
||||
const itemWidth = width <= MOBILE_BREAKPOINT ? ITEM_WIDTH_MOBILE : ITEM_WIDTH;
|
||||
|
||||
return Math.floor(
|
||||
Math.min(width - GRID_PADDING - TOOLBAR_WIDTH, MAX_GRID_WIDTH) / itemWidth
|
||||
);
|
||||
};
|
||||
12
src/hooks/useMediaQuery.ts
Normal file
12
src/hooks/useMediaQuery.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { useMemo, useReducer, Reducer } from "react";
|
||||
import useEvent from "./useEvent";
|
||||
|
||||
const updater: Reducer<number, void> = (s) => (s + 1) % 1_000_000;
|
||||
|
||||
export default function useMediaQuery(query: string) {
|
||||
const mq = useMemo(() => window.matchMedia(query), [query]);
|
||||
const [, update] = useReducer(updater, 0);
|
||||
|
||||
useEvent("resize", update, { passive: true });
|
||||
return mq.matches;
|
||||
}
|
||||
@@ -1,6 +1,11 @@
|
||||
import { useRecoilValue } from "recoil";
|
||||
import {
|
||||
iconWeightAtom,
|
||||
iconSizeAtom,
|
||||
iconColorAtom,
|
||||
STORAGE_KEY,
|
||||
} from "@/state";
|
||||
import useDebounce from "./useDebounce";
|
||||
import { iconWeightAtom, iconSizeAtom, iconColorAtom } from "../state/atoms";
|
||||
|
||||
export default function usePersistSettings() {
|
||||
const weight = useRecoilValue(iconWeightAtom);
|
||||
@@ -10,7 +15,7 @@ export default function usePersistSettings() {
|
||||
useDebounce(
|
||||
() => {
|
||||
const serializedState = JSON.stringify({ weight, size, color });
|
||||
window.localStorage.setItem("__phosphor_settings__", serializedState);
|
||||
window.localStorage.setItem(STORAGE_KEY, serializedState);
|
||||
},
|
||||
2000,
|
||||
[weight, size, color]
|
||||
|
||||
35
src/hooks/useSessionState.ts
Normal file
35
src/hooks/useSessionState.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { useCallback, useState, Dispatch, SetStateAction } from "react";
|
||||
import { STORAGE_KEY } from "@/state";
|
||||
|
||||
type Initializer<S> = () => S;
|
||||
type Setter<S> = (prev: S) => S;
|
||||
type Action<S> = S | Setter<S> | Initializer<S>;
|
||||
|
||||
function expand<S extends object>(action: Action<S>, prev?: S) {
|
||||
if (typeof action === "function") {
|
||||
return (action as Setter<S>)(prev!);
|
||||
} else {
|
||||
return action;
|
||||
}
|
||||
}
|
||||
|
||||
export default function useSessionState<S extends object>(
|
||||
key: string,
|
||||
fallbackState: S | (() => S)
|
||||
): [S, Dispatch<SetStateAction<S>>] {
|
||||
const [value, setValue] = useState<S>(() => {
|
||||
let val = sessionStorage.getItem(STORAGE_KEY + key);
|
||||
if (val) return JSON.parse(val) as S;
|
||||
return expand(fallbackState);
|
||||
});
|
||||
|
||||
const set: Dispatch<SetStateAction<S>> = useCallback((val) => {
|
||||
setValue((prev) => {
|
||||
const next = expand(val, prev);
|
||||
sessionStorage.setItem(STORAGE_KEY + key, JSON.stringify(next));
|
||||
return next;
|
||||
});
|
||||
}, []);
|
||||
|
||||
return [value, set];
|
||||
}
|
||||
Reference in New Issue
Block a user