!!
Diff
public/index.css | 44 ++++++++++++++++++++++++++++++++++++++++++--
src/App.js | 13 +++++++++++--
src/index_old.js | 448 --------------------------------------------------------------------------------
src/stringTable.js | 7 +++++++
public/mp3/jiafei.mp3 | 0
src/components/MainDiv.js | 34 +++++++++++-----------------------
src/components/MainUI.js | 44 ++++++++++++++++++++++++++++++++++++++++++++
src/components/MouseFollower.js | 10 +++++++---
src/components/WhitelistUI.js | 34 ++++++++++++++++++++++++++++++++++
9 files changed, 154 insertions(+), 480 deletions(-)
@@ -131,15 +131,26 @@
padding: 20px;
}
.MainUI {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
flex-wrap: wrap;
}
.MainDiv h1 {
text-align: center;
flex: none;
animation: sigmoid-motion 2s linear infinite;
max-width: 8em;
}
.MainDiv-2 h1 {
font-size: medium;
}
.MainDiv-tendencies h1 {
animation: sigmoid-motion 2s linear infinite;
}
@keyframes sigmoid-motion {
@@ -262,7 +273,7 @@
border-radius: 10px;
color: white;
border: 1px solid black;
padding: 10px;
padding: 2px;
margin: 10px;
text-align: center;
@@ -272,7 +283,6 @@
margin: 0;
padding: 0;
padding-bottom: 10px;
text-transform: uppercase;
}
@@ -281,19 +291,23 @@
list-style-type: none;
text-align: center;
margin: none;
margin-bottom: 2px;
font-size: small;
}
.SettingsPane button {
display: inline-block;
height: 2em;
margin-bottom: 0.5em;
background-color: #333;
font-size: small;
}
.MouseFollower {
position: absolute;
z-index: 20;
pointer-events: none;
}
.Gatito {
@@ -304,6 +318,7 @@
z-index: 10;
min-width: 20%;
max-width: 30%;
pointer-events: none;
}
.Gatito-tendencies {
@@ -390,4 +405,25 @@
width: 20%;
height: 3em;
}
.WhitelistUI label {
display: block;
text-align: center;
}
.WhitelistUI input {
margin-left: 5px;
}
#with-sta-email {
padding: 5px;
margin: 10px;
border: 1px dotted gray;
}
#without-sta-email {
padding: 5px;
margin: 10px;
border: 1px dotted gray;
}
@@ -30,6 +30,7 @@
const [mode, setMode] = useState(0);
const [characteristics, setCharacteristics] = useState(true);
const [tendencies, setTendencies] = useState(true);
const [joinWhitelist, setJoinWhitelist] = useState(false);
const mousePosition = useMousePosition();
const windowSize = useWindowSize();
@@ -50,6 +51,12 @@
}>
<source src="/mp3/maskoff.mp3" type="audio/mpeg" />
</audio> : null}
{mode === 2 ?
<audio autoPlay={true} loop={true} muted={
(mode === 2 && characteristics) ? false : true
}>
<source src="/mp3/jiafei.mp3" type="audio/mpeg" />
</audio> : null}
<BGElem
mode={mode}
characteristics={characteristics}
@@ -77,20 +84,22 @@
mode={mode}
characteristics={characteristics}
tendencies={tendencies}
joinWhitelist={joinWhitelist}
setMode={setMode}
setCharacteristics={setCharacteristics}
setTendencies={setTendencies}
setJoinWhitelist={setJoinWhitelist}
mousePosition={mousePosition}
windowSize={windowSize}
audio={vineboom}
/>
<MouseFollower
{ tendencies ? <MouseFollower
mode={mode}
characteristics={characteristics}
tendencies={tendencies}
mousePosition={mousePosition}
windowSize={windowSize}
/>
/> : null}
<Gatito
mode={mode}
characteristics={characteristics}
@@ -1,448 +1,0 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import { useState, useEffect } from 'react';
import reportWebVitals from './reportWebVitals';
import useSound from 'use-sound';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
const getClassName = (elementName, mode, characteristics, tendencies) => {
let className = elementName + " " + elementName + "-" + mode;
if (characteristics) {
className += " " + elementName + "-characteristics";
}
if (tendencies) {
className += " " + elementName + "-tendencies";
}
return className;
}
const useMousePosition = () => {
const [
mousePosition,
setMousePosition
] = React.useState({ x: null, y: null });
React.useEffect(() => {
const updateMousePosition = ev => {
setMousePosition({ x: ev.clientX, y: ev.clientY });
};
window.addEventListener('mousemove', updateMousePosition);
return () => {
window.removeEventListener('mousemove', updateMousePosition);
};
}, []);
return mousePosition;
};
const useWindowSize = () => {
const [
windowSize,
setWindowSize
] = React.useState({ width: window.innerWidth, height: window.innerHeight });
React.useEffect(() => {
const updateWindowSize = () => {
setWindowSize({ width: window.innerWidth, height: window.innerHeight });
};
window.addEventListener('resize', updateWindowSize);
return () => {
window.removeEventListener('resize', updateWindowSize);
};
}, []);
return windowSize;
};
const useAudio = url => {
const [audio] = useState(new Audio(url));
const [playing, setPlaying] = useState(false);
const setUrl = url => {
audio.src = url;
};
useEffect(() => {
playing ? audio.play() : audio.pause();
},
[playing]
);
useEffect(() => {
audio.addEventListener('ended', () => setPlaying(false));
return () => {
audio.removeEventListener('ended', () => setPlaying(false));
};
}, []);
return [playing, setPlaying, setUrl];
};
function App() {
const [mode, setMode] = useState(0);
const [characteristics, setCharacteristics] = useState(true);
const [tendencies, setTendencies] = useState(true);
const mousePosition = useMousePosition();
const windowSize = useWindowSize();
const vineboom = new Audio("/mp3/vineboom.mp3");
return (
<div className={getClassName("App", mode, characteristics, tendencies)}>
{mode === 0 ?
<audio autoPlay={true} loop={true} muted={
(mode === 0 && characteristics) ? false : true
}>
<source src="/mp3/phonkcore.mp3" type="audio/mpeg" />
</audio> : null}
{mode === 1 ?
<audio autoPlay={true} loop={true} muted={
(mode === 1 && characteristics) ? false : true
}>
<source src="/mp3/maskoff.mp3" type="audio/mpeg" />
</audio> : null}
<BGElem
mode={mode}
characteristics={characteristics}
tendencies={tendencies}
mousePosition={mousePosition}
windowSize={windowSize}
/>
<BGOverlay
mode={mode}
characteristics={characteristics}
tendencies={tendencies}
mousePosition={mousePosition}
windowSize={windowSize}
bottomness={true}
/>
<BGOverlay
mode={mode}
characteristics={characteristics}
tendencies={tendencies}
mousePosition={mousePosition}
windowSize={windowSize}
bottomness={false}
/>
<MainDiv
mode={mode}
characteristics={characteristics}
tendencies={tendencies}
setMode={setMode}
setCharacteristics={setCharacteristics}
setTendencies={setTendencies}
mousePosition={mousePosition}
windowSize={windowSize}
audio={vineboom}
/>
<MouseFollower
mode={mode}
characteristics={characteristics}
tendencies={tendencies}
mousePosition={mousePosition}
windowSize={windowSize}
/>
<Gatito
mode={mode}
characteristics={characteristics}
tendencies={tendencies}
/>
</div>
);
}
function ClipboardCopy({ copyText }) {
const [isCopied, setIsCopied] = useState(false);
async function copyTextToClipboard(text) {
if ('clipboard' in navigator) {
return await navigator.clipboard.writeText(text);
} else {
return document.execCommand('copy', true, text);
}
}
const handleCopyClick = () => {
copyTextToClipboard(copyText)
.then(() => {
setIsCopied(true);
setTimeout(() => {
setIsCopied(false);
}, 1500);
})
.catch((err) => {
console.log(err);
});
}
return (
<div>
<input id="server-url" type="text" value={copyText} readOnly />
<button id="server-copy-button" onClick={handleCopyClick}>
<span>{isCopied ? 'Copied!' : 'Copy'}</span>
</button>
</div>
);
}
function BGElem({mode, characteristics, tendencies, mousePosition, windowSize}) {
return (
<div
className={getClassName("BGElem", mode, characteristics, tendencies)}
style= {{
transform: tendencies ?
"scale(2.0) perspective(1000px) rotateX(" + ((-1 * mousePosition.y) + (windowSize.height / 2)) / 25 + "deg) rotateY(" + ((mousePosition.x) - (windowSize.width / 2)) / 25 + "deg)"
: "scale(2.0)",
}}
/>
);
}
function BGOverlay({mode, characteristics, tendencies, mousePosition, windowSize, bottomness}) {
return(
<div
className={bottomness ? getClassName("BGOverlay", mode, characteristics, tendencies) + " BGOverlay-top" : getClassName("BGOverlay", mode, characteristics, tendencies) + " BGOverlay-bottom"}
/>
);
}
function PrankButton({characteristics, audio}) {
const [clicked, setClicked] = useState(false);
useEffect(() => {
if (clicked && characteristics) {
audio.play();
}
}, [clicked]);
return (
<span
className="main-button-style"
onClick={() => setClicked(true)}
style={{
lineHeight: clicked ? "3em" : "1em",
}}
>
{clicked ?
<div>Get pranked</div>
: <div>Buy ranks! <br /><small>Pay with Ethereum, Dogecoin, Gruncible, Quelchtube</small></div>}
</span>
);
}
function SettingsPane({mode, characteristics, tendencies, setMode, setCharacteristics, setTendencies, audio}) {
const handleModeChange = (event) => {
setMode((mode + 1) % 3);
if (characteristics) {
audio.play();
}
}
const handleCharacteristicsChange = (event) => {
setCharacteristics(!characteristics);
if (characteristics) {
audio.play();
}
}
const handleTendenciesChange = (event) => {
setTendencies(!tendencies);
if (characteristics) {
audio.play();
}
}
return (
<ul className={getClassName("SettingsPane", mode, characteristics, tendencies)}>
<h3 id="settings-title">Settings</h3>
<li>
Mode: <button value={0} onClick={handleModeChange} className={"settings-button " + getClassName("mode")}>
{mode === 0 ? "Swiss Bingus" :
mode === 1 ? "Swag Floppa" :
mode === 2 ? "Maoist Sploingus" : "Error"}
</button>
</li>
<li>
Characteristics: <button value={0} onClick={handleCharacteristicsChange} className={"settings-button " + getClassName("characteristics")}>
{characteristics ? "On" : "Off"}
</button>
</li>
<li>
Tendencies: <button value={0} onClick={handleTendenciesChange} className={"settings-button " + getClassName("tendencies")}>
{tendencies ? "On" : "Off"}
</button>
</li>
</ul>
)
}
function MouseFollower({mode, characteristics, tendencies, mousePosition, windowSize}) {
return (
mode === 2 && tendencies ?
<img
className={getClassName("MouseFollower", mode, characteristics, tendencies)}
src="/img/talisman.png"
style= {{
transform: "translate(" + (50 + mousePosition.x - (windowSize.width / 2)) + "px, " + (80 + mousePosition.y - (windowSize.height / 2)) + "px)",
}}
/> : <TextMouseSpooler
frequentSaying="Swiss!"
lessFrequentSaying="Swag!"
mousePosition={mousePosition}
/>
);
}
function TextMouseSpooler({frequentSaying, lessFrequentSaying, mousePosition}) {
const [mousePositionSinceLastSignificantMove, setMousePositionSinceLastSignificantMove] = useState({x: 0, y: 0});
const [textObjectArray, setTextObjectArray] = useState([]);
useEffect(() => {
const distance = Math.sqrt(Math.pow(mousePosition.x - mousePositionSinceLastSignificantMove.x, 2) + Math.pow(mousePosition.y - mousePositionSinceLastSignificantMove.y, 2));
if (distance > 20) {
setTextObjectArray(textObjectArray.concat({
position: mousePositionSinceLastSignificantMove,
saying: Math.random() > 0.5 ? frequentSaying : lessFrequentSaying,
timeAtCreation: Date.now(),
}));
setMousePositionSinceLastSignificantMove(mousePosition);
if (Date.now() % 1000 === 0) {
for (let i = 0; i < textObjectArray.length; i++) {
if (Date.now() - textObjectArray[i].timeAtCreation > 5000) {
textObjectArray.splice(i, 1);
}
}
}
}
}, [mousePosition]);
return (
<div className="TextMouseSpooler">
{}
{textObjectArray.map((textObject, index) => {
return (
<span
key={index}
className="text-mouse-spooler-span"
style={{
top: textObject.position.y,
left: textObject.position.x,
}}
>
{textObject.saying}
</span>
);
})}
</div>
);
}
function MainDiv({mode, characteristics, tendencies, setMode, setCharacteristics, setTendencies, mousePosition, windowSize, audio}) {
return (
<div
className={getClassName("MainDiv", mode, characteristics, tendencies)}
style= {{
transform:
tendencies ?
"perspective(1000px) rotateX(" + ((mousePosition.y) - (windowSize.height / 2)) / 20 + "deg) rotateY(" + ((-1 * mousePosition.x) + (windowSize.width / 2)) / 20 + "deg)"
: "perspective(1000px) rotateX(0deg) rotateY(0deg)"
,
}}
>
<div id="wrap">
<h1>{
mode === 0 ? "Swiss Town" :
mode === 1 ? "Sigma Town" :
mode === 2 ? "爱国华为官小分红习近平思想讨论组"
: "Error"}
</h1>
</div>
<h2>Server IP:</h2>
<ClipboardCopy copyText={"mc.7800.io"}/>
<small id="ip-tagline">version 1.19.4, port 25565</small>
<a className="main-button-style" href="/whitelist">Join the whitelist</a>
<PrankButton characteristics={characteristics} audio={audio}/>
<SettingsPane
mode={mode}
characteristics={characteristics}
tendencies={tendencies}
setMode={setMode}
setCharacteristics={setCharacteristics}
setTendencies={setTendencies}
audio={audio}
/>
<a id="yaqub" href="https://yaqubro.li">made on the island of patmos 6,600 years ago</a>
</div>
);
}
function Gatito({ mode, tendencies }) {
return (
<img className={getClassName("Gatito", mode, false, tendencies)} src={
mode === 0 ? "/img/bingus.png" :
mode === 1 ? "/img/dripfloppa.png" :
mode === 2 ? "/img/sploingus.png" :
"/img/bingus.png"
}/>
);
}
export default App;
reportWebVitals();
@@ -1,0 +1,7 @@
let stringTable = {
server_name: "mc.7800.io",
server_version: "1.19.4",
server_port: "25565"
};
export default stringTable;
Binary files /dev/null and a/public/mp3/jiafei.mp3 differ
@@ -1,10 +1,15 @@
import React from 'react';
import ClipboardCopy from './ClipboardCopy';
import PrankButton from './PrankButton';
import SettingsPane from './SettingsPane';
import getClassName from '../utils/getClassName';
import MainUI from './MainUI';
import WhitelistUI from './WhitelistUI';
function MainDiv({ mode, characteristics, tendencies, setMode, setCharacteristics, setTendencies, mousePosition, windowSize, audio }) {
function MainDiv({ mode, characteristics, tendencies, joinWhitelist, setMode, setCharacteristics, setTendencies, setJoinWhitelist, mousePosition, windowSize, audio }) {
const [whitelistUI, setWhitelistUI] = React.useState(false);
return (
<div
className={getClassName("MainDiv", mode, characteristics, tendencies)}
@@ -16,35 +21,18 @@
,
}}
>
<div id="wrap">
<h1>{
mode === 0 ? "Swiss Town" :
mode === 1 ? "Sigma Town" :
mode === 2 ? "爱国华为官小分红习近平思想讨论组"
: "Error"}
</h1>
</div>
<h2>Server IP:</h2>
<ClipboardCopy
copyText={"mc.7800.io"}
tendencies={tendencies}
characteristics={characteristics}
audio={audio}
mousePosition={mousePosition}
/>
<small id="ip-tagline">version 1.19.4, port 25565</small>
<a className="main-button-style" href="/whitelist">Join the whitelist</a>
<PrankButton characteristics={characteristics} audio={audio}/>
<SettingsPane
{ whitelistUI ? <WhitelistUI /> :
<MainUI
mode={mode}
characteristics={characteristics}
tendencies={tendencies}
joinWhitelist={whitelistUI}
setMode={setMode}
setCharacteristics={setCharacteristics}
setTendencies={setTendencies}
setWhitelistUI={setWhitelistUI}
audio={audio}
/>
<a id="yaqub" href="https://yaqubro.li">made on the island of patmos 6,600 years ago</a>
/> }
</div>
);
}
@@ -1,0 +1,44 @@
import React from 'react';
import ClipboardCopy from './ClipboardCopy';
import PrankButton from './PrankButton';
import SettingsPane from './SettingsPane';
import getClassName from '../utils/getClassName';
function MainUI({ mode, characteristics, tendencies, setMode, setCharacteristics, setTendencies, setWhitelistUI, mousePosition, windowSize, audio }) {
return (
<div
className={getClassName("MainUI", mode, characteristics, tendencies)}
>
<h1>{
mode === 0 ? "Swiss Town" :
mode === 1 ? "Sigma Town" :
mode === 2 ? "爱国华为官小分红习近平思想讨论组"
: "Error"}
</h1>
<h2>Server IP:</h2>
<ClipboardCopy
copyText={"mc.7800.io"}
tendencies={tendencies}
characteristics={characteristics}
audio={audio}
mousePosition={mousePosition}
/>
<small id="ip-tagline">version 1.19.4, port 25565</small>
<span className="main-button-style" onClick={() => setWhitelistUI(true)}>Join the whitelist</span>
<a className="main-button-style" href="/dynmap">View the dynmap</a>
<PrankButton characteristics={characteristics} audio={audio}/>
<SettingsPane
mode={mode}
characteristics={characteristics}
tendencies={tendencies}
setMode={setMode}
setCharacteristics={setCharacteristics}
setTendencies={setTendencies}
audio={audio}
/>
</div>
);
}
export default MainUI;
@@ -1,21 +1,25 @@
import React from 'react';
import TextMouseSpooler from './TextMouseSpooler';
import getClassName from '../utils/getClassName';
function MouseFollower({ mode, characteristics, tendencies, mousePosition, windowSize }) {
return (
mode === 2 && tendencies ?
mode === 2 ?
<img
className={getClassName("MouseFollower", mode, characteristics, tendencies)}
src="/img/talisman.png"
style= {{
transform: "translate(" + (50 + mousePosition.x - (windowSize.width / 2)) + "px, " + (80 + mousePosition.y - (windowSize.height / 2)) + "px)",
}}
/> : <TextMouseSpooler
/> : mode == 0 ? <TextMouseSpooler
frequentSaying="Swiss!"
lessFrequentSaying="Swag!"
mousePosition={mousePosition}
/>
/> : mode == 1 ? <TextMouseSpooler
frequentSaying="Bussin!"
lessFrequentSaying="Grindset!"
mousePosition={mousePosition}
/> : null
);
}
@@ -1,0 +1,34 @@
import React from "react";
import getClassName from "../utils/getClassName";
function WhitelistUI() {
return (
<div className={getClassName("WhitelistUI")}>
<h1>Join the whitelist</h1>
<div id="with-sta-email">
<h3>If you have a St. Andrews email</h3>
<form action="https://mc.7800.io/whitelist" method="post">
<input type="hidden" name="st-andrews" value="true" />
<label htmlFor="email">St. Andrews email (prefix only):</label>
<input type="text" id="email" name="email" />
<label htmlFor="minecraft-username">Minecraft username:</label>
<input type="text" name="minecraft-username" />
<input type="submit" value="Submit" />
</form>
</div>
<div id="without-sta-email">
<h3>If you don't</h3>
<form action="https://mc.7800.io/whitelist" method="post">
<input type="hidden" name="st-andrews" value="false" />
<label htmlFor="minecraft-username">Minecraft username:</label>
<input type="text" name="minecraft-username" />
<label htmlFor="reason">Reason for joining:</label>
<textarea name="reason" id="reason" cols="30" rows="10"></textarea>
<input type="submit" value="Submit" />
</form>
</div>
</div>
);
}
export default WhitelistUI;