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;
 | 
						|
}
 |