Compare commits

...

23 Commits
main ... main

Author SHA1 Message Date
db3a8d6b15 ihr ihr ihr3
All checks were successful
continuous-integration/drone/push Build is passing
2025-10-21 17:34:51 +02:00
88d806c0e4 ihr ihr ihr2
All checks were successful
continuous-integration/drone/push Build is passing
2025-10-21 17:34:06 +02:00
52ca7a2b0f ihr ihr ihr
All checks were successful
continuous-integration/drone/push Build is passing
2025-10-21 17:32:01 +02:00
f942c73b02 we we we
All checks were successful
continuous-integration/drone/push Build is passing
2025-10-21 17:05:05 +02:00
07507d46e0 So this is Christmas And what have you done Another year over And a new one just begun
All checks were successful
continuous-integration/drone/push Build is passing
2025-10-13 18:05:16 +02:00
e116fee53a Bump year in Title/Description
All checks were successful
continuous-integration/drone/push Build is passing
2024-11-11 13:53:02 +01:00
a313e09410 Trigger CI
All checks were successful
continuous-integration/drone/push Build is passing
2024-11-09 14:28:19 +01:00
e2e6799f49 update 2024-11-09 13:11:57 +01:00
41598ffa32 fix oopsie 2023-11-28 15:58:48 +01:00
3df1360c66 2k23 2023-11-28 15:33:28 +01:00
95ed928f18 logo
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-21 15:19:36 +01:00
9f643fae78 Update wording
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-21 14:53:17 +01:00
8262e1fa5b SS,SH,FB: text rewriting, tech fixes
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-18 14:55:18 +01:00
171d710bac more info
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-17 15:30:01 +01:00
Mrmaxmeier
2e1f63c5f2 more cleanup
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-15 14:36:42 +01:00
Mrmaxmeier
9a227a1e47 remove workarounds
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-15 14:25:40 +01:00
59901b4c92 kill die react kacke im titel 2.0
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-14 23:54:46 +01:00
9285d46840 titel
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-14 23:44:12 +01:00
21faf7b043 soprafixes
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-14 23:31:30 +01:00
c25d746ecb looks better now
Some checks failed
continuous-integration/drone/push Build is failing
2022-11-14 23:28:16 +01:00
8a5a7cc732 background maybe but not maybe
Some checks failed
continuous-integration/drone/push Build is failing
2022-11-14 22:30:20 +01:00
303aa556cf compiles locally and somewhat works locally
Some checks failed
continuous-integration/drone/push Build is failing
2022-11-14 21:20:26 +01:00
Dominic Zimmer
45f6c958fe Pipeline test
All checks were successful
continuous-integration/drone/push Build is passing
2022-11-14 16:24:09 +01:00
16 changed files with 26096 additions and 108 deletions

16692
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,9 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.2.0",
"@fortawesome/free-solid-svg-icons": "^6.2.0",
"@fortawesome/react-fontawesome": "^0.2.0",
"@testing-library/jest-dom": "^5.16.5", "@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0", "@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
@ -10,9 +13,11 @@
"@types/node": "^16.11.64", "@types/node": "^16.11.64",
"@types/react": "^18.0.21", "@types/react": "^18.0.21",
"@types/react-dom": "^18.0.6", "@types/react-dom": "^18.0.6",
"fortawesome": "^0.0.1-security",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"serve": "^14.2.1",
"typescript": "^4.8.4", "typescript": "^4.8.4",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
}, },

BIN
public/background.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

