Compare commits

24 Commits
Author SHA1 Message Date
parablack f619b79b0f -> 2026 2026-10-22 16:18:20 +02:00
parablack db3a8d6b15 ihr ihr ihr3 2025-10-21 17:34:51 +02:00
parablack 88d806c0e4 ihr ihr ihr2 2025-10-21 17:34:06 +02:00
parablack 52ca7a2b0f ihr ihr ihr 2025-10-21 17:32:01 +02:00
parablack f942c73b02 we we we 2025-10-21 17:05:05 +02:00
parablack 07507d46e0 So this is Christmas And what have you done Another year over And a new one just begun 2025-10-13 18:05:16 +02:00
kai e116fee53a Bump year in Title/Description 2024-11-11 13:53:02 +01:00
kai a313e09410 Trigger CI 2024-11-09 14:28:19 +01:00
parablack e2e6799f49 update 2024-11-09 13:11:57 +01:00
parablack 41598ffa32 fix oopsie 2023-11-28 15:58:48 +01:00
parablack 3df1360c66 2k23 2023-11-28 15:33:28 +01:00
parablack 95ed928f18 logo 2022-11-21 15:19:36 +01:00
parablack 9f643fae78 Update wording 2022-11-21 14:53:17 +01:00
parablack 8262e1fa5b SS,SH,FB: text rewriting, tech fixes 2022-11-18 14:55:18 +01:00
parablack 171d710bac more info 2022-11-17 15:30:01 +01:00
Mrmaxmeier 2e1f63c5f2 more cleanup 2022-11-15 14:36:42 +01:00
Mrmaxmeier 9a227a1e47 remove workarounds 2022-11-15 14:25:40 +01:00
parablack 59901b4c92 kill die react kacke im titel 2.0 2022-11-14 23:54:46 +01:00
parablack 9285d46840 titel 2022-11-14 23:44:12 +01:00
parablack 21faf7b043 soprafixes 2022-11-14 23:31:30 +01:00
parablack c25d746ecb looks better now 2022-11-14 23:28:16 +01:00
parablack 8a5a7cc732 background maybe but not maybe 2022-11-14 22:30:20 +01:00
parablack 303aa556cf compiles locally and somewhat works locally 2022-11-14 21:20:26 +01:00
Dominic Zimmer 45f6c958fe Pipeline test 2022-11-14 16:24:09 +01:00
16 changed files with 26096 additions and 108 deletions
+16646 -46
View File
File diff suppressed because it is too large Load Diff
+5
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"
}, },
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 15 KiB

+3 -2
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

+2 -2
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",
+1 -2
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;
+94 -28
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);
}
}
+117 -16
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);
// SAFETY: If this is undefined, the contextProvider already fails
const endpoint = parseURI(window.location.href) as APIEndPoint;
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"> return <div className="App">
<header className="App-header" > <div className='container'>
<img src={logo} className="App-logo" alt="logo" /> <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 18. 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;18. 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>
}; };
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

+11
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;
}
+8 -3
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
View File
File diff suppressed because it is too large Load Diff