color-q/src/stores/schemes.ts
2025-01-24 10:48:36 +08:00

131 lines
3.6 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';
import { SchemeContent, SchemeStorage, SchemeType } from '../models';
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<SchemeContent<SchemeStorage>[]>('schemes', []);
export const activeSchemeAtom = atomWithStorage<string | null>('activeScheme', null);
export function useSchemeList(): Pick<SchemeContent<SchemeStorage>, '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, type }) => ({ id, name, createdAt, type })),
[schemes],
);
return sortedSchemes;
}
export function useScheme(id: string): SchemeContent<SchemeStorage> | null {
const schemes = useAtomValue(schemesAtom);
const scheme = useMemo(() => schemes.find((s) => isEqual(id, s.id)) ?? null, [schemes, id]);
return scheme;
}
export function useActiveScheme(): SchemeContent<SchemeStorage> | null {
const activeSchemeId = useAtomValue(activeSchemeAtom);
const activeScheme = useScheme(activeSchemeId ?? 'UNEXISTS');
return activeScheme;
}
export function useCreateScheme(): (
name: string,
type: SchemeType,
description?: string,
) => string {
const updateSchemes = useSetAtom(schemesAtom);
const createSchemeAction = useCallback(
(name: string, type: SchemeType, description?: string) => {
const newId = v4();
updateSchemes((prev) => [
...prev,
{
id: newId,
name,
createdAt: dayjs().toISOString(),
description: description ?? null,
type,
schemeStorage: {},
},
]);
return newId;
},
[updateSchemes],
);
return createSchemeAction;
}
export function useUpdateScheme(
id: string,
): (updater: (prev: SchemeContent<SchemeStorage>) => SchemeContent<SchemeStorage>) => void {
const updateSchemes = useSetAtom(schemesAtom);
const updateAction = useCallback(
(updater: (prev: SchemeContent<SchemeStorage>) => SchemeContent<SchemeStorage>) => {
updateSchemes((prev) =>
reduce(
prev,
(acc, scheme) => {
if (isEqual(id, scheme.id)) {
acc.push(updater(scheme));
} else {
acc.push(scheme);
}
return acc;
},
[] as SchemeContent<SchemeStorage>[],
),
);
},
[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;
}