BIN
public/background.mp4 Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -3,11 +3,12 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<meta <meta
name="description" name="description"
content="Web site created using create-react-app" content="Weihnachtsfeier 2025"
/> />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!-- <!--
@ -24,7 +25,7 @@
work correctly both with client-side routing and a non-root public URL. work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`. Learn how to configure a non-root public URL by running `npm run build`.
--> -->
<title>React App</title> <title>Weihnachtsfeier 2025</title>
</head> </head>
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View File

@ -1,6 +1,6 @@
{ {
"short_name": "React App", "short_name": "Weihnachtsfeier",
"name": "Create React App Sample", "name": "Weihnachtsfeier 2023",
"icons": [ "icons": [
{ {
"src": "favicon.ico", "src": "favicon.ico",

View File

@ -41,8 +41,7 @@ export const PartyContextProvider: React.FC<{ children: React.ReactNode }> = (pr
const [partyContext, setPartyContext] = useState<PartyContextType>(); const [partyContext, setPartyContext] = useState<PartyContextType>();
const apiEndpoint = useMemo<APIEndPoint>(() => { const apiEndpoint = useMemo<APIEndPoint>(() => {
// eslint-disable-next-line no-restricted-globals const href = window.location.href;
const href = location.href;
const p = parseURI(href); const p = parseURI(href);
if (!p) return { partyName: "error", token: "" } if (!p) return { partyName: "error", token: "" }
return p; return p;

View File

@ -4,41 +4,107 @@
background-color: black; background-color: black;
} }
.App { .App {
color: white;
font-size: calc(7px + 2vmin);
text-shadow:
-1px -1px 0.2em #000,
1px -1px 0.2em #000,
-1px 1px 0.2em #000,
1px 1px 0.2em #000;
text-align: center;
display: flex;
justify-content: center;
}
.container {
max-width: 1224px;
margin-left: 3ch;
margin-right: 3ch;
}
.fullheight {
min-height: 100vh;
}
.hero {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.hero-outer {
flex-grow: 1;
display: flex;
flex-direction: column;
justify-content: center;
padding-bottom: 0.5em;
}
@media (min-width: 1024px) {
.hero-outer {
justify-content: flex-end;
}
}
h1,
h2 {
margin: 1em 0 0.1em 0;
}
p {
margin: 0.3em 0 0.3em 0;
}
.feedback {
line-height: 3em;
text-align: center; text-align: center;
} }
.App-logo { input[type="radio"] {
height: 40vmin; display: none;
pointer-events: none;
} }
@media (prefers-reduced-motion: no-preference) { input[type="radio"]+label {
.App-logo { font-size: larger;
animation: App-logo-spin infinite 20s linear; cursor: pointer;
} padding: 0 1em 0 1em;
border-right: 0.1em solid white;
} }
.App-header { input[type="radio"]+label:hover {
background-color: #282c34; text-shadow: 0 0 1em white;
min-height: 100vh; }
display: flex;
flex-direction: column; input[type="radio"]+label:last-of-type {
align-items: center; border-right: none;
justify-content: center; }
font-size: calc(10px + 2vmin);
input[type="radio"]:checked+label {
color: var(--selected-color);
text-shadow: 0 0 1em var(--selected-color);
text-decoration: underline;
}
#coming-yes+label {
--selected-color: #0f0;
}
#coming-maybe+label {
--selected-color: #fc0;
}
#coming-no+label {
--selected-color: #f00;
}
.hooverdam:hover {
text-shadow: 0 0 1em white;
}
a {
color: white; color: white;
} }
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

View File

@ -1,27 +1,128 @@
import React, { useContext } from 'react'; import React, { ChangeEvent, useContext, useRef, useState } from 'react';
import logo from './logo.svg';
import './PartyPage.css'; import './PartyPage.css';
import { PartyContext } from './PartyContext'; import { APIEndPoint, PartyContext, PartyStatus } from './PartyContext';
// import MatrixBackground from './MatrixBackground';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faAngleDown, faCalendarDays, faLocationDot } from '@fortawesome/free-solid-svg-icons';
import { modifySelfRequest, parseURI } from './partyApi';
const myDear = {
"m": "lieber",
"f": "liebe",
"d": "",
};
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function getComingString(party: PartyStatus): string {
if (party.maybe_coming === 0) {
// exact number
if (party.definitely_coming === 0) {
return "Bisher hat noch niemand zugesagt."
} else if (party.definitely_coming === 1) {
return "Bisher hat ein Gast zugesagt."
} else {
return `Es haben schon ${party.definitely_coming} Gäste zugesagt.`
}
} else {
// inexact
if (party.definitely_coming === 0 && party.maybe_coming === 1) {
return "Bisher hat ein Gast vorläufig zugesagt."
} else if (party.definitely_coming === 0) {
return `Bisher haben ${party.maybe_coming} Gäste vorläufig zugesagt.`
} else {
return `Nach den bisherigen Zusagen kommen ${party.definitely_coming} bis ${party.definitely_coming + party.maybe_coming} Gäste.`
}
}
}
export const PartyPage: React.FC = () => { export const PartyPage: React.FC = () => {
const partyContext = useContext(PartyContext); const partyContext = useContext(PartyContext);
const dear = myDear[partyContext.self.grammatical_gender];
const name = partyContext.self.name;
const isMehrzahl = partyContext.self.grammatical_gender === "d";
const wannUndWoRef = useRef<HTMLDivElement>(null)
const executeScroll = () => {
wannUndWoRef.current!.scrollIntoView({ behavior: 'smooth' })
}
const [comingState, setComingState] = useState(partyContext.self.coming);
return <div className="App" > // SAFETY: If this is undefined, the contextProvider already fails
<header className="App-header" > const endpoint = parseURI(window.location.href) as APIEndPoint;
<img src={logo} className="App-logo" alt="logo" />
const handleSelect = async (e: ChangeEvent) => {
const value = (e.target as HTMLInputElement).value;
if (value !== "yes" && value !== "no" && value !== "maybe") {
throw new Error("received invalid value?");
}
const status = await modifySelfRequest(endpoint, { coming: value });
setComingState(status.coming);
}
return <div className="App">
<div className='container'>
<div className='hero fullheight'>
<div className='hero-outer'></div>
<h1>Hallo {dear} {name},</h1>
<p> <p>
Edit <code> src/PartyPage.tsx </code> and save to reload. wir laden {isMehrzahl ? 'euch' : 'dich'} am <strong>Freitag, den 19. Dezember</strong> herzlich ein, mit uns zu feiern!
</p> </p>
<a <p>
className="App-link" Ab <strong>19:00</strong> veranstalten wir nämlich wieder unsere alljährliche Weihnachtsparty!
href="https://reactjs.org" </p>
target="_blank" <p>
rel="noopener noreferrer" Wir würden uns sehr freuen, wenn auch {isMehrzahl ? 'ihr' : 'du'}, {dear} {name}, {isMehrzahl ? 'dabei seid.' : 'dabei bist :)'}
> </p>
Learn React <div className='feedback'>
</a> <input type="radio" id="coming-yes" name="coming" value="yes" checked={comingState === "yes"} onChange={handleSelect} />
<span>Hello {partyContext.self.name}</span> <label htmlFor='coming-yes'>Ja</label>
</header> <input type="radio" id="coming-maybe" name="coming" value="maybe" checked={comingState === "maybe"} onChange={handleSelect} />
<label htmlFor='coming-maybe'>Vielleicht</label>
<input type="radio" id="coming-no" name="coming" value="no" checked={comingState === "no"} onChange={handleSelect} />
<label htmlFor='coming-no'>Nein</label>
</div>
<div className='hero-outer' >
<span className='hooverdam' onClick={executeScroll}>
<p>Mehr Infos</p>
<FontAwesomeIcon icon={faAngleDown} />
</span>
</div>
</div>
<div className='hero fullheight' ref={wannUndWoRef}>
<h2>Wann und Wo?</h2>
<p>
<FontAwesomeIcon icon={faCalendarDays} /> <strong>&nbsp;19. Dezember, ab 19:00</strong>. Bitte kommt nicht all zu spät.
</p>
<p>
<FontAwesomeIcon icon={faLocationDot} /> <strong>&nbsp;Gebäude E1 1, Raum 407</strong>, Universität des Saarlandes
</p>
<h2>Was ist geplant?</h2>
<p>
Wir (Iona, Sebastian &amp; Simon) wollen uns mit euch auf Weihnachten einstimmen.
Wir planen ein weihnachtliches Programm mit Geschichten, Liedern, Essen und der einen oder anderen Überraschung. Falls du ein Instrument spielst, bring es auch gerne mit.
</p>
<p>
Natürlich haben wir auch genügend Zeit, uns gemütlich bei einem Heißgetränk zu unterhalten.
</p>
<h2>Was gibt es zu Essen?</h2>
<p>
Wir planen ein Potluck-Event. Damit sollte für alle genug Essen dabei sein.
Getränke, insbesondere Glühwein, Kinderpunsch und Ähnliches, wird von uns organisiert.
</p>
<h2>Was soll ich mitbringen?</h2>
<p>
Es wäre super, wenn du zum Potluck ein Gericht mitbringen kannst. Für Inspirationen kannst du uns natürlich gerne fragen, oder schon einmal <a href="https://www.tasteofhome.com/collection/vegetarian-potluck-recipes/">hier</a> vorbeischauen.
Bitte informiere uns kurz, was du gerne mitbringen würdest, damit wir besser kalkulieren können.
Ansonsten darfst du auch sehr gerne Plätzchen, Weihnachtsdeko oder Ähnliches mitbringen.
</p>
<p>
Falls du ansonsten Wünsche oder Anregungen für einen gelungenen Abend hast, teil uns diese gerne mit!
</p>
</div>
</div>
</div> </div>
}; };

BIN
src/background.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

View File

@ -11,3 +11,14 @@ code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace; monospace;
} }
body {
background-image: url('./background.gif');
background-size: cover;
background-position: center;
background-attachment: fixed;
height: 100vh;
padding:0;
margin:0;
}

View File

@ -1,16 +1,21 @@
import { APIEndPoint, PartyStatus, SelfStatus, UpdatableSelfStatus } from "./PartyContext"; import { APIEndPoint, PartyStatus, SelfStatus, UpdatableSelfStatus } from "./PartyContext";
export const parseURI = (uri: string): APIEndPoint | undefined => { export const parseURI = (uri: string): APIEndPoint | undefined => {
const x = uri.match(/https?:\/\/(?<partyName>.+)\.party\.leafbla\.de\/(?<token>.+)/); // const x = uri.match(/https?:\/\/(?<partyName>.+)\.party\.leafbla\.de\/(?<token>.+)/);
const x = uri.match(/https?:\/\/[^/]+\/(?<token>.+)/);
if (x === null || x.groups === undefined) return; if (x === null || x.groups === undefined) return;
const partyName = x.groups["partyName"]; // const partyName = x.groups["partyName"];
const partyName = "xmas";
const token = x.groups["token"]; const token = x.groups["token"];
if (!partyName || !token) return; if (!partyName || !token) return;
return { partyName, token }; return { partyName, token };
}; };
const apiUrl = (apiEndPoint : APIEndPoint): string => { const apiUrl = (apiEndPoint : APIEndPoint): string => {
return `https://party.leafbla.de/api/${apiEndPoint.partyName}/${apiEndPoint.token}`;
let a = `https://party.leafbla.de/api/${apiEndPoint.partyName}/${apiEndPoint.token}`;
console.log(a);
return a;
}; };
export const getSelfStatusRequest = async (apiEndpoint: APIEndPoint): Promise<SelfStatus> => { export const getSelfStatusRequest = async (apiEndpoint: APIEndPoint): Promise<SelfStatus> => {

9200
yarn.lock Normal file

File diff suppressed because it is too large Load Diff