| import { clsx, type ClassValue } from 'clsx' |
| import { twMerge } from 'tailwind-merge' |
| import { StoreApi, UseBoundStore } from 'zustand' |
|
|
| export function cn(...inputs: ClassValue[]) { |
| return twMerge(clsx(inputs)) |
| } |
|
|
| export function randomColor() { |
| const digits = '0123456789abcdef' |
| let code = '#' |
| for (let i = 0; i < 6; i++) { |
| code += digits.charAt(Math.floor(Math.random() * 16)) |
| } |
| return code |
| } |
|
|
| export function errorMessage(error: any) { |
| return error instanceof Error ? error.message : `${error}` |
| } |
|
|
| |
| |
| |
| |
| |
| |
| export function throttle<T extends (...args: any[]) => any>(fn: T, delay: number): (...args: Parameters<T>) => void { |
| let lastCall = 0 |
| let timeoutId: ReturnType<typeof setTimeout> | null = null |
|
|
| return function(this: any, ...args: Parameters<T>) { |
| const now = Date.now() |
| const remaining = delay - (now - lastCall) |
|
|
| if (remaining <= 0) { |
| |
| if (timeoutId) { |
| clearTimeout(timeoutId) |
| timeoutId = null |
| } |
| lastCall = now |
| fn.apply(this, args) |
| } else if (!timeoutId) { |
| |
| timeoutId = setTimeout(() => { |
| lastCall = Date.now() |
| timeoutId = null |
| fn.apply(this, args) |
| }, remaining) |
| } |
| } |
| } |
|
|
| type WithSelectors<S> = S extends { getState: () => infer T } |
| ? S & { use: { [K in keyof T]: () => T[K] } } |
| : never |
|
|
| export const createSelectors = <S extends UseBoundStore<StoreApi<object>>>(_store: S) => { |
| const store = _store as WithSelectors<typeof _store> |
| store.use = {} |
| for (const k of Object.keys(store.getState())) { |
| ;(store.use as any)[k] = () => store((s) => s[k as keyof typeof s]) |
| } |
|
|
| return store |
| } |
|
|