From 48f229883f9f2f68c6bcdc7c8fe67967e57a2370 Mon Sep 17 00:00:00 2001 From: Inna Abdrakhmanova Date: Mon, 13 Jan 2025 20:49:05 +0100 Subject: [PATCH 01/12] Add GlowHoverContainer component --- .../components/containers/base-container.tsx | 24 +- .../use-glow-hover/glow-hover-effect.ts | 274 ++++++++++++++++++ ui/src/components/use-glow-hover/index.ts | 4 + .../use-glow-hover/linear-animation.ts | 37 +++ .../use-glow-hover/use-glow-hover.ts | 20 ++ ui/src/index.ts | 1 + 6 files changed, 357 insertions(+), 3 deletions(-) create mode 100644 ui/src/components/use-glow-hover/glow-hover-effect.ts create mode 100644 ui/src/components/use-glow-hover/index.ts create mode 100644 ui/src/components/use-glow-hover/linear-animation.ts create mode 100644 ui/src/components/use-glow-hover/use-glow-hover.ts diff --git a/ui/src/components/containers/base-container.tsx b/ui/src/components/containers/base-container.tsx index ba4f1b77d..24058e47e 100644 --- a/ui/src/components/containers/base-container.tsx +++ b/ui/src/components/containers/base-container.tsx @@ -1,17 +1,21 @@ +'use client'; + import React from 'react'; import { twMerge } from 'tailwind-merge'; import { BackgroundColor } from '../../interfaces/color'; +import { useGlowHover } from '../use-glow-hover'; type BaseContainerProps = { backgroundColor?: BackgroundColor; + wrapperRef?: React.Ref; } & React.HTMLAttributes; export const BaseContainer = React.forwardRef( - ({ children, className, backgroundColor, ...props }, ref) => { + ({ children, className, backgroundColor, wrapperClassName, wrapperRef, ...props }, ref) => { return ( -
+
-
+
{children}
@@ -19,3 +23,17 @@ export const BaseContainer = React.forwardRef>( + ({ className, ...props }, ref) => { + const refCard = useGlowHover({ lightColor: '#CEFF00' }); + + return ( + } + /> + ); + }, +); diff --git a/ui/src/components/use-glow-hover/glow-hover-effect.ts b/ui/src/components/use-glow-hover/glow-hover-effect.ts new file mode 100644 index 000000000..f8d971a91 --- /dev/null +++ b/ui/src/components/use-glow-hover/glow-hover-effect.ts @@ -0,0 +1,274 @@ +'use client'; + +import { linearAnimation } from './linear-animation'; +/*import presets, { GlowHoverPreset } from './presets';*/ + +/*import { + forceLightTheme, + forceDarkTheme, + resetForcedTheme +} from './theme-utils';*/ + +export type GlowHoverOptions = { + hoverBg?: string; + lightSize?: number; + lightSizeEnterAnimationTime?: number; + lightSizeLeaveAnimationTime?: number; + isElementMovable?: boolean; + customStaticBg?: string; + /* /!** + * Force theme on hover. Use with caution. + *!/ + forceTheme?: 'light' | 'dark' | false;*/ + enableBurst?: boolean; +} & ( + | { + /*preset: keyof typeof presets;*/ + lightColor?: string; + } + | { + /*preset?: never;*/ + lightColor: string; + } +); + +type Coords = { + x: number; + y: number; +}; + +const BURST_TIME = 300; + +export function parseColor(colorToParse: string) { + const div = document.createElement('div'); + div.style.color = colorToParse; + div.style.position = 'absolute'; + div.style.display = 'none'; + document.body.appendChild(div); + const colorFromEl = getComputedStyle(div).color; + document.body.removeChild(div); + const parsedColor = colorFromEl.match(/^rgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+)\s*)?\)$/i); + if (parsedColor) { + const alpha = typeof parsedColor[4] === 'undefined' ? 1 : parsedColor[4]; + return [parsedColor[1], parsedColor[2], parsedColor[3], alpha]; + } else { + console.error(`Color ${colorToParse} could not be parsed.`); + return [0, 0, 0, 0]; + } +} + +// eslint-disable-next-line complexity +export const glowHoverEffect = (el: HTMLElement, { preset, ...options }: GlowHoverOptions) => { + if (!el) { + // eslint-disable-next-line @typescript-eslint/no-empty-function + return () => {}; + } + /*let presetCfg: GlowHoverPreset = {}; + if (preset) { + const maybePreset = presets[preset] as GlowHoverPreset; + if (!maybePreset) { + throw new Error(`Unknown preset ${preset}`); + } + presetCfg = maybePreset; + }*/ + + const lightColor = options.lightColor ?? '#CEFF00'; + const lightSize = options.lightSize ?? 130; + const lightSizeEnterAnimationTime = options.lightSizeEnterAnimationTime ?? 100; + const lightSizeLeaveAnimationTime = options.lightSizeLeaveAnimationTime ?? 50; + const isElementMovable = options.isElementMovable ?? false; + const customStaticBg = options.customStaticBg ?? null; + + /*let forceTheme = options.forceTheme ?? null;*/ + + const enableBurst = options.enableBurst ?? false; + + const getResolvedHoverBg = () => getComputedStyle(el).backgroundColor; + + let resolvedHoverBg = getResolvedHoverBg(); + + // default bg (if not defined) is rgba(0, 0, 0, 0) which is bugged in gradients in Safari + // so we use transparent lightColor instead + const parsedLightColor = parseColor(lightColor); + const parsedLightColorRGBString = parsedLightColor.slice(0, 3).join(','); + const resolvedGradientBg = `rgba(${parsedLightColorRGBString},0)`; + + let isMouseInside = false; + let currentLightSize = 0; + let blownSize = 0; + let lightSizeEnterAnimationId: number = null; + let lightSizeLeaveAnimationId: number = null; + let blownSizeIncreaseAnimationId: number = null; + let blownSizeDecreaseAnimationId: number = null; + let lastMousePos: Coords; + const defaultBox = el.getBoundingClientRect(); + let lastElPos: Coords = { x: defaultBox.left, y: defaultBox.top }; + + const updateGlowEffect = () => { + if (!lastMousePos) { + return; + } + const gradientXPos = lastMousePos.x - lastElPos.x; + const gradientYPos = lastMousePos.y - lastElPos.y; + // we do not use transparent color here because of dirty gradient in Safari (more info: https://stackoverflow.com/questions/38391457/linear-gradient-to-transparent-bug-in-latest-safari) + const gradient = `radial-gradient(circle at ${gradientXPos}px ${gradientYPos}px, ${lightColor} 0%, ${resolvedGradientBg} calc(${ + blownSize * 2.5 + }% + ${currentLightSize}px)) no-repeat`; + + // we duplicate resolvedHoverBg layer here because of transition "blinking" without it + el.style.background = `${gradient} border-box border-box ${resolvedHoverBg}`; + }; + + const updateEffectWithPosition = () => { + if (isMouseInside) { + const curBox = el.getBoundingClientRect(); + lastElPos = { x: curBox.left, y: curBox.top }; + updateGlowEffect(); + } + }; + + const onMouseEnter = (e: MouseEvent) => { + resolvedHoverBg = getResolvedHoverBg(); + lastMousePos = { x: e.clientX, y: e.clientY }; + const curBox = el.getBoundingClientRect(); + lastElPos = { x: curBox.left, y: curBox.top }; + isMouseInside = true; + window.cancelAnimationFrame(lightSizeEnterAnimationId); + window.cancelAnimationFrame(lightSizeLeaveAnimationId); + + /*if (forceTheme === 'light') { + forceLightTheme(el); + } else if (forceTheme === 'dark') { + forceDarkTheme(el); + }*/ + + // animate currentLightSize from 0 to lightSize + linearAnimation({ + onProgress: (progress) => { + currentLightSize = lightSize * progress; + updateGlowEffect(); + }, + time: lightSizeEnterAnimationTime, + initialProgress: currentLightSize / lightSize, + onIdUpdate: (newId) => (lightSizeEnterAnimationId = newId), + }); + }; + + const onMouseMove = (e: MouseEvent) => { + lastMousePos = { x: e.clientX, y: e.clientY }; + if (isElementMovable) { + updateEffectWithPosition(); + } else { + updateGlowEffect(); + } + }; + + const onMouseLeave = () => { + isMouseInside = false; + window.cancelAnimationFrame(lightSizeEnterAnimationId); + window.cancelAnimationFrame(lightSizeLeaveAnimationId); + window.cancelAnimationFrame(blownSizeIncreaseAnimationId); + window.cancelAnimationFrame(blownSizeDecreaseAnimationId); + + // animate currentLightSize from lightSize to 0 + linearAnimation({ + onProgress: (progress) => { + currentLightSize = lightSize * (1 - progress); + blownSize = Math.min(blownSize, (1 - progress) * 100); + + if (progress < 1) { + updateGlowEffect(); + } else { + el.style.background = customStaticBg ? customStaticBg : ''; + } + + /*if (forceTheme && progress === 1) { + resetForcedTheme(el); + }*/ + }, + time: lightSizeLeaveAnimationTime, + initialProgress: 1 - currentLightSize / lightSize, + onIdUpdate: (newId) => (lightSizeLeaveAnimationId = newId), + }); + }; + + const onMouseDown = (e: MouseEvent) => { + lastMousePos = { x: e.clientX, y: e.clientY }; + const curBox = el.getBoundingClientRect(); + lastElPos = { x: curBox.left, y: curBox.top }; + window.cancelAnimationFrame(blownSizeIncreaseAnimationId); + window.cancelAnimationFrame(blownSizeDecreaseAnimationId); + + // animate blownSize from 0 to 100 + linearAnimation({ + onProgress: (progress) => { + blownSize = 100 * progress; + updateGlowEffect(); + }, + time: BURST_TIME, + initialProgress: blownSize / 100, + onIdUpdate: (newId) => (blownSizeIncreaseAnimationId = newId), + }); + }; + + const onMouseUp = (e: MouseEvent) => { + lastMousePos = { x: e.clientX, y: e.clientY }; + const curBox = el.getBoundingClientRect(); + lastElPos = { x: curBox.left, y: curBox.top }; + window.cancelAnimationFrame(blownSizeIncreaseAnimationId); + window.cancelAnimationFrame(blownSizeDecreaseAnimationId); + + // animate blownSize from 100 to 0 + linearAnimation({ + onProgress: (progress) => { + blownSize = (1 - progress) * 100; + updateGlowEffect(); + }, + time: BURST_TIME, + initialProgress: 1 - blownSize / 100, + onIdUpdate: (newId) => (blownSizeDecreaseAnimationId = newId), + }); + }; + + document.addEventListener('scroll', updateEffectWithPosition); + window.addEventListener('resize', updateEffectWithPosition); + el.addEventListener('mouseenter', onMouseEnter); + el.addEventListener('mousemove', onMouseMove); + el.addEventListener('mouseleave', onMouseLeave); + if (enableBurst) { + el.addEventListener('mousedown', onMouseDown); + el.addEventListener('mouseup', onMouseUp); + } + + let resizeObserver: ResizeObserver; + if (window.ResizeObserver) { + resizeObserver = new ResizeObserver(updateEffectWithPosition); + resizeObserver.observe(el); + } + + return () => { + window.cancelAnimationFrame(lightSizeEnterAnimationId); + window.cancelAnimationFrame(lightSizeLeaveAnimationId); + window.cancelAnimationFrame(blownSizeIncreaseAnimationId); + window.cancelAnimationFrame(blownSizeDecreaseAnimationId); + + document.removeEventListener('scroll', updateEffectWithPosition); + window.removeEventListener('resize', updateEffectWithPosition); + el.removeEventListener('mouseenter', onMouseEnter); + el.removeEventListener('mousemove', onMouseMove); + el.removeEventListener('mouseleave', onMouseLeave); + if (enableBurst) { + el.removeEventListener('mousedown', onMouseDown); + el.removeEventListener('mouseup', onMouseUp); + } + + /*if (forceTheme) { + resetForcedTheme(el); + }*/ + + if (resizeObserver) { + resizeObserver.unobserve(el); + resizeObserver.disconnect(); + } + }; +}; diff --git a/ui/src/components/use-glow-hover/index.ts b/ui/src/components/use-glow-hover/index.ts new file mode 100644 index 000000000..7818a6ed8 --- /dev/null +++ b/ui/src/components/use-glow-hover/index.ts @@ -0,0 +1,4 @@ +export { glowHoverEffect } from './glow-hover-effect'; +export type { GlowHoverOptions } from './glow-hover-effect'; +export { useGlowHover } from './use-glow-hover'; +export type { GlowHoverHookOptions } from './use-glow-hover'; diff --git a/ui/src/components/use-glow-hover/linear-animation.ts b/ui/src/components/use-glow-hover/linear-animation.ts new file mode 100644 index 000000000..b8555009f --- /dev/null +++ b/ui/src/components/use-glow-hover/linear-animation.ts @@ -0,0 +1,37 @@ +'use client'; + +interface LinearAnimationParams { + onProgress: (progress: number) => void; + onIdUpdate?: (id: number) => void; + time: number; + initialProgress?: number; +} + +export const linearAnimation = ({ + onProgress, + // eslint-disable-next-line @typescript-eslint/no-empty-function + onIdUpdate = () => {}, + time, + initialProgress = 0, +}: LinearAnimationParams) => { + if (time === 0) { + onProgress(1); + onIdUpdate(null); + return; + } + + let start: number = null; + const step = (timestamp: number) => { + if (!start) start = timestamp; + const progress = Math.min((timestamp - start) / time + initialProgress, 1); + + onProgress(progress); + + if (progress < 1) { + onIdUpdate(window.requestAnimationFrame(step)); + } else { + onIdUpdate(null); + } + }; + onIdUpdate(window.requestAnimationFrame(step)); +}; diff --git a/ui/src/components/use-glow-hover/use-glow-hover.ts b/ui/src/components/use-glow-hover/use-glow-hover.ts new file mode 100644 index 000000000..2fa16d585 --- /dev/null +++ b/ui/src/components/use-glow-hover/use-glow-hover.ts @@ -0,0 +1,20 @@ +'use client'; + +import { useEffect, useRef } from 'react'; + +import { glowHoverEffect, GlowHoverOptions } from './glow-hover-effect'; + +export type GlowHoverHookOptions = GlowHoverOptions & { disabled?: boolean }; +export const useGlowHover = ({ disabled = false, ...options }: GlowHoverHookOptions) => { + const ref = useRef(null); + + useEffect( + () => + !disabled && ref.current + ? glowHoverEffect(ref.current, options) + : // eslint-disable-next-line @typescript-eslint/no-empty-function + () => {}, + [disabled, ...Object.values(options)], + ); + return ref; +}; diff --git a/ui/src/index.ts b/ui/src/index.ts index eedc35e21..8b2e48f95 100644 --- a/ui/src/index.ts +++ b/ui/src/index.ts @@ -27,3 +27,4 @@ export * from './components/table'; export * from './components/tabs'; export * from './components/tooltip'; export * from './components/typography'; +export * from './components/use-glow-hover'; From 9acb966ec3bd4cae7d9e74b8d508bbfde2958085 Mon Sep 17 00:00:00 2001 From: Inna Abdrakhmanova Date: Mon, 13 Jan 2025 20:49:49 +0100 Subject: [PATCH 02/12] Add usage example to the main page (TODO: remove the example before merge) --- .../(website)/(home)/(sections)/overview.tsx | 80 +++++++++++-------- 1 file changed, 48 insertions(+), 32 deletions(-) diff --git a/website/src/app/[lang]/[region]/(website)/(home)/(sections)/overview.tsx b/website/src/app/[lang]/[region]/(website)/(home)/(sections)/overview.tsx index f074a7cf0..7fd1d126a 100644 --- a/website/src/app/[lang]/[region]/(website)/(home)/(sections)/overview.tsx +++ b/website/src/app/[lang]/[region]/(website)/(home)/(sections)/overview.tsx @@ -1,6 +1,6 @@ import { DefaultParams } from '@/app/[lang]/[region]'; import { Translator } from '@socialincome/shared/src/utils/i18n'; -import { BaseContainer, Typography } from '@socialincome/ui'; +import { BaseContainer, GLowHoverContainer, Typography } from '@socialincome/ui'; import { FontColor } from '@socialincome/ui/src/interfaces/color'; export async function Overview({ lang }: DefaultParams) { @@ -10,36 +10,52 @@ export async function Overview({ lang }: DefaultParams) { }); return ( - - - {translator.t('section-2.title-1')} - -
- {translator.t<{ text: string; color?: FontColor }[]>('section-2.title-2').map((title, index) => ( - - {title.text}{' '} - - ))} -
- - {translator.t('section-2.title-3')} - -
    -
  1. - {translator.t('section-2.text-3.1')} -
  2. -
  3. - {translator.t('section-2.text-3.2')} -
  4. -
