mirror of
https://github.com/revanced/revanced-website.git
synced 2025-04-29 22:24:31 +02:00
feat: Animate donate heart more lively (#168)
* feat: improve donate heart animations * use number * handle unmounting * fix: Screen horizontal overflow * refactor: Sass changes --------- Co-authored-by: Ushie <ushiekane@gmail.com> Co-authored-by: Kendell R <KTibow@users.noreply.github.com>
This commit is contained in:
parent
7787ecde2c
commit
6401aa381e
@ -1,22 +1,195 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
export let backgroundImageUrl: string;
|
export let backgroundImageUrl: string;
|
||||||
export let foregroundImageUrl: string;
|
export let foregroundImageUrl: string;
|
||||||
export let alt: string;
|
export let alt: string;
|
||||||
|
|
||||||
|
let showHeart: (e: MouseEvent, behind: boolean) => void = (_e, _behind) => {};
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
const background = document.getElementById('pulsating-image')!;
|
||||||
|
|
||||||
|
let lastHeartTime = 0;
|
||||||
|
|
||||||
|
showHeart = (e, behind) => {
|
||||||
|
const rect = background.getBoundingClientRect();
|
||||||
|
if (Date.now() - lastHeartTime < 100) return;
|
||||||
|
lastHeartTime = Date.now();
|
||||||
|
|
||||||
|
const heart = document.createElement('img');
|
||||||
|
heart.src = foregroundImageUrl;
|
||||||
|
heart.style.position = 'absolute';
|
||||||
|
|
||||||
|
let x = e.clientX - rect.left - heart.width;
|
||||||
|
let y = e.clientY - rect.top - heart.height;
|
||||||
|
|
||||||
|
x += Math.floor(Math.random() * 30) - 15;
|
||||||
|
y += Math.floor(Math.random() * 30) - 15;
|
||||||
|
|
||||||
|
heart.style.left = `${x}px`;
|
||||||
|
heart.style.top = `${y}px`;
|
||||||
|
heart.style.height = '50px';
|
||||||
|
heart.style.width = '50px';
|
||||||
|
|
||||||
|
if (behind) heart.style.zIndex = '-1';
|
||||||
|
|
||||||
|
const animations = [
|
||||||
|
'float-up',
|
||||||
|
'float-scale-rotate-left',
|
||||||
|
'float-scale-rotate-right',
|
||||||
|
'float-scale-rotate-right-2',
|
||||||
|
'float-scale-rotate-left-2'
|
||||||
|
];
|
||||||
|
heart.classList.add(animations[Math.floor(Math.random() * animations.length)]);
|
||||||
|
heart.classList.add('float');
|
||||||
|
|
||||||
|
background.appendChild(heart);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
heart.remove();
|
||||||
|
}, 1000);
|
||||||
|
};
|
||||||
|
|
||||||
|
let interval: number | undefined;
|
||||||
|
function showHeartRandom() {
|
||||||
|
const rect = background.getBoundingClientRect();
|
||||||
|
|
||||||
|
const x = rect.left + Math.floor(Math.random() * rect.width);
|
||||||
|
const y = rect.top + Math.floor(Math.random() * rect.height);
|
||||||
|
showHeart!({ clientX: x, clientY: y } as MouseEvent, true);
|
||||||
|
|
||||||
|
interval = setTimeout(showHeartRandom, Math.random() * 300);
|
||||||
|
}
|
||||||
|
showHeartRandom();
|
||||||
|
|
||||||
|
return () => clearTimeout(interval);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div id="pulsating-image-scale">
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
<div id="pulsating-image-hover">
|
<div
|
||||||
<div id="background" style:background-image="url({backgroundImageUrl})">
|
id="pulsating-image"
|
||||||
<img src={foregroundImageUrl} {alt} />
|
on:mousemove={(e) => showHeart(e, false)}
|
||||||
|
on:mousedown={(e) => showHeart(e, false)}
|
||||||
|
>
|
||||||
|
<div id="pulsating-image-rotate">
|
||||||
|
<div id="pulsating-image-hover">
|
||||||
|
<div id="background" style:background-image="url({backgroundImageUrl})">
|
||||||
|
<img id="heart-secondary" src={foregroundImageUrl} {alt} />
|
||||||
|
<img id="heart-primary" src={foregroundImageUrl} {alt} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
#pulsating-image-scale {
|
:root {
|
||||||
user-select: none;
|
overflow-x: hidden;
|
||||||
cursor: pointer;
|
}
|
||||||
|
|
||||||
|
:global(.float) {
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0;
|
||||||
|
filter: blur(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.float-up) {
|
||||||
|
animation: floatUp 1s ease-out forwards;
|
||||||
|
@keyframes floatUp {
|
||||||
|
0% {
|
||||||
|
transform: translateY(0px);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 0.3;
|
||||||
|
filter: blur(0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateY(-40px);
|
||||||
|
opacity: 0;
|
||||||
|
filter: blur(5px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.float-scale-rotate-left) {
|
||||||
|
animation: floatScaleRotateLeft 1s ease-out forwards;
|
||||||
|
@keyframes floatScaleRotateLeft {
|
||||||
|
0% {
|
||||||
|
transform: translateY(0px) scale(1.2);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 0.3;
|
||||||
|
filter: blur(0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateY(-20px) scale(0.5) rotate(-45deg);
|
||||||
|
opacity: 0;
|
||||||
|
filter: blur(5px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.float-scale-rotate-right) {
|
||||||
|
animation: floatScaleRotateRight 1s ease-out forwards;
|
||||||
|
@keyframes floatScaleRotateRight {
|
||||||
|
0% {
|
||||||
|
transform: translateY(0px) scale(1.2);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 0.3;
|
||||||
|
filter: blur(0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateY(-20px) scale(0.5) rotate(45deg);
|
||||||
|
opacity: 0;
|
||||||
|
filter: blur(5px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.float-scale-rotate-right-2) {
|
||||||
|
animation: floatScaleRotateRight2 1s ease-out forwards;
|
||||||
|
@keyframes floatScaleRotateRight2 {
|
||||||
|
0% {
|
||||||
|
transform: translateY(0px) scale(1.8);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 0.3;
|
||||||
|
filter: blur(0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateY(-30px) scale(1) rotate(50deg);
|
||||||
|
opacity: 0;
|
||||||
|
filter: blur(5px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.float-scale-rotate-left-2) {
|
||||||
|
animation: floatScaleRotateLeft2 1s ease-out forwards;
|
||||||
|
@keyframes floatScaleRotateLeft2 {
|
||||||
|
0% {
|
||||||
|
transform: translateY(0px) scale(1.8);
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 0.3;
|
||||||
|
filter: blur(0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateY(-30px) scale(1) rotate(-50deg);
|
||||||
|
opacity: 0;
|
||||||
|
filter: blur(5px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pulsating-image {
|
||||||
|
user-select: none;
|
||||||
|
border-radius: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
filter: brightness(1);
|
||||||
transition:
|
transition:
|
||||||
transform 0.4s ease,
|
transform 0.4s ease,
|
||||||
filter 0.2s ease;
|
filter 0.2s ease;
|
||||||
@ -26,100 +199,156 @@
|
|||||||
|
|
||||||
&:active {
|
&:active {
|
||||||
filter: brightness(1.3);
|
filter: brightness(1.3);
|
||||||
transform: scaleY(0.95) rotate(-5deg);
|
transform: scaleY(0.95) rotate(5deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
#pulsating-image-hover {
|
#pulsating-image-rotate {
|
||||||
height: 225px;
|
animation: rotate 1.25s infinite;
|
||||||
width: 225px;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
|
|
||||||
&:hover {
|
@keyframes rotate {
|
||||||
animation: wiggle 1s;
|
32% {
|
||||||
|
transform: rotate(-5deg);
|
||||||
@keyframes wiggle {
|
}
|
||||||
0% {
|
50% {
|
||||||
transform: rotate(0);
|
transform: rotate(4deg);
|
||||||
}
|
}
|
||||||
25% {
|
80% {
|
||||||
transform: rotate(5deg);
|
transform: rotate(-3deg);
|
||||||
}
|
|
||||||
50% {
|
|
||||||
transform: rotate(-5deg);
|
|
||||||
}
|
|
||||||
75% {
|
|
||||||
transform: rotate(5deg);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#background {
|
#pulsating-image-hover {
|
||||||
pointer-events: none;
|
height: 225px;
|
||||||
display: flex;
|
width: 225px;
|
||||||
background-repeat: no-repeat;
|
transition: all 0.2s ease;
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
animation: pulse-size 1.2s infinite;
|
|
||||||
will-change: transform;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
img {
|
&:hover {
|
||||||
height: 50%;
|
animation: wiggle 1s;
|
||||||
animation:
|
|
||||||
double-pulse-size 1.2s infinite,
|
|
||||||
pulse-glow 1.2s infinite;
|
|
||||||
will-change: transform, box-shadow;
|
|
||||||
|
|
||||||
@keyframes double-pulse-size {
|
@keyframes wiggle {
|
||||||
0% {
|
0% {
|
||||||
transform: scale(0.7);
|
transform: rotate(0);
|
||||||
}
|
}
|
||||||
13% {
|
25% {
|
||||||
transform: scale(0.8);
|
transform: rotate(5deg);
|
||||||
}
|
}
|
||||||
30% {
|
50% {
|
||||||
transform: scale(0.7);
|
transform: rotate(-5deg);
|
||||||
}
|
}
|
||||||
45% {
|
75% {
|
||||||
transform: scale(0.8);
|
transform: rotate(5deg);
|
||||||
}
|
}
|
||||||
100% {
|
100% {
|
||||||
transform: scale(0.7);
|
transform: rotate(0deg);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes pulse-glow {
|
|
||||||
30% {
|
|
||||||
filter: drop-shadow(0 0 0rem var(--red-one));
|
|
||||||
}
|
|
||||||
45% {
|
|
||||||
filter: drop-shadow(0 0 0.5rem var(--red-one));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes pulse-size {
|
#background {
|
||||||
0% {
|
border-radius: 100%;
|
||||||
transform: scale(0.7);
|
box-shadow: 0 0 0 1rem black;
|
||||||
|
pointer-events: none;
|
||||||
|
display: flex;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
animation: pulse-size 1.25s infinite;
|
||||||
|
will-change: transform;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
#heart-secondary {
|
||||||
|
animation: pulse-fade 1.25s infinite ease-out;
|
||||||
|
opacity: 0.5;
|
||||||
|
will-change: transform, filter;
|
||||||
|
filter: opacity(0);
|
||||||
|
transform: scale(0.8);
|
||||||
|
|
||||||
|
@keyframes pulse-fade {
|
||||||
|
30% {
|
||||||
|
transform: scale(0.7);
|
||||||
|
filter: blur(0rem) opacity(0.7);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1.8);
|
||||||
|
filter: blur(1rem) opacity(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
30% {
|
#heart-primary {
|
||||||
filter: brightness(1);
|
animation:
|
||||||
|
double-pulse-size 1.25s infinite,
|
||||||
|
pulse-glow 1.25s infinite;
|
||||||
|
@keyframes double-pulse-size {
|
||||||
|
0% {
|
||||||
|
transform: scale(0.7) rotate(0);
|
||||||
|
}
|
||||||
|
13% {
|
||||||
|
transform: scale(0.84);
|
||||||
|
}
|
||||||
|
16% {
|
||||||
|
transform: scale(0.82);
|
||||||
|
}
|
||||||
|
30% {
|
||||||
|
transform: scale(0.7);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: scale(0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: scale(0.7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& {
|
||||||
|
filter: drop-shadow(0 0 0 var(--red-one));
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse-glow {
|
||||||
|
33% {
|
||||||
|
filter: drop-shadow(0 0 0rem var(--red-one));
|
||||||
|
}
|
||||||
|
45% {
|
||||||
|
filter: drop-shadow(0 0 0.5rem var(--red-one));
|
||||||
|
}
|
||||||
|
80% {
|
||||||
|
filter: drop-shadow(0 0 0.5rem var(--red-one));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
39% {
|
#heart-primary,
|
||||||
filter: brightness(1.2);
|
#heart-secondary {
|
||||||
|
position: absolute;
|
||||||
|
height: 50%;
|
||||||
|
will-change: transform, box-shadow;
|
||||||
}
|
}
|
||||||
32% {
|
|
||||||
transform: scale(0.68);
|
& {
|
||||||
|
box-shadow: 0 0 0 0 #000000;
|
||||||
}
|
}
|
||||||
50% {
|
|
||||||
transform: scale(0.78);
|
@keyframes pulse-size {
|
||||||
}
|
0% {
|
||||||
100% {
|
transform: scale(0.7);
|
||||||
transform: scale(0.7);
|
filter: brightness(1);
|
||||||
|
}
|
||||||
|
32% {
|
||||||
|
box-shadow: 0 0 50px 3px #000000;
|
||||||
|
transform: scale(0.64) scaleY(0.95);
|
||||||
|
}
|
||||||
|
38% {
|
||||||
|
box-shadow: 0 0 0 0 #000000;
|
||||||
|
filter: brightness(1.2);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: scale(0.78);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
box-shadow: 0 0 0 0 #000000;
|
||||||
|
filter: brightness(1);
|
||||||
|
transform: scale(0.7);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user