diff --git a/.prettierrc b/.prettierrc index f98a0aa..6889049 100644 --- a/.prettierrc +++ b/.prettierrc @@ -3,7 +3,7 @@ "tabWidth": 4, "singleQuote": true, "trailingComma": "none", - "printWidth": 100, + "printWidth": 120, "plugins": ["prettier-plugin-svelte"], "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] } diff --git a/package.json b/package.json index 1743bea..fafbd22 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "aquavox", - "version": "1.8.3", + "version": "1.9.0", "private": false, "scripts": { "dev": "vite dev", diff --git a/src/lib/components/interactiveBox.svelte b/src/lib/components/interactiveBox.svelte index c726e3b..8dcf506 100644 --- a/src/lib/components/interactiveBox.svelte +++ b/src/lib/components/interactiveBox.svelte @@ -34,6 +34,7 @@ function volumeBarOnChange(e: any) { adjustVolume(e.target.value); + localStorage.setItem('volume', e.target.value); } onMount(() => { @@ -43,9 +44,7 @@ }); $: { - console.log(songInfoTopContainer, songInfoTopContent); if (songInfoTopContainer && songInfoTopContent) { - console.log(songInfoTopContent.offsetWidth, songInfoTopContainer.offsetWidth); isInfoTopOverflowing = songInfoTopContent.offsetWidth > songInfoTopContainer.offsetWidth; } @@ -77,7 +76,7 @@ bind:this={songInfoTopContent}>{name} -
+ {/if} diff --git a/src/lib/components/lyrics.svelte b/src/lib/components/lyrics.svelte index 1778646..39aed0f 100644 --- a/src/lib/components/lyrics.svelte +++ b/src/lib/components/lyrics.svelte @@ -3,23 +3,75 @@ export let lyrics: string[]; export let originalLyrics: Line[]; export let progress: number; + function userSlideProgress() { + systemCouldScrollSince = 0; + }; + export { userSlideProgress }; + let currentScrollPos = ''; let currentLyric: Line; let currentLyricIndex = -1; + let lyricsContainer: HTMLDivElement; + let systemScrolling = false; + let systemCouldScrollSince = 0; + let lastScroll = 0; let refs = []; let _refs: any[] = []; $: refs = _refs.filter(Boolean); + function smoothScrollTo(element: HTMLElement, to: number, duration: number, timingFunction: Function) { + if (systemCouldScrollSince > Date.now()) return; + systemScrolling = true; + const start = element.scrollTop; + const change = to - start; + const startTime = performance.now(); + + function animateScroll(timestamp: number) { + const elapsedTime = timestamp - startTime; + const progress = Math.min(elapsedTime / duration, 1); + const easedProgress = timingFunction(progress, 1.1, 0, 1, 1); + element.scrollTop = start + change * easedProgress; + + console.log(elapsedTime); + if (elapsedTime < duration) { + requestAnimationFrame(animateScroll); + } else { + console.log('?'); + systemScrolling = false; + } + } + + requestAnimationFrame(animateScroll); + } + + // Define your custom Bézier curve function + function customBezier(progress: number, p1x: number, p1y: number, p2x: number, p2y: number) { + function cubicBezier(t: number, p1: number, p2: number) { + const c = 3 * p1; + const b = 3 * (p2 - p1) - c; + const a = 1 - c - b; + return a * Math.pow(t, 3) + b * Math.pow(t, 2) + c * t; + } + + return cubicBezier(progress, p1x, p2x); + } + function getClass(lyricIndex: number, progress: number) { + if (!currentLyric) return 'after-lyric'; if (lyricIndex === currentLyricIndex) return 'current-lyric'; else if (progress > currentLyric.endSeconds) return 'after-lyric'; else return 'previous-lyric'; } + function inRange(x: number, min: number, max: number) { + return (x - min) * (x - max) <= 0; + } + $: { - if (originalLyrics) { + if (originalLyrics && lyricsContainer) { let found = false; + let finallyFound = false; for (let i = 0; i < originalLyrics.length; i++) { let l = originalLyrics[i]; if (progress >= l.startSeconds && progress <= l.endSeconds) { @@ -28,20 +80,53 @@ found = true; const currentRef = refs[i]; if (currentRef && currentScrollPos !== currentLyric.text) { - currentRef.scrollIntoView({ behavior: 'smooth', block: 'center' }); + const targetScroll = lyricsContainer.scrollTop + currentRef.getBoundingClientRect().top - 320; + const duration = 700; + smoothScrollTo(lyricsContainer, targetScroll, duration, customBezier); + lastScroll = 0; currentScrollPos = currentLyric.text; } break; } } - for (let i = 0; i < lyrics.length; i++) { - const offset = Math.abs(i - currentLyricIndex); - const blurRadius = Math.min(offset * 1, 16); - if (refs[i]) { - refs[i].style.filter = `blur(${blurRadius}px)`; + if (!found) { + for (let i = 0; i < originalLyrics.length; i++) { + let l = originalLyrics[i]; + let nl = i + 1 < originalLyrics.length ? originalLyrics[i + 1] : originalLyrics[i]; + if ( + progress >= l.endSeconds && + progress < nl.startSeconds && + inRange(lastScroll, l.endSeconds, nl.startSeconds) === false + ) { + const currentRef = refs[i]; + const targetScroll = lyricsContainer.scrollTop + currentRef.getBoundingClientRect().top - 320; + const duration = 700; + currentLyricIndex = i - 0.1; + currentLyric = { + id: '-1', + startTime: '00:00:00,000', + startSeconds: l.endSeconds + 0.01, + endTime: '00:00:00,000', + endSeconds: nl.startSeconds - 0.01, + text: '' + }; + smoothScrollTo(lyricsContainer, targetScroll, duration, customBezier); + lastScroll = progress; + finallyFound = true; + break; + } } } - if (!found) { + if (systemCouldScrollSince < Date.now()) { + for (let i = 0; i < lyrics.length; i++) { + const offset = Math.abs(i - currentLyricIndex); + const blurRadius = Math.min(offset * 1, 16); + if (refs[i]) { + refs[i].style.filter = `blur(${blurRadius}px)`; + } + } + } + if (found == false && finallyFound == false) { currentLyric = { id: '-1', startTime: '00:00:00,000', @@ -58,7 +143,17 @@ {#if lyrics && originalLyrics}