- - {translator.t('section-2.title-4')} - - {translator.t('section-2.text-4')} - - {translator.t('section-2.title-5')} - - {translator.t('section-2.text-5')} -
+ <> + {/* TODO: remove the example of GlowHoverContainer usage below before merge */} + + + {translator.t('section-2.title-1')} + +
+ {translator.t<{ text: string; color?: FontColor }[]>('section-2.title-2').map((title, index) => ( + + {title.text}{' '} + + ))} +
+
+ + + + {translator.t('section-2.title-1')} + +
+ {translator.t<{ text: string; color?: FontColor }[]>('section-2.title-2').map((title, index) => ( + + {title.text}{' '} + + ))} +
+ + {translator.t('section-2.title-3')} + +
    +
  1. + {translator.t('section-2.text-3.1')} +
  2. +
  3. + {translator.t('section-2.text-3.2')} +
  4. +
+ + {translator.t('section-2.title-4')} + + {translator.t('section-2.text-4')} + + {translator.t('section-2.title-5')} + + {translator.t('section-2.text-5')} +
+ ); } From c2773a969f3568ec67925e8db0bc032f49db8e9f Mon Sep 17 00:00:00 2001 From: Inna Abdrakhmanova Date: Mon, 13 Jan 2025 21:39:16 +0100 Subject: [PATCH 03/12] Remove unnecessary comments --- .../use-glow-hover/glow-hover-effect.ts | 37 ------------------- .../use-glow-hover/linear-animation.ts | 1 - .../use-glow-hover/use-glow-hover.ts | 2 +- 3 files changed, 1 insertion(+), 39 deletions(-) diff --git a/ui/src/components/use-glow-hover/glow-hover-effect.ts b/ui/src/components/use-glow-hover/glow-hover-effect.ts index f8d971a91..741eb8ca0 100644 --- a/ui/src/components/use-glow-hover/glow-hover-effect.ts +++ b/ui/src/components/use-glow-hover/glow-hover-effect.ts @@ -1,13 +1,6 @@ 'use client'; import { linearAnimation } from './linear-animation'; -/*import presets, { GlowHoverPreset } from './presets';*/ - -/*import { - forceLightTheme, - forceDarkTheme, - resetForcedTheme -} from './theme-utils';*/ export type GlowHoverOptions = { hoverBg?: string; @@ -16,10 +9,6 @@ export type GlowHoverOptions = { lightSizeLeaveAnimationTime?: number; isElementMovable?: boolean; customStaticBg?: string; - /* /!** - * Force theme on hover. Use with caution. - *!/ - forceTheme?: 'light' | 'dark' | false;*/ enableBurst?: boolean; } & ( | { @@ -57,20 +46,10 @@ export function parseColor(colorToParse: string) { } } -// eslint-disable-next-line complexity export const glowHoverEffect = (el: HTMLElement, { preset, ...options }: GlowHoverOptions) => { if (!el) { - // eslint-disable-next-line @typescript-eslint/no-empty-function return () => {}; } - /*let presetCfg: GlowHoverPreset = {}; - if (preset) { - const maybePreset = presets[preset] as GlowHoverPreset; - if (!maybePreset) { - throw new Error(`Unknown preset ${preset}`); - } - presetCfg = maybePreset; - }*/ const lightColor = options.lightColor ?? '#CEFF00'; const lightSize = options.lightSize ?? 130; @@ -79,8 +58,6 @@ export const glowHoverEffect = (el: HTMLElement, { preset, ...options }: GlowHov const isElementMovable = options.isElementMovable ?? false; const customStaticBg = options.customStaticBg ?? null; - /*let forceTheme = options.forceTheme ?? null;*/ - const enableBurst = options.enableBurst ?? false; const getResolvedHoverBg = () => getComputedStyle(el).backgroundColor; @@ -136,12 +113,6 @@ export const glowHoverEffect = (el: HTMLElement, { preset, ...options }: GlowHov window.cancelAnimationFrame(lightSizeEnterAnimationId); window.cancelAnimationFrame(lightSizeLeaveAnimationId); - /*if (forceTheme === 'light') { - forceLightTheme(el); - } else if (forceTheme === 'dark') { - forceDarkTheme(el); - }*/ - // animate currentLightSize from 0 to lightSize linearAnimation({ onProgress: (progress) => { @@ -181,10 +152,6 @@ export const glowHoverEffect = (el: HTMLElement, { preset, ...options }: GlowHov } else { el.style.background = customStaticBg ? customStaticBg : ''; } - - /*if (forceTheme && progress === 1) { - resetForcedTheme(el); - }*/ }, time: lightSizeLeaveAnimationTime, initialProgress: 1 - currentLightSize / lightSize, @@ -262,10 +229,6 @@ export const glowHoverEffect = (el: HTMLElement, { preset, ...options }: GlowHov el.removeEventListener('mouseup', onMouseUp); } - /*if (forceTheme) { - resetForcedTheme(el); - }*/ - if (resizeObserver) { resizeObserver.unobserve(el); resizeObserver.disconnect(); diff --git a/ui/src/components/use-glow-hover/linear-animation.ts b/ui/src/components/use-glow-hover/linear-animation.ts index b8555009f..595f0cd15 100644 --- a/ui/src/components/use-glow-hover/linear-animation.ts +++ b/ui/src/components/use-glow-hover/linear-animation.ts @@ -9,7 +9,6 @@ interface LinearAnimationParams { export const linearAnimation = ({ onProgress, - // eslint-disable-next-line @typescript-eslint/no-empty-function onIdUpdate = () => {}, time, initialProgress = 0, diff --git a/ui/src/components/use-glow-hover/use-glow-hover.ts b/ui/src/components/use-glow-hover/use-glow-hover.ts index 2fa16d585..b799181e1 100644 --- a/ui/src/components/use-glow-hover/use-glow-hover.ts +++ b/ui/src/components/use-glow-hover/use-glow-hover.ts @@ -12,7 +12,7 @@ export const useGlowHover = ({ disabled = false, ...options }: GlowHoverHookOpti () => !disabled && ref.current ? glowHoverEffect(ref.current, options) - : // eslint-disable-next-line @typescript-eslint/no-empty-function + : () => {}, [disabled, ...Object.values(options)], ); From d618b555c202cae13617ec455c53838093eac195 Mon Sep 17 00:00:00 2001 From: IPogorelova Date: Mon, 13 Jan 2025 20:41:36 +0000 Subject: [PATCH 04/12] Prettified Code! --- ui/src/components/use-glow-hover/use-glow-hover.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ui/src/components/use-glow-hover/use-glow-hover.ts b/ui/src/components/use-glow-hover/use-glow-hover.ts index b799181e1..e86636125 100644 --- a/ui/src/components/use-glow-hover/use-glow-hover.ts +++ b/ui/src/components/use-glow-hover/use-glow-hover.ts @@ -9,11 +9,7 @@ export const useGlowHover = ({ disabled = false, ...options }: GlowHoverHookOpti const ref = useRef(null); useEffect( - () => - !disabled && ref.current - ? glowHoverEffect(ref.current, options) - : - () => {}, + () => (!disabled && ref.current ? glowHoverEffect(ref.current, options) : () => {}), [disabled, ...Object.values(options)], ); return ref; From 1dd4189a995f7929002a587ab7cf49600f9f2361 Mon Sep 17 00:00:00 2001 From: Inna Abdrakhmanova Date: Tue, 14 Jan 2025 19:04:53 +0100 Subject: [PATCH 05/12] Add missing wrapperClassName prop to BaseContainerProps --- ui/src/components/containers/base-container.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/src/components/containers/base-container.tsx b/ui/src/components/containers/base-container.tsx index 24058e47e..9bfb43532 100644 --- a/ui/src/components/containers/base-container.tsx +++ b/ui/src/components/containers/base-container.tsx @@ -7,6 +7,7 @@ import { useGlowHover } from '../use-glow-hover'; type BaseContainerProps = { backgroundColor?: BackgroundColor; + wrapperClassName?: string; wrapperRef?: React.Ref; } & React.HTMLAttributes; From 8e07d04d6af2092fbe3f4f8f883194d623747a6c Mon Sep 17 00:00:00 2001 From: Sandino Scheidegger Date: Tue, 14 Jan 2025 21:22:22 +0100 Subject: [PATCH 06/12] wip fix --- .../use-glow-hover/glow-hover-effect.ts | 17 +++++++++-------- ui/src/components/use-glow-hover/presets.ts | 11 +++++++++++ 2 files changed, 20 insertions(+), 8 deletions(-) create mode 100644 ui/src/components/use-glow-hover/presets.ts diff --git a/ui/src/components/use-glow-hover/glow-hover-effect.ts b/ui/src/components/use-glow-hover/glow-hover-effect.ts index 741eb8ca0..e173fcba8 100644 --- a/ui/src/components/use-glow-hover/glow-hover-effect.ts +++ b/ui/src/components/use-glow-hover/glow-hover-effect.ts @@ -1,6 +1,7 @@ 'use client'; import { linearAnimation } from './linear-animation'; +import { presets } from './presets'; // Ensure this import statement is present export type GlowHoverOptions = { hoverBg?: string; @@ -10,16 +11,16 @@ export type GlowHoverOptions = { isElementMovable?: boolean; customStaticBg?: string; enableBurst?: boolean; -} & ( - | { - /*preset: keyof typeof presets;*/ + } & ( + | { + preset: keyof typeof presets; lightColor?: string; - } - | { - /*preset?: never;*/ + } + | { + preset?: undefined; lightColor: string; - } -); + } + ); type Coords = { x: number; diff --git a/ui/src/components/use-glow-hover/presets.ts b/ui/src/components/use-glow-hover/presets.ts new file mode 100644 index 000000000..0eb4a6630 --- /dev/null +++ b/ui/src/components/use-glow-hover/presets.ts @@ -0,0 +1,11 @@ +export const presets = { + default: { + lightColor: '#CEFF00', + lightSize: 130, + lightSizeEnterAnimationTime: 100, + lightSizeLeaveAnimationTime: 50, + isElementMovable: false, + customStaticBg: null, + enableBurst: false, + }, +}; \ No newline at end of file From 90e5f3aac146259d3583359788f8128ded60a857 Mon Sep 17 00:00:00 2001 From: ssandino Date: Tue, 14 Jan 2025 20:25:23 +0000 Subject: [PATCH 07/12] Prettified Code! --- .../components/use-glow-hover/glow-hover-effect.ts | 12 ++++++------ ui/src/components/use-glow-hover/presets.ts | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ui/src/components/use-glow-hover/glow-hover-effect.ts b/ui/src/components/use-glow-hover/glow-hover-effect.ts index e173fcba8..6b8f4d2aa 100644 --- a/ui/src/components/use-glow-hover/glow-hover-effect.ts +++ b/ui/src/components/use-glow-hover/glow-hover-effect.ts @@ -11,16 +11,16 @@ export type GlowHoverOptions = { isElementMovable?: boolean; customStaticBg?: string; enableBurst?: boolean; - } & ( - | { +} & ( + | { preset: keyof typeof presets; lightColor?: string; - } - | { + } + | { preset?: undefined; lightColor: string; - } - ); + } +); type Coords = { x: number; diff --git a/ui/src/components/use-glow-hover/presets.ts b/ui/src/components/use-glow-hover/presets.ts index 0eb4a6630..a49047d95 100644 --- a/ui/src/components/use-glow-hover/presets.ts +++ b/ui/src/components/use-glow-hover/presets.ts @@ -8,4 +8,4 @@ export const presets = { customStaticBg: null, enableBurst: false, }, -}; \ No newline at end of file +}; From 81691b72906ae034b0e80714ed9159489fead01f Mon Sep 17 00:00:00 2001 From: Sandino Scheidegger Date: Tue, 14 Jan 2025 21:30:06 +0100 Subject: [PATCH 08/12] wip fix 2 --- .../use-glow-hover/glow-hover-effect.ts | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/ui/src/components/use-glow-hover/glow-hover-effect.ts b/ui/src/components/use-glow-hover/glow-hover-effect.ts index e173fcba8..06e66e673 100644 --- a/ui/src/components/use-glow-hover/glow-hover-effect.ts +++ b/ui/src/components/use-glow-hover/glow-hover-effect.ts @@ -1,7 +1,7 @@ 'use client'; import { linearAnimation } from './linear-animation'; -import { presets } from './presets'; // Ensure this import statement is present +import { presets } from './presets'; export type GlowHoverOptions = { hoverBg?: string; @@ -11,15 +11,15 @@ export type GlowHoverOptions = { isElementMovable?: boolean; customStaticBg?: string; enableBurst?: boolean; - } & ( - | { - preset: keyof typeof presets; - lightColor?: string; - } - | { - preset?: undefined; - lightColor: string; - } +} & ( + | { + preset: keyof typeof presets; + lightColor?: string; +} + | { + preset?: undefined; + lightColor: string; +} ); type Coords = { @@ -74,10 +74,10 @@ export const glowHoverEffect = (el: HTMLElement, { preset, ...options }: GlowHov let isMouseInside = false; let currentLightSize = 0; let blownSize = 0; - let lightSizeEnterAnimationId: number = null; - let lightSizeLeaveAnimationId: number = null; - let blownSizeIncreaseAnimationId: number = null; - let blownSizeDecreaseAnimationId: number = null; + let lightSizeEnterAnimationId: number | undefined = undefined; + let lightSizeLeaveAnimationId: number | undefined = undefined; + let blownSizeIncreaseAnimationId: number | undefined = undefined; + let blownSizeDecreaseAnimationId: number | undefined = undefined; let lastMousePos: Coords; const defaultBox = el.getBoundingClientRect(); let lastElPos: Coords = { x: defaultBox.left, y: defaultBox.top }; @@ -235,4 +235,4 @@ export const glowHoverEffect = (el: HTMLElement, { preset, ...options }: GlowHov resizeObserver.disconnect(); } }; -}; +}; \ No newline at end of file From 49de84b0052131ff9aac8d8378a05bc27e0b41ba Mon Sep 17 00:00:00 2001 From: ssandino Date: Tue, 14 Jan 2025 20:42:10 +0000 Subject: [PATCH 09/12] Prettified Code! --- .../use-glow-hover/glow-hover-effect.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ui/src/components/use-glow-hover/glow-hover-effect.ts b/ui/src/components/use-glow-hover/glow-hover-effect.ts index 06e66e673..151fe3c81 100644 --- a/ui/src/components/use-glow-hover/glow-hover-effect.ts +++ b/ui/src/components/use-glow-hover/glow-hover-effect.ts @@ -13,14 +13,14 @@ export type GlowHoverOptions = { enableBurst?: boolean; } & ( | { - preset: keyof typeof presets; - lightColor?: string; -} + preset: keyof typeof presets; + lightColor?: string; + } | { - preset?: undefined; - lightColor: string; -} - ); + preset?: undefined; + lightColor: string; + } +); type Coords = { x: number; @@ -235,4 +235,4 @@ export const glowHoverEffect = (el: HTMLElement, { preset, ...options }: GlowHov resizeObserver.disconnect(); } }; -}; \ No newline at end of file +}; From ef2fe22e875970484b396749493c82d5a7606f8e Mon Sep 17 00:00:00 2001 From: Sandino Scheidegger Date: Tue, 14 Jan 2025 21:47:10 +0100 Subject: [PATCH 10/12] wip fix 3 --- .../use-glow-hover/glow-hover-effect.ts | 56 ++++++++++++++----- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/ui/src/components/use-glow-hover/glow-hover-effect.ts b/ui/src/components/use-glow-hover/glow-hover-effect.ts index 06e66e673..5115fd027 100644 --- a/ui/src/components/use-glow-hover/glow-hover-effect.ts +++ b/ui/src/components/use-glow-hover/glow-hover-effect.ts @@ -111,8 +111,12 @@ export const glowHoverEffect = (el: HTMLElement, { preset, ...options }: GlowHov const curBox = el.getBoundingClientRect(); lastElPos = { x: curBox.left, y: curBox.top }; isMouseInside = true; - window.cancelAnimationFrame(lightSizeEnterAnimationId); - window.cancelAnimationFrame(lightSizeLeaveAnimationId); + if (lightSizeEnterAnimationId !== undefined) { + window.cancelAnimationFrame(lightSizeEnterAnimationId); + } + if (lightSizeLeaveAnimationId !== undefined) { + window.cancelAnimationFrame(lightSizeLeaveAnimationId); + } // animate currentLightSize from 0 to lightSize linearAnimation({ @@ -137,10 +141,18 @@ export const glowHoverEffect = (el: HTMLElement, { preset, ...options }: GlowHov const onMouseLeave = () => { isMouseInside = false; - window.cancelAnimationFrame(lightSizeEnterAnimationId); - window.cancelAnimationFrame(lightSizeLeaveAnimationId); - window.cancelAnimationFrame(blownSizeIncreaseAnimationId); - window.cancelAnimationFrame(blownSizeDecreaseAnimationId); + if (lightSizeEnterAnimationId !== undefined) { + window.cancelAnimationFrame(lightSizeEnterAnimationId); + } + if (lightSizeLeaveAnimationId !== undefined) { + window.cancelAnimationFrame(lightSizeLeaveAnimationId); + } + if (blownSizeIncreaseAnimationId !== undefined) { + window.cancelAnimationFrame(blownSizeIncreaseAnimationId); + } + if (blownSizeDecreaseAnimationId !== undefined) { + window.cancelAnimationFrame(blownSizeDecreaseAnimationId); + } // animate currentLightSize from lightSize to 0 linearAnimation({ @@ -164,8 +176,12 @@ export const glowHoverEffect = (el: HTMLElement, { preset, ...options }: GlowHov lastMousePos = { x: e.clientX, y: e.clientY }; const curBox = el.getBoundingClientRect(); lastElPos = { x: curBox.left, y: curBox.top }; - window.cancelAnimationFrame(blownSizeIncreaseAnimationId); - window.cancelAnimationFrame(blownSizeDecreaseAnimationId); + if (blownSizeIncreaseAnimationId !== undefined) { + window.cancelAnimationFrame(blownSizeIncreaseAnimationId); + } + if (blownSizeDecreaseAnimationId !== undefined) { + window.cancelAnimationFrame(blownSizeDecreaseAnimationId); + } // animate blownSize from 0 to 100 linearAnimation({ @@ -183,8 +199,12 @@ export const glowHoverEffect = (el: HTMLElement, { preset, ...options }: GlowHov lastMousePos = { x: e.clientX, y: e.clientY }; const curBox = el.getBoundingClientRect(); lastElPos = { x: curBox.left, y: curBox.top }; - window.cancelAnimationFrame(blownSizeIncreaseAnimationId); - window.cancelAnimationFrame(blownSizeDecreaseAnimationId); + if (blownSizeIncreaseAnimationId !== undefined) { + window.cancelAnimationFrame(blownSizeIncreaseAnimationId); + } + if (blownSizeDecreaseAnimationId !== undefined) { + window.cancelAnimationFrame(blownSizeDecreaseAnimationId); + } // animate blownSize from 100 to 0 linearAnimation({ @@ -215,10 +235,18 @@ export const glowHoverEffect = (el: HTMLElement, { preset, ...options }: GlowHov } return () => { - window.cancelAnimationFrame(lightSizeEnterAnimationId); - window.cancelAnimationFrame(lightSizeLeaveAnimationId); - window.cancelAnimationFrame(blownSizeIncreaseAnimationId); - window.cancelAnimationFrame(blownSizeDecreaseAnimationId); + if (lightSizeEnterAnimationId !== undefined) { + window.cancelAnimationFrame(lightSizeEnterAnimationId); + } + if (lightSizeLeaveAnimationId !== undefined) { + window.cancelAnimationFrame(lightSizeLeaveAnimationId); + } + if (blownSizeIncreaseAnimationId !== undefined) { + window.cancelAnimationFrame(blownSizeIncreaseAnimationId); + } + if (blownSizeDecreaseAnimationId !== undefined) { + window.cancelAnimationFrame(blownSizeDecreaseAnimationId); + } document.removeEventListener('scroll', updateEffectWithPosition); window.removeEventListener('resize', updateEffectWithPosition); From 5dd5de41918449f5d5b75c5422153b65313c7b1f Mon Sep 17 00:00:00 2001 From: Sandino Scheidegger Date: Tue, 14 Jan 2025 21:54:46 +0100 Subject: [PATCH 11/12] wip fix 4 --- .../use-glow-hover/glow-hover-effect.ts | 16 +++++------ .../use-glow-hover/linear-animation.ts | 28 ++++++++++--------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/ui/src/components/use-glow-hover/glow-hover-effect.ts b/ui/src/components/use-glow-hover/glow-hover-effect.ts index 5c1870507..5115fd027 100644 --- a/ui/src/components/use-glow-hover/glow-hover-effect.ts +++ b/ui/src/components/use-glow-hover/glow-hover-effect.ts @@ -13,14 +13,14 @@ export type GlowHoverOptions = { enableBurst?: boolean; } & ( | { - preset: keyof typeof presets; - lightColor?: string; - } + preset: keyof typeof presets; + lightColor?: string; +} | { - preset?: undefined; - lightColor: string; - } -); + preset?: undefined; + lightColor: string; +} + ); type Coords = { x: number; @@ -263,4 +263,4 @@ export const glowHoverEffect = (el: HTMLElement, { preset, ...options }: GlowHov resizeObserver.disconnect(); } }; -}; +}; \ No newline at end of file diff --git a/ui/src/components/use-glow-hover/linear-animation.ts b/ui/src/components/use-glow-hover/linear-animation.ts index 595f0cd15..08fb57bc4 100644 --- a/ui/src/components/use-glow-hover/linear-animation.ts +++ b/ui/src/components/use-glow-hover/linear-animation.ts @@ -2,35 +2,37 @@ interface LinearAnimationParams { onProgress: (progress: number) => void; - onIdUpdate?: (id: number) => void; + onIdUpdate?: (id: number | undefined) => void; time: number; initialProgress?: number; } export const linearAnimation = ({ - onProgress, - onIdUpdate = () => {}, - time, - initialProgress = 0, -}: LinearAnimationParams) => { + onProgress, + onIdUpdate = () => {}, + time, + initialProgress = 0, + }: LinearAnimationParams) => { if (time === 0) { onProgress(1); - onIdUpdate(null); + onIdUpdate(undefined); return; } - let start: number = null; + let start: number | undefined = undefined; const step = (timestamp: number) => { - if (!start) start = timestamp; + if (start === undefined) start = timestamp; const progress = Math.min((timestamp - start) / time + initialProgress, 1); onProgress(progress); if (progress < 1) { - onIdUpdate(window.requestAnimationFrame(step)); + const id = window.requestAnimationFrame(step); + onIdUpdate(id); } else { - onIdUpdate(null); + onIdUpdate(undefined); } }; - onIdUpdate(window.requestAnimationFrame(step)); -}; + const id = window.requestAnimationFrame(step); + onIdUpdate(id); +}; \ No newline at end of file From 04844697fadc08e5c13ae487fb2ae6f8af15ceb0 Mon Sep 17 00:00:00 2001 From: ssandino Date: Tue, 14 Jan 2025 20:57:07 +0000 Subject: [PATCH 12/12] Prettified Code! --- .../use-glow-hover/glow-hover-effect.ts | 16 ++++++++-------- .../use-glow-hover/linear-animation.ts | 12 ++++++------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/ui/src/components/use-glow-hover/glow-hover-effect.ts b/ui/src/components/use-glow-hover/glow-hover-effect.ts index 5115fd027..5c1870507 100644 --- a/ui/src/components/use-glow-hover/glow-hover-effect.ts +++ b/ui/src/components/use-glow-hover/glow-hover-effect.ts @@ -13,14 +13,14 @@ export type GlowHoverOptions = { enableBurst?: boolean; } & ( | { - preset: keyof typeof presets; - lightColor?: string; -} + preset: keyof typeof presets; + lightColor?: string; + } | { - preset?: undefined; - lightColor: string; -} - ); + preset?: undefined; + lightColor: string; + } +); type Coords = { x: number; @@ -263,4 +263,4 @@ export const glowHoverEffect = (el: HTMLElement, { preset, ...options }: GlowHov resizeObserver.disconnect(); } }; -}; \ No newline at end of file +}; diff --git a/ui/src/components/use-glow-hover/linear-animation.ts b/ui/src/components/use-glow-hover/linear-animation.ts index 08fb57bc4..4f2106f89 100644 --- a/ui/src/components/use-glow-hover/linear-animation.ts +++ b/ui/src/components/use-glow-hover/linear-animation.ts @@ -8,11 +8,11 @@ interface LinearAnimationParams { } export const linearAnimation = ({ - onProgress, - onIdUpdate = () => {}, - time, - initialProgress = 0, - }: LinearAnimationParams) => { + onProgress, + onIdUpdate = () => {}, + time, + initialProgress = 0, +}: LinearAnimationParams) => { if (time === 0) { onProgress(1); onIdUpdate(undefined); @@ -35,4 +35,4 @@ export const linearAnimation = ({ }; const id = window.requestAnimationFrame(step); onIdUpdate(id); -}; \ No newline at end of file +};