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
19 changed files with 26373 additions and 6170 deletions
+16880 -6084
View File
File diff suppressed because it is too large Load Diff
+15 -6
View File
@@ -3,19 +3,28 @@
"version": "0.1.0",
"private": true,
"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/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.2",
"@types/node": "^16.18.126",
"@types/react": "19.2.7",
"@types/react-dom": "19.2.3",
"react": "19.2.3",
"react-dom": "19.2.3",
"@types/node": "^16.11.64",
"@types/react": "^18.0.21",
"@types/react-dom": "^18.0.6",
"fortawesome": "^0.0.1-security",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"typescript": "^4.9.5",
"serve": "^14.2.1",
"typescript": "^4.8.4",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
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>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Party Invitation"
content="Weihnachtsfeier 2025"
/>
<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.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>Party Invitation</title>
<title>Weihnachtsfeier 2025</title>
</head>
<body>
<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",
"name": "Create React App Sample",
"short_name": "Weihnachtsfeier",
"name": "Weihnachtsfeier 2023",
"icons": [
{
"src": "favicon.ico",
+4 -15
View File
@@ -1,17 +1,15 @@
import React, { createContext, useCallback, useEffect, useMemo, useState } from 'react';
import { getPartyStatusRequest, getSelfStatusRequest, modifySelfRequest, parseURI } from './partyApi';
import { getPartyStatusRequest, getSelfStatusRequest, parseURI } from './partyApi';
import './PartyPage.css';
export const PartyContext = createContext<PartyContextType>({
party: { definitely_coming: 0, maybe_coming: 0 },
self: { token: "", name: "", coming: "yes", grammatical_gender: "m" },
update: () => {},
self: { token: "", name: "", coming: "yes", grammatical_gender: "m" }
});
export type PartyContextType = {
party: PartyStatus,
self: SelfStatus,
update: (u: UpdatableSelfStatus) => void,
}
export type PartyStatus = {
@@ -36,8 +34,6 @@ export type APIEndPoint = { partyName: string, token: string };
// Adapt this type to your desires
export type SelfStatusExtraData = {
/* Example type: */
/* plusone: string; */
};
export const PartyContextProvider: React.FC<{ children: React.ReactNode }> = (props) => {
@@ -45,8 +41,7 @@ export const PartyContextProvider: React.FC<{ children: React.ReactNode }> = (pr
const [partyContext, setPartyContext] = useState<PartyContextType>();
const apiEndpoint = useMemo<APIEndPoint>(() => {
// eslint-disable-next-line no-restricted-globals
const href = location.href;
const href = window.location.href;
const p = parseURI(href);
if (!p) return { partyName: "error", token: "" }
return p;
@@ -56,13 +51,7 @@ export const PartyContextProvider: React.FC<{ children: React.ReactNode }> = (pr
if (partyContext !== undefined) return;
const selfStatus = await getSelfStatusRequest(apiEndpoint);
const partyStatus = await getPartyStatusRequest(apiEndpoint);
const update = async (newData: UpdatableSelfStatus) => {
const reply = await modifySelfRequest(apiEndpoint, newData);
const ctx = { party: partyStatus, self: reply, update: update };
setPartyContext(ctx);
return partyStatus;
};
const ctx = { party: partyStatus, self: selfStatus, update: update };
const ctx = { party: partyStatus, self: selfStatus };
setPartyContext(ctx);
}, [apiEndpoint, partyContext]);
+106 -8
View File
@@ -1,12 +1,110 @@
.root {
margin: auto;
.loading {
height: 100vh;
width: 100vw;
background-color: black;
}
.coming-yes button[data-coming="yes"]{
background-color: green;
.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;
}
.coming-maybe button[data-coming="maybe"]{
background-color: yellow;
.container {
max-width: 1224px;
margin-left: 3ch;
margin-right: 3ch;
}
.coming-no button[data-coming="no"]{
background-color: red;
.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;
}
input[type="radio"] {
display: none;
}
input[type="radio"]+label {
font-size: larger;
cursor: pointer;
padding: 0 1em 0 1em;
border-right: 0.1em solid white;
}
input[type="radio"]+label:hover {
text-shadow: 0 0 1em white;
}
input[type="radio"]+label:last-of-type {
border-right: none;
}
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;
}
+120 -44
View File
@@ -1,52 +1,128 @@
import React, { useContext } from 'react';
import React, { ChangeEvent, useContext, useRef, useState } from 'react';
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 = () => {
const {self: guest, update: updateGuest} = 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">
<div className='container'>
<div className='hero fullheight'>
<div className='hero-outer'></div>
<h1>Hallo {dear} {name},</h1>
<p>
wir laden {isMehrzahl ? 'euch' : 'dich'} am <strong>Freitag, den 18. Dezember</strong> herzlich ein, mit uns zu feiern!
</p>
<p>
Ab <strong>19:00</strong> veranstalten wir nämlich wieder unsere alljährliche Weihnachtsparty!
</p>
<p>
Wir würden uns sehr freuen, wenn auch {isMehrzahl ? 'ihr' : 'du'}, {dear} {name}, {isMehrzahl ? 'dabei seid.' : 'dabei bist :)'}
</p>
<div className='feedback'>
<input type="radio" id="coming-yes" name="coming" value="yes" checked={comingState === "yes"} onChange={handleSelect} />
<label htmlFor='coming-yes'>Ja</label>
<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>
return <div>
<p>
<span>Hello {guest.name}</span>
</p>
<p>
Please come to the party!
</p>
<p>
Are you coming?
<div className={`coming-${guest.coming}`}>
<button data-coming={"yes"} onClick={() => updateGuest({coming: "yes"})}>
Yes
</button>
<button data-coming={"maybe"} onClick={() => updateGuest({coming: "maybe"})}>
Maybe
</button>
<button data-coming={"no"} onClick={() => updateGuest({coming: "no"})}>
No
</button>
</div>
</p>
{/*
Example usage of extraData:
<div>
<button onClick={() => {
const lastNum = parseInt(selfStatus.extra?.["plusone"] ?? "NaN");
if (isNaN(lastNum) || lastNum <= 0) return;
update({extra:{plusone: "" + (lastNum - 1)}});
}}>
-1
</button>
<button onClick={() => update({extra:{plusone: "1"}})}>
Du bringst {selfStatus.extra?.["plusone"] ?? "undefined"} Plus-Eins
</button>
<button onClick={() => {
const lastNum = parseInt(selfStatus.extra?.["plusone"] ?? "NaN");
if (isNaN(lastNum)) return;
update({extra:{plusone: "" + (lastNum + 1)}});
}}>
+1
</button>
</div>
*/}
</div>
};
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

+11 -3
View File
@@ -1,7 +1,4 @@
body {
height: 100%;
width: 100%;
display: flex;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
@@ -14,3 +11,14 @@ code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
body {
background-image: url('./background.gif');
background-size: cover;
background-position: center;
background-attachment: fixed;
height: 100vh;
padding:0;
margin:0;
}
+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

+9 -4
View File
@@ -1,16 +1,21 @@
import { APIEndPoint, PartyStatus, SelfStatus, UpdatableSelfStatus } from "./PartyContext";
export const parseURI = (uri: string): APIEndPoint | undefined => {
const x = uri.match(/https?:\/\/(?<partyName>\w+)\.(?<host>.+)\/(?<token>.+)/);
// const x = uri.match(/https?:\/\/(?<partyName>.+)\.party\.leafbla\.de\/(?<token>.+)/);
const x = uri.match(/https?:\/\/[^/]+\/(?<token>.+)/);
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"];
if (!partyName || !token) return;
return { partyName, token };
};
const apiUrl = (apiEndPoint: APIEndPoint): string => {
return `https://party.leafbla.de/api/${apiEndPoint.partyName}/${apiEndPoint.token}`;
const apiUrl = (apiEndPoint : APIEndPoint): string => {
let a = `https://party.leafbla.de/api/${apiEndPoint.partyName}/${apiEndPoint.token}`;
console.log(a);
return a;
};
export const getSelfStatusRequest = async (apiEndpoint: APIEndPoint): Promise<SelfStatus> => {
+15
View File
@@ -0,0 +1,15 @@
import { ReportHandler } from 'web-vitals';
const reportWebVitals = (onPerfEntry?: ReportHandler) => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFB(onPerfEntry);
});
}
};
export default reportWebVitals;
+5
View File
@@ -0,0 +1,5 @@
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';
+9200
View File
File diff suppressed because it is too large Load Diff