Add style
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Dominic Zimmer 2023-02-15 10:55:55 +01:00
parent 7a36dce160
commit a4515d4e3e
6 changed files with 253 additions and 16696 deletions

16742
package-lock.json generated

File diff suppressed because it is too large Load Diff

126
src/AnnoyerHandler.tsx Normal file
View File

@ -0,0 +1,126 @@
export type Annoyer = {
image: string,
x: number,
y: number,
angle: number,
xSpeed: number,
ySpeed: number,
angleSpeed: number,
isVisible: boolean,
wasVisible: boolean,
age: number,
uuid: string
};
const randomGaussian = () => {
return Math.sqrt(-2 * Math.log(1 - Math.random())) * Math.cos(2 * Math.PI * Math.random());
}
export class AnnoyerHandler {
public annoyers: Set<Annoyer>;
private images: string[];
private max_annoyers: number;
constructor(images: string[], start_limit?: number) {
this.annoyers = new Set<Annoyer>();
this.images = images;
this.max_annoyers = start_limit ?? 0;
while (this.annoyers.size < this.max_annoyers) {
this.annoyers.add(this.generateAnnoyer());
}
}
generateAnnoyer = (): Annoyer => {
const usedImages = new Set(Array.from(this.annoyers).map(annoyer => annoyer.image));
const possibleImages = this.images.filter(image => !usedImages.has(image));
let image: string;
if (possibleImages.length !== 0) {
//console.log("there are unused images, taking one of them");
const ims = Array.from(possibleImages);
image = ims[Math.floor(Math.random() * ims.length)];
} else {
//console.log("all images are in use, taking one at random");
image = this.images[Math.floor(Math.random() * this.images.length)];
}
const maxWidth = document.documentElement.clientWidth;
const maxHeight = document.documentElement.clientHeight;
const outerMargin = 150;
const startingPosition = (): [number, number] => {
const r1 = Math.random() * 2 - 1;
const r2 = Math.random() * 2 - 1;
const marginX = r1 * outerMargin;
const marginY = r2 * outerMargin;
const x = r1 < 0 ? marginX : maxWidth + marginX;
const y = r2 < 0 ? marginY : maxHeight + marginY;
return [x,y];
};
const [startX, startY] = startingPosition();
const speed = (startingPosition: [number, number]): [number, number] => {
const r1 = Math.random();
const r2 = Math.random();
const targetX = r1 * maxWidth;
const targetY = r2 * maxHeight;
const distance = Math.sqrt(
(targetX - startingPosition[0]) * (targetX - startingPosition[0]) +
(targetY - startingPosition[1]) * (targetY - startingPosition[1])
)
const speed = ( Math.abs(randomGaussian()) + 0.5) * 2;
const normalizedSpeed = speed / distance;
return [(targetX - startingPosition[0]) * normalizedSpeed, (targetY - startingPosition[1]) * normalizedSpeed];
};
const [speedX, speedY] = speed([startX, startY]);
const newAnnoyer = {
image: image,
x: startX,
y: startY,
angle: 0,
angleSpeed: randomGaussian(),
xSpeed: speedX ,
ySpeed: speedY ,
age: Math.random() * -1000,
isVisible: false,
wasVisible: false,
uuid: "" + Math.random()
};
return newAnnoyer;
};
die = (annoyer: Annoyer) => {
this.annoyers.delete(annoyer);
this.spawnUntilLimit();
};
changeLimit = (newValue: number) => {
this.max_annoyers = newValue;
this.spawnUntilLimit();
};
spawnUntilLimit = () => {
while (this.annoyers.size < this.max_annoyers)
this.annoyers.add(this.generateAnnoyer());
};
tick = () => {
this.annoyers.forEach(annoyer => {
//if (annoyer.age > 10000) return;
annoyer.x += annoyer.xSpeed;
annoyer.y += annoyer.ySpeed;
annoyer.angle += annoyer.angleSpeed;
annoyer.age++;
if (annoyer.isVisible && !annoyer.wasVisible) {
//console.log("annoyer became visible");
} else if (annoyer.wasVisible && !annoyer.isVisible) {
//console.log("annoyer became invisible");
//console.log("annoyer died at the age of ",annoyer.age);
this.die(annoyer);
} else if (annoyer.age > 10000) this.die(annoyer);
annoyer.wasVisible = annoyer.isVisible;
});
};
}

45
src/KrassesOverlay.tsx Normal file
View File

@ -0,0 +1,45 @@
import { useEffect, useState } from 'react';
import { Annoyer, AnnoyerHandler } from './AnnoyerHandler';
import './Krassesoverlay.css';
const emojis = Array.from("🥐🥯🥞🍦🧁🍰🎂🍮🍭🍫🍬🍩🍪");
export const KrassesOverlay: React.FC = () => {
const [annoyerHandler, ] = useState(() => new AnnoyerHandler(emojis, 2));
const [x, setX] = useState(0);
const update = () => setX(x+1);
const handler = () => {
annoyerHandler.tick();
update();
};
useEffect(() => {
const interval = setInterval(handler, 10);
return () => clearInterval(interval);
});
const ref = (annoyer: Annoyer) => (element: HTMLImageElement) => {
if (!element) return;
const rect = element.getBoundingClientRect();
const visible = rect.bottom >= 0 &&
rect.right >= 0 &&
rect.top <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.left <= (window.innerWidth || document.documentElement.clientWidth);
annoyer.isVisible = visible;
};
return <div className="overlay">
{Array.from(annoyerHandler.annoyers).map((annoyer, index) => (
<span ref={ref(annoyer)} key={index} className="annoyer" style={
{
fontSize: 40,
top: annoyer.y, left: annoyer.x,
transform: `rotate(${annoyer.angle}deg)`
}
}>{annoyer.image}</span>
))}
</div>;
}

12
src/Krassesoverlay.css Normal file
View File

@ -0,0 +1,12 @@
.overlay {
overflow: hidden;
z-index: 1;
width: 100vw;
height: 100vh;
position: absolute;
}
.annoyer {
position: absolute;
max-block-size: 70px;
}

View File

@ -68,4 +68,23 @@ input[type="radio"]:checked+label {
#coming-no+label {
--selected-color: #dc2626;
}
.bg {
background-image: url("https://www.inshape.de/fileadmin/user_upload/user_upload/Fotolia_216856994_Subscription_Monthly_M.jpg");
width: 100vw;
height: 100vh;
position: absolute;
filter: blur(7px);
background-size: cover;
}
.bgwrap {
position: sticky;
top: 0px;
z-index: -1;
}
.page :is(p, label, h1, h2, h3, h4, h5, h6) {
filter: drop-shadow(1px 1px 3px white);
}

View File

@ -5,6 +5,7 @@ import { APIEndPoint, PartyContext } from './PartyContext';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faAngleDown, faCalendarDays, faLocationDot } from '@fortawesome/free-solid-svg-icons';
import { modifySelfRequest, parseURI } from './partyApi';
import { KrassesOverlay } from './KrassesOverlay';
export const PartyPage: React.FC = () => {
const partyContext = useContext(PartyContext);
@ -58,6 +59,10 @@ export const PartyPage: React.FC = () => {
}
return <div className="App">
<div className="bgwrap">
<div className="bg" />
<KrassesOverlay />
</div>
<div className='page'>
<h1>Hallo {dear} {name},</h1>
<div className='page-content'>