diff --git a/frontend/src/lib/utils.ts b/frontend/src/lib/utils.ts new file mode 100644 index 0000000..8bffa0e --- /dev/null +++ b/frontend/src/lib/utils.ts @@ -0,0 +1,106 @@ +import { cubicOut } from 'svelte/easing' +import type { TransitionConfig } from 'svelte/transition' + +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 } \ No newline at end of file