124 lines
3.3 KiB
TypeScript
124 lines
3.3 KiB
TypeScript
import dayjs from 'dayjs';
|
|
import { useAtomValue, useSetAtom } from 'jotai';
|
|
import { atomWithStorage } from 'jotai/utils';
|
|
import { isEqual, reduce } from 'lodash-es';
|
|
import { useCallback, useMemo } from 'react';
|
|
import { v4 } from 'uuid';
|
|
|
|
type ColorSet = {
|
|
normal?: string | null;
|
|
hover?: string | null;
|
|
active?: string | null;
|
|
focus?: string | null;
|
|
disabled?: string | null;
|
|
lighten?: string | null;
|
|
darken?: string | null;
|
|
};
|
|
|
|
type Scheme = {
|
|
primary?: ColorSet | null;
|
|
secondary?: ColorSet | ColorSet[] | null;
|
|
accent?: ColorSet | null;
|
|
neutral?: ColorSet | null;
|
|
foreground?: ColorSet | null;
|
|
background?: ColorSet | null;
|
|
danger?: ColorSet | null;
|
|
warning?: ColorSet | null;
|
|
success?: ColorSet | null;
|
|
info?: ColorSet | null;
|
|
border?: ColorSet | null;
|
|
};
|
|
|
|
export type SchemeSet = {
|
|
id: string;
|
|
name: string;
|
|
createdAt: string;
|
|
description: string | null;
|
|
lightScheme: Scheme;
|
|
darkScheme: Scheme;
|
|
};
|
|
|
|
const schemesAtom = atomWithStorage<SchemeSet[]>('schemes', []);
|
|
export const activeSchemeAtom = atomWithStorage<string | null>('activeScheme', null);
|
|
|
|
export function useSchemeList(): Pick<SchemeSet, 'id' | 'name' | 'createdAt'>[] {
|
|
const schemes = useAtomValue(schemesAtom);
|
|
const sortedSchemes = useMemo(
|
|
() =>
|
|
schemes
|
|
.sort((a, b) => dayjs(b.createdAt).diff(dayjs(a.createdAt)))
|
|
.map(({ id, name, createdAt }) => ({ id, name, createdAt })),
|
|
[schemes],
|
|
);
|
|
|
|
return sortedSchemes;
|
|
}
|
|
|
|
export function useScheme(id: string): SchemeSet | null {
|
|
const schemes = useAtomValue(schemesAtom);
|
|
const scheme = useMemo(() => schemes.find((s) => isEqual(id, s.id)) ?? null, [schemes, id]);
|
|
return scheme;
|
|
}
|
|
|
|
export function useActiveScheme(): SchemeSet | null {
|
|
const activeSchemeId = useAtomValue(activeSchemeAtom);
|
|
const activeScheme = useScheme(activeSchemeId ?? 'UNEXISTS');
|
|
return activeScheme;
|
|
}
|
|
|
|
export function useCreateScheme(): (name: string, description?: string) => string {
|
|
const updateSchemes = useSetAtom(schemesAtom);
|
|
const createSchemeAction = useCallback(
|
|
(name: string, description?: string) => {
|
|
const newId = v4();
|
|
updateSchemes((prev) => [
|
|
...prev,
|
|
{
|
|
id: newId,
|
|
name,
|
|
createdAt: dayjs().toISOString(),
|
|
description: description ?? null,
|
|
lightScheme: {},
|
|
darkScheme: {},
|
|
},
|
|
]);
|
|
return newId;
|
|
},
|
|
[updateSchemes],
|
|
);
|
|
|
|
return createSchemeAction;
|
|
}
|
|
|
|
export function useUpdateScheme(id: string): (updater: (prev: SchemeSet) => SchemeSet) => void {
|
|
const updateSchemes = useSetAtom(schemesAtom);
|
|
const updateAction = useCallback(
|
|
(updater: (prev: SchemeSet) => SchemeSet) => {
|
|
updateSchemes((prev) =>
|
|
reduce(
|
|
prev,
|
|
(acc, scheme) => {
|
|
if (isEqual(id, scheme.id)) {
|
|
acc.push(updater(scheme));
|
|
} else {
|
|
acc.push(scheme);
|
|
}
|
|
return acc;
|
|
},
|
|
[] as SchemeSet[],
|
|
),
|
|
);
|
|
},
|
|
[id],
|
|
);
|
|
return updateAction;
|
|
}
|
|
|
|
export function useRemoveScheme(id: string): () => void {
|
|
const updateSchemes = useSetAtom(schemesAtom);
|
|
const removeAction = useCallback(() => {
|
|
updateSchemes((prev) => prev.filter((s) => !isEqual(id, s.id)));
|
|
}, [updateSchemes, id]);
|
|
return removeAction;
|
|
}
|