import { type ClassValue, clsx } from 'clsx' import { twMerge } from 'tailwind-merge' import { cubicOut } from 'svelte/easing' import type { TransitionConfig } from 'svelte/transition' import { dailyFoodStore } from '$lib/store/energy/dailyFoodStore' import { foodStore } from '$lib/store/energy/foodStore' import { weeklyFoodStore } from '$lib/store/energy/weeklyFoodStore' import { monthlyFoodStore } from '$lib/store/energy/monthlyFoodStore' import { yearlyFoodStore } from '$lib/store/energy/yearlyFoodStore' import { weightStore } from '$lib/store/weight/weightStore' import { dailyWeightStore } from '$lib/store/weight/dailyWeightStore' import { weeklyWeightStore } from '$lib/store/weight/weeklyWeightStore' import { monthlyWeightStore } from '$lib/store/weight/monthlyWeightStore' import { yearlyWeightStore } from '$lib/store/weight/yearlyWeightStore' export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)) } type FlyAndScaleParams = { y?: number x?: number start?: number duration?: number } export const flyAndScale = ( node: Element, params: FlyAndScaleParams = { y: -8, x: 0, start: 0.95, duration: 150 } ): TransitionConfig => { const style = getComputedStyle(node) const transform = style.transform === 'none' ? '' : style.transform const scaleConversion = ( valueA: number, scaleA: [number, number], scaleB: [number, number] ) => { const [minA, maxA] = scaleA const [minB, maxB] = scaleB const percentage = (valueA - minA) / (maxA - minA) const valueB = percentage * (maxB - minB) + minB return valueB } const styleToString = ( style: Record ): string => { return Object.keys(style).reduce((str, key) => { if (style[key] === undefined) return str return str + `${key}:${style[key]};` }, '') } return { duration: params.duration ?? 200, delay: 0, css: t => { const y = scaleConversion(t, [0, 1], [params.y ?? 5, 0]) const x = scaleConversion(t, [0, 1], [params.x ?? 0, 0]) const scale = scaleConversion(t, [0, 1], [params.start ?? 0.95, 1]) return styleToString({ transform: `${transform} translate3d(${x}px, ${y}px, 0) scale(${scale})`, opacity: t }) }, easing: cubicOut } } type Color = { h: number s: number l: number } function ColorDistance(color1: Color, color2: Color) { return Math.abs(color1.h - color2.h) } function GenerateRandomHSL(): Color { const hue = Math.floor(Math.random() * 360) const saturation = 70 const lightness = 60 return { h: hue, s: saturation, l: lightness } } const existingColors: Color[] = [] function GenerateColor(): string { const minDistance = 15 let newColor: Color let isDistinct = false let iterations = 0 while (!isDistinct) { iterations++ if (iterations > 1000) { console.error('Failed to generate a distinct color after 1000 iterations') break } newColor = GenerateRandomHSL() isDistinct = true for (const color of existingColors) { if (ColorDistance(newColor, color) < minDistance) { isDistinct = false break } } existingColors.push(newColor) } // We can not reach this point without having a color generated // @ts-ignore return `hsl(${newColor.h}, ${newColor.s}%, ${newColor.l}%)` } export { GenerateColor } export function RefreshStores() { // @ts-ignore foodStore.refresh() // @ts-ignore dailyFoodStore.refresh() // @ts-ignore weeklyFoodStore.refresh() // @ts-ignore monthlyFoodStore.refresh() // @ts-ignore yearlyFoodStore.refresh() // @ts-ignore weightStore.refresh() // @ts-ignore dailyWeightStore.refresh() // @ts-ignore weeklyWeightStore.refresh() // @ts-ignore monthlyWeightStore.refresh() // @ts-ignore yearlyWeightStore.refresh() }