working
@@ -10,7 +10,8 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"canvas-confetti": "^1.9.4",
|
"canvas-confetti": "^1.9.4",
|
||||||
"react": "^19.2.0",
|
"react": "^19.2.0",
|
||||||
"react-dom": "^19.2.0"
|
"react-dom": "^19.2.0",
|
||||||
|
"react-router-dom": "^7.13.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.39.1",
|
"@eslint/js": "^9.39.1",
|
||||||
@@ -1971,6 +1972,19 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/cookie": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/express"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/cross-spawn": {
|
"node_modules/cross-spawn": {
|
||||||
"version": "7.0.6",
|
"version": "7.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||||
@@ -2869,6 +2883,44 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-router": {
|
||||||
|
"version": "7.13.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.13.0.tgz",
|
||||||
|
"integrity": "sha512-PZgus8ETambRT17BUm/LL8lX3Of+oiLaPuVTRH3l1eLvSPpKO3AvhAEb5N7ihAFZQrYDqkvvWfFh9p0z9VsjLw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"cookie": "^1.0.1",
|
||||||
|
"set-cookie-parser": "^2.6.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=18",
|
||||||
|
"react-dom": ">=18"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-router-dom": {
|
||||||
|
"version": "7.13.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.13.0.tgz",
|
||||||
|
"integrity": "sha512-5CO/l5Yahi2SKC6rGZ+HDEjpjkGaG/ncEP7eWFTvFxbHP8yeeI0PxTDjimtpXYlR3b3i9/WIL4VJttPrESIf2g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"react-router": "7.13.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=18",
|
||||||
|
"react-dom": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/resolve-from": {
|
"node_modules/resolve-from": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
|
||||||
@@ -2940,6 +2992,12 @@
|
|||||||
"semver": "bin/semver.js"
|
"semver": "bin/semver.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/set-cookie-parser": {
|
||||||
|
"version": "2.7.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz",
|
||||||
|
"integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/shebang-command": {
|
"node_modules/shebang-command": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||||
|
|||||||
@@ -12,7 +12,8 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"canvas-confetti": "^1.9.4",
|
"canvas-confetti": "^1.9.4",
|
||||||
"react": "^19.2.0",
|
"react": "^19.2.0",
|
||||||
"react-dom": "^19.2.0"
|
"react-dom": "^19.2.0",
|
||||||
|
"react-router-dom": "^7.13.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.39.1",
|
"@eslint/js": "^9.39.1",
|
||||||
|
|||||||
@@ -1,187 +1,12 @@
|
|||||||
import { useState } from "react";
|
import { Routes, Route } from "react-router-dom";
|
||||||
import { useRef } from "react";
|
import HomePage from "./HomePage";
|
||||||
import confetti from "canvas-confetti";
|
import YesPage from "./yes";
|
||||||
import "./App.css";
|
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const blockbusterRef = useRef(null);
|
|
||||||
|
|
||||||
const moveButton = () => {
|
|
||||||
const button = blockbusterRef.current;
|
|
||||||
const dialog = button.closest("dialog");
|
|
||||||
|
|
||||||
const dialogRect = dialog.getBoundingClientRect();
|
|
||||||
const buttonRect = button.getBoundingClientRect();
|
|
||||||
|
|
||||||
const padding = 20;
|
|
||||||
|
|
||||||
const maxX = dialogRect.width - buttonRect.width - padding;
|
|
||||||
const maxY = dialogRect.height - buttonRect.height - padding;
|
|
||||||
|
|
||||||
const x = Math.random() * maxX;
|
|
||||||
const y = Math.random() * maxY;
|
|
||||||
|
|
||||||
button.style.left = `${x}px`;
|
|
||||||
button.style.top = `${y}px`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const dialogRef = useRef(null);
|
|
||||||
|
|
||||||
const openPopup = () => {
|
|
||||||
dialogRef.current.showModal();
|
|
||||||
};
|
|
||||||
|
|
||||||
const closePopup = () => {
|
|
||||||
dialogRef.current.close();
|
|
||||||
};
|
|
||||||
const [showConfirm, setShowConfirm] = useState(false);
|
|
||||||
const [showConfirm2, setShowConfirm2] = useState(false);
|
|
||||||
const [showConfirm3, setShowConfirm3] = useState(false);
|
|
||||||
const [showConfirm4, setShowConfirm4] = useState(false);
|
|
||||||
const [showDeclineQ, setShowDeclineQ] = useState(false);
|
|
||||||
const [showDeclineOffer, setShowDeclineOffer] = useState(false);
|
|
||||||
|
|
||||||
const handleYes = () => {
|
|
||||||
const bursts = 9; // how many times it fires
|
|
||||||
|
|
||||||
for (let i = 0; i < bursts; i++) {
|
|
||||||
setTimeout(() => {
|
|
||||||
confetti({
|
|
||||||
particleCount: 80,
|
|
||||||
spread: 70,
|
|
||||||
origin: {
|
|
||||||
x: Math.random(), // 0 → 1 (left to right)
|
|
||||||
y: 0.9
|
|
||||||
// y: Math.random() * 0.6 // top half of screen
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}, i * 200); // delay between bursts (ms)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleNo = () => {
|
|
||||||
setShowConfirm(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleYes2 = () => {
|
|
||||||
setShowConfirm2(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleYes3 = () => {
|
|
||||||
setShowConfirm3(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleYes4 = () => {
|
|
||||||
setShowConfirm4(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleNo5 = () => {
|
|
||||||
setShowDeclineQ(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container">
|
<Routes>
|
||||||
<h1>Will you be my Valentine? 💖</h1>
|
<Route path="/" element={<HomePage />} />
|
||||||
|
<Route path="/yes" element={<YesPage />} />
|
||||||
<div className="photos">
|
</Routes>
|
||||||
<div className="photo">Photo 1</div>
|
|
||||||
<div className="photo">Photo 2</div>
|
|
||||||
<div className="photo">Photo 3</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="buttons">
|
|
||||||
<button className="yes" onClick={handleYes}>
|
|
||||||
Yes 💕🥳
|
|
||||||
</button>
|
|
||||||
<button className="no" onClick={handleNo}>
|
|
||||||
No 😢
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{showConfirm && (
|
|
||||||
<div className="overlay">
|
|
||||||
<div className="popup">
|
|
||||||
<h2>Are you sure? 😢</h2>
|
|
||||||
<button className="yes" onClick={handleYes2}>
|
|
||||||
Yes
|
|
||||||
</button>
|
|
||||||
<button className="no" onClick={handleYes}>
|
|
||||||
No
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{showConfirm2 && (
|
|
||||||
<div className="overlay">
|
|
||||||
<div className="popup">
|
|
||||||
<h2>Are you sure you're sure? 😭</h2>
|
|
||||||
<button className="yes" onClick={handleYes3}>
|
|
||||||
Yes
|
|
||||||
</button>
|
|
||||||
<button className="no" onClick={handleYes}>
|
|
||||||
No
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{showConfirm3 && (
|
|
||||||
<div className="overlay">
|
|
||||||
<div className="popup">
|
|
||||||
<h2>Are you sure that you're sure of being sure? 💔😭</h2>
|
|
||||||
<button className="yes" onClick={handleYes4}>
|
|
||||||
Yes
|
|
||||||
</button>
|
|
||||||
<button className="no" onClick={handleNo}>
|
|
||||||
No
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{showConfirm4 && (
|
|
||||||
<div className="overlay">
|
|
||||||
<div className="popup">
|
|
||||||
<h2>Have you tried being unsure? 🤞🙏</h2>
|
|
||||||
<button className="yes" onClick={handleYes}>
|
|
||||||
Yes
|
|
||||||
</button>
|
|
||||||
<button className="no" onClick={handleNo5}>
|
|
||||||
No
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{showDeclineQ && (
|
|
||||||
<div className="overlay">
|
|
||||||
<div className="popup">
|
|
||||||
<h2>Would you like to decline to be my valentine? 💔😭😢</h2>
|
|
||||||
<button className="yes" onClick={openPopup}>
|
|
||||||
Yes
|
|
||||||
</button>
|
|
||||||
<button className="no" onClick={handleNo}>
|
|
||||||
No
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<dialog ref={dialogRef} className="modal">
|
|
||||||
<h2>How to Decline Offer:</h2>
|
|
||||||
<p>Offer can only be declined in person at your nearest Blockbuster location*</p>
|
|
||||||
<p>*Bend, Oregon location is not a valid location to decline this offer</p>
|
|
||||||
|
|
||||||
<button onClick={closePopup}>
|
|
||||||
I understand, I'll be your valentine 💖
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
ref={blockbusterRef}
|
|
||||||
className="runaway"
|
|
||||||
onMouseEnter={moveButton}
|
|
||||||
onClick={closePopup}
|
|
||||||
>
|
|
||||||
I understand, I will go to blockbuster
|
|
||||||
</button>
|
|
||||||
</dialog>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,236 @@
|
|||||||
|
import { useRef, useState } from "react";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import confetti from "canvas-confetti";
|
||||||
|
import hozier from "./assets/hozier.jpeg"
|
||||||
|
import newberg_tree from "./assets/newberg_tree.jpeg"
|
||||||
|
import newberg_tractor from "./assets/newberg_tractor.jpeg"
|
||||||
|
import panic from "./assets/panic.jpeg"
|
||||||
|
import corvallis from "./assets/corvallis.jpeg"
|
||||||
|
import seal_rock from "./assets/seal_rock.jpeg"
|
||||||
|
import yaquina_lighthouse from "./assets/yaquina_lighthouse.jpeg"
|
||||||
|
import "./App.css";
|
||||||
|
|
||||||
|
export default function Homepage() {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const dialogRef = useRef(null);
|
||||||
|
const blockbusterButtonRef = useRef(null);
|
||||||
|
|
||||||
|
const isTouchDevice = () =>
|
||||||
|
"ontouchstart" in window || navigator.maxTouchPoints > 0;
|
||||||
|
|
||||||
|
const [showConfirm, setShowConfirm] = useState(false);
|
||||||
|
const [showConfirm2, setShowConfirm2] = useState(false);
|
||||||
|
const [showConfirm3, setShowConfirm3] = useState(false);
|
||||||
|
const [showConfirm4, setShowConfirm4] = useState(false);
|
||||||
|
const [showDeclineQ, setShowDeclineQ] = useState(false);
|
||||||
|
|
||||||
|
const openPopup = () => {
|
||||||
|
dialogRef.current.showModal();
|
||||||
|
|
||||||
|
// Wait for layout to settle
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
const button = blockbusterButtonRef.current;
|
||||||
|
const rect = button.getBoundingClientRect();
|
||||||
|
|
||||||
|
button.style.left = `${rect.left}px`;
|
||||||
|
button.style.top = `${rect.top}px`;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------
|
||||||
|
* Runaway Blockbuster button logic
|
||||||
|
* ------------------------------------------------------------------ */
|
||||||
|
const moveButton = () => {
|
||||||
|
const button = blockbusterButtonRef.current;
|
||||||
|
|
||||||
|
const buttonRect = button.getBoundingClientRect();
|
||||||
|
|
||||||
|
const padding = 16;
|
||||||
|
|
||||||
|
const maxX = window.innerWidth - buttonRect.width - padding;
|
||||||
|
const maxY = window.innerHeight - buttonRect.height - padding;
|
||||||
|
|
||||||
|
const x = Math.random() * maxX;
|
||||||
|
const y = Math.random() * maxY;
|
||||||
|
|
||||||
|
button.style.left = `${Math.max(padding, x)}px`;
|
||||||
|
button.style.top = `${Math.max(padding, y)}px`;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const handleRunawayPress = (event) => {
|
||||||
|
if (isTouchDevice()) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
moveButton();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------
|
||||||
|
* Button handlers
|
||||||
|
* ------------------------------------------------------------------ */
|
||||||
|
const handleAccept = () => {
|
||||||
|
const bursts = 9;
|
||||||
|
|
||||||
|
for (let i = 0; i < bursts; i++) {
|
||||||
|
setTimeout(() => {
|
||||||
|
confetti({
|
||||||
|
particleCount: 80,
|
||||||
|
spread: 70,
|
||||||
|
origin: {
|
||||||
|
x: Math.random(),
|
||||||
|
y: 0.9,
|
||||||
|
// y: Math.random() * 0.6
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}, i * 200);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNo = () => {
|
||||||
|
setShowConfirm(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleYes2 = () => {
|
||||||
|
setShowConfirm2(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleYes3 = () => {
|
||||||
|
setShowConfirm3(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleYes4 = () => {
|
||||||
|
setShowConfirm4(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNo5 = () => {
|
||||||
|
setShowDeclineQ(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------
|
||||||
|
* Render
|
||||||
|
* ------------------------------------------------------------------ */
|
||||||
|
return (
|
||||||
|
<div className="container">
|
||||||
|
<h1>Will you be my Valentine? 💖</h1>
|
||||||
|
|
||||||
|
<div className="photos">
|
||||||
|
<div className="photo">
|
||||||
|
<img src={newberg_tree} alt="Photo 1" />
|
||||||
|
</div>
|
||||||
|
<div className="photo">
|
||||||
|
<img src={hozier} alt="Photo 1" />
|
||||||
|
</div>
|
||||||
|
<div className="photo">
|
||||||
|
<img src={panic} alt="Photo 1" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="buttons">
|
||||||
|
<button className="yes" onClick={handleAccept}>
|
||||||
|
Yes 💕🥳
|
||||||
|
</button>
|
||||||
|
<button className="no" onClick={handleNo}>
|
||||||
|
No 😢
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{showConfirm && (
|
||||||
|
<div className="overlay">
|
||||||
|
<div className="popup">
|
||||||
|
<h3>Are you sure? 😢</h3>
|
||||||
|
<button className="yes" onClick={handleYes2}>
|
||||||
|
Yes
|
||||||
|
</button>
|
||||||
|
<button className="no" onClick={handleAccept}>
|
||||||
|
No
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{showConfirm2 && (
|
||||||
|
<div className="overlay">
|
||||||
|
<div className="popup">
|
||||||
|
<h3>Are you sure you're sure? 😭</h3>
|
||||||
|
<button className="yes" onClick={handleYes3}>
|
||||||
|
Yes
|
||||||
|
</button>
|
||||||
|
<button className="no" onClick={handleAccept}>
|
||||||
|
No
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{showConfirm3 && (
|
||||||
|
<div className="overlay">
|
||||||
|
<div className="popup">
|
||||||
|
<h3>Are you sure that you're sure of being sure? 💔😭</h3>
|
||||||
|
<button className="yes" onClick={handleYes4}>
|
||||||
|
Yes
|
||||||
|
</button>
|
||||||
|
<button className="no" onClick={handleAccept}>
|
||||||
|
No
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{showConfirm4 && (
|
||||||
|
<div className="overlay">
|
||||||
|
<div className="popup">
|
||||||
|
<h3>Have you tried being unsure? 🤞🙏</h3>
|
||||||
|
<button className="yes" onClick={handleAccept}>
|
||||||
|
Yes
|
||||||
|
</button>
|
||||||
|
<button className="no" onClick={handleNo5}>
|
||||||
|
No
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{showDeclineQ && (
|
||||||
|
<div className="overlay">
|
||||||
|
<div className="popup">
|
||||||
|
<h3>Would you like to decline to be my valentine? 💔😭😢</h3>
|
||||||
|
<button className="yes" onClick={openPopup}>
|
||||||
|
Yes
|
||||||
|
</button>
|
||||||
|
<button className="no" onClick={handleNo}>
|
||||||
|
No
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<dialog ref={dialogRef} className="modal">
|
||||||
|
<h2>How to Decline Offer:</h2>
|
||||||
|
<p>
|
||||||
|
Offer can only be declined in person at your nearest Blockbuster
|
||||||
|
location*
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
*Bend, Oregon location is not a valid location to decline this offer
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<button onClick={handleAccept}>
|
||||||
|
I understand, I'll be your valentine 💖
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
ref={blockbusterButtonRef}
|
||||||
|
className="runaway"
|
||||||
|
onMouseEnter={moveButton} // desktop
|
||||||
|
onTouchStart={handleRunawayPress} // mobile
|
||||||
|
onClick={handleRunawayPress} // fallback
|
||||||
|
>
|
||||||
|
I understand, I will go to blockbuster
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</dialog>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 2.5 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 918 KiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 2.2 MiB |
|
After Width: | Height: | Size: 456 KiB |
|
After Width: | Height: | Size: 502 KiB |
@@ -42,7 +42,7 @@ button {
|
|||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
background-color: #1a1a1a;
|
background-color: #531300;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: border-color 0.25s;
|
transition: border-color 0.25s;
|
||||||
}
|
}
|
||||||
@@ -81,9 +81,33 @@ dialog::backdrop {
|
|||||||
|
|
||||||
.modal {
|
.modal {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
overflow: hidden; /* prevent scrollbars */
|
||||||
}
|
}
|
||||||
|
|
||||||
.runaway {
|
.runaway {
|
||||||
position: absolute;
|
position: fixed; /* escape the dialog */
|
||||||
transition: left 0.15s ease, top 0.15s ease;
|
z-index: 9999; /* above everything */
|
||||||
|
transition: left 0.12s ease, top 0.12s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.photos {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap; /* allow photos to wrap to next line */
|
||||||
|
gap: 12px; /* space between photos */
|
||||||
|
justify-content: center; /* center on screen */
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.photo img {
|
||||||
|
width: 150px;
|
||||||
|
height: 150px;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 4px 10px rgba(0,0,0,0.15);
|
||||||
|
transition: transform 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo img:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
import { StrictMode } from 'react'
|
import React from "react";
|
||||||
import { createRoot } from 'react-dom/client'
|
import ReactDOM from "react-dom/client";
|
||||||
import './index.css'
|
import { BrowserRouter } from "react-router-dom";
|
||||||
import App from './App.tsx'
|
import App from "./App";
|
||||||
|
import "./index.css"; // your global styles
|
||||||
|
|
||||||
createRoot(document.getElementById('root')!).render(
|
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
|
||||||
<StrictMode>
|
<React.StrictMode>
|
||||||
<App />
|
<BrowserRouter>
|
||||||
</StrictMode>,
|
<App />
|
||||||
)
|
</BrowserRouter>
|
||||||
|
</React.StrictMode>
|
||||||
|
);
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
export default function YesPage() {
|
||||||
|
return (
|
||||||
|
<div className="container">
|
||||||
|
<h1>Congratulations, you're now my valentine!!! 💖🥳</h1>
|
||||||
|
<h2>Great job using the freewill the website gave you to make the right choice!!!</h2>
|
||||||
|
<h3>No takebacks allowed, you're stuck with me 🎉</h3>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -4,4 +4,7 @@ import react from '@vitejs/plugin-react'
|
|||||||
// https://vite.dev/config/
|
// https://vite.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
|
server: {
|
||||||
|
host: true,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|||||||