Started with web application
This commit is contained in:
parent
7beda138c5
commit
75f2365024
40 changed files with 17382 additions and 0 deletions
75
frontend/src/components/Footer.css
Normal file
75
frontend/src/components/Footer.css
Normal file
|
@ -0,0 +1,75 @@
|
|||
footer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
.footer-container {
|
||||
background-color: var(--primary);
|
||||
padding: 4rem 0 2rem 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.footer-links {
|
||||
width: 100%;
|
||||
max-width: 1080px;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.footer-link-wrapper {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.footer-link-items {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: left;
|
||||
text-align: left;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
.footer-link-items h2 {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.footer-link-items > h2 {
|
||||
color: var(--secondary);
|
||||
}
|
||||
|
||||
.footer-link-items a {
|
||||
color: var(--secondary);
|
||||
text-decoration: none;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.footer-link-items a:hover {
|
||||
border-bottom: 0.2em dotted var(--secondary);
|
||||
transition: 0.2s none;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.footer-container {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.footer-links {
|
||||
display: flex;
|
||||
flex-flow: column wrap;
|
||||
|
||||
}
|
||||
|
||||
.footer-link-wrapper {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.footer-link-items {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
36
frontend/src/components/Footer.jsx
Normal file
36
frontend/src/components/Footer.jsx
Normal file
|
@ -0,0 +1,36 @@
|
|||
import React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import "./Footer.css";
|
||||
|
||||
function Footer() {
|
||||
const EMAIL_ADRESS = process.env.REACT_APP_EMAIL_ADRESS;
|
||||
const GPG_KEY = process.env.REACT_APP_GPG_KEY
|
||||
return (
|
||||
<footer className="footer-container">
|
||||
<div className="footer-links">
|
||||
<div className="footer-link-wrapper">
|
||||
<div className="footer-link-items">
|
||||
<h2>Informationen</h2>
|
||||
<Link to="/ueber">Hintergrund</Link>
|
||||
<Link to="/manual">Wie funktioniert das?</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className="footer-link-wrapper">
|
||||
<div className="footer-link-items">
|
||||
<h2>Kontakt</h2>
|
||||
<Link to={EMAIL_ADRESS}> {EMAIL_ADRESS}</Link>
|
||||
<Link to={GPG_KEY}>GPG-Key</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className="footer-link-wrapper">
|
||||
<div className="footer-link-items">
|
||||
<h2>Rechtliches</h2>
|
||||
<Link to="/privacy">Datenschutz</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
|
||||
export default Footer;
|
0
frontend/src/components/Input.css
Normal file
0
frontend/src/components/Input.css
Normal file
59
frontend/src/components/Navbar.css
Normal file
59
frontend/src/components/Navbar.css
Normal file
|
@ -0,0 +1,59 @@
|
|||
.navbar {
|
||||
background-color: var(--primary);
|
||||
height: 4rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 1.2rem;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.navbar-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 4rem;
|
||||
max-width: 1080px;
|
||||
}
|
||||
|
||||
.navbar-logo {
|
||||
color: var(--secondary);
|
||||
justify-self: start;
|
||||
margin-left: 1.5em;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
font-size: 2rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.nav-menu {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, auto);
|
||||
grid-gap: 1rem;
|
||||
list-style: none;
|
||||
text-align: center;
|
||||
width: 60vw;
|
||||
justify-content: end;
|
||||
margin-right: 2rem;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
height: 4rem;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
color: var(--secondary);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
padding: 0.1rem 0.2rem;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.nav-links:hover {
|
||||
border-bottom: 0.2em dotted var(--secondary);
|
||||
transition: all 0.2s none;
|
||||
}
|
36
frontend/src/components/Navbar.jsx
Normal file
36
frontend/src/components/Navbar.jsx
Normal file
|
@ -0,0 +1,36 @@
|
|||
import React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import "./Navbar.css";
|
||||
|
||||
function Navbar() {
|
||||
return (
|
||||
<>
|
||||
<nav className="navbar">
|
||||
<div className="navbar-container">
|
||||
<Link to="/" className="navbar-logo">
|
||||
Briefgenerator{" "}
|
||||
</Link>
|
||||
<ul className="nav-menu">
|
||||
<li className="nav-item">
|
||||
<Link to="/" className="nav-links">
|
||||
Startseite
|
||||
</Link>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<Link to="/about" className="nav-links">
|
||||
Über
|
||||
</Link>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<Link to="/faq" className="nav-links">
|
||||
FAQ
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default Navbar;
|
0
frontend/src/components/RadioButtons.jsx
Normal file
0
frontend/src/components/RadioButtons.jsx
Normal file
13
frontend/src/components/SubmitInput.jsx
Normal file
13
frontend/src/components/SubmitInput.jsx
Normal file
|
@ -0,0 +1,13 @@
|
|||
import React from "react";
|
||||
import "./Input.css";
|
||||
|
||||
function SubmitInput(props) {
|
||||
return (
|
||||
<label className="submit-field">
|
||||
<p>{props.label}</p>
|
||||
<input type="submit" value={props.value} />
|
||||
</label>
|
||||
);
|
||||
}
|
||||
|
||||
export default SubmitInput;
|
20
frontend/src/components/TextAreaInput.jsx
Normal file
20
frontend/src/components/TextAreaInput.jsx
Normal file
|
@ -0,0 +1,20 @@
|
|||
import React from "react";
|
||||
import "../App.css";
|
||||
|
||||
function TextAreaInput(props) {
|
||||
return (
|
||||
<label className="input-field">
|
||||
<p>{props.label}</p>
|
||||
<textarea
|
||||
value={props.value}
|
||||
name={props.name}
|
||||
placeholder={props.value || "Brieftext"}
|
||||
onChange={props.onChange}
|
||||
rows={props.rows || 5}
|
||||
cols={props.cols || 30}
|
||||
/>
|
||||
</label>
|
||||
);
|
||||
}
|
||||
|
||||
export default TextAreaInput;
|
18
frontend/src/components/TextInput.jsx
Normal file
18
frontend/src/components/TextInput.jsx
Normal file
|
@ -0,0 +1,18 @@
|
|||
import React from "react";
|
||||
import "./Input.css";
|
||||
|
||||
function TextInput(props) {
|
||||
return (
|
||||
<label className="input-field">
|
||||
<p>{props.label}</p>
|
||||
<input
|
||||
type="text"
|
||||
name={props.name}
|
||||
placeholder={props.placeholder}
|
||||
onChange={props.onChange}
|
||||
/>
|
||||
</label>
|
||||
);
|
||||
}
|
||||
|
||||
export default TextInput;
|
8
frontend/src/components/pages/About.jsx
Normal file
8
frontend/src/components/pages/About.jsx
Normal file
|
@ -0,0 +1,8 @@
|
|||
import React from "react";
|
||||
import "../../App.css";
|
||||
|
||||
function About() {
|
||||
return <h1>About</h1>;
|
||||
}
|
||||
|
||||
export default About;
|
8
frontend/src/components/pages/Faq.jsx
Normal file
8
frontend/src/components/pages/Faq.jsx
Normal file
|
@ -0,0 +1,8 @@
|
|||
import React from "react";
|
||||
import "../../App.css";
|
||||
|
||||
function Faq() {
|
||||
return <h1>FAQ</h1>;
|
||||
}
|
||||
|
||||
export default Faq;
|
169
frontend/src/components/pages/Home.jsx
Normal file
169
frontend/src/components/pages/Home.jsx
Normal file
|
@ -0,0 +1,169 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import TextInput from "../TextInput";
|
||||
import SubmitInput from "../SubmitInput";
|
||||
import TextAreaInput from "../TextAreaInput";
|
||||
import "../../App.css";
|
||||
|
||||
function Home() {
|
||||
const [currentTime, setCurrentTime] = useState(0);
|
||||
|
||||
const [state, setState] = useState({
|
||||
senderGender: "",
|
||||
senderPrename: "",
|
||||
senderSurname: "",
|
||||
senderStreet: "",
|
||||
senderHouse: "",
|
||||
senderPlz: "",
|
||||
senderPlace: "",
|
||||
receiverGender: "",
|
||||
receiverPrename: "",
|
||||
receiverSurname: "",
|
||||
receiverStreet: "",
|
||||
receiverHouse: "",
|
||||
receiverPlz: "",
|
||||
receiverPlace: "",
|
||||
subject: "",
|
||||
message: "",
|
||||
});
|
||||
|
||||
const handleChange = (e) => {
|
||||
const value = e.target.value;
|
||||
setState({
|
||||
...state,
|
||||
[e.target.name]: value,
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmitClick = (e) => {
|
||||
e.preventDefault();
|
||||
let opts = {
|
||||
state: state
|
||||
};
|
||||
fetch("api/generate-letter", {
|
||||
method: "post",
|
||||
body: JSON.stringify(opts),
|
||||
}).then((response) => {
|
||||
if (response.status !== 200) {
|
||||
console.log("An error occured");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetch("/time")
|
||||
.then((res) => res.json())
|
||||
.then((data) => {
|
||||
setCurrentTime(data.time);
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="App">
|
||||
<form onSubmit={onSubmitClick}>
|
||||
<div className="letter-adresses">
|
||||
<div className="adress-sender">
|
||||
<h2>Absender</h2>
|
||||
<TextInput
|
||||
label="Geschlecht"
|
||||
name="senderGender"
|
||||
placeholder="Frau"
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<TextInput
|
||||
label="Vorname"
|
||||
name="senderPrename"
|
||||
placeholder="Max"
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<TextInput
|
||||
label="Nachname"
|
||||
name="senderSurname"
|
||||
placeholder="Muster"
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<TextInput
|
||||
label="Strasse"
|
||||
name="senderStreet"
|
||||
placeholder="Musterstrasse"
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<TextInput
|
||||
label="Hausnummer"
|
||||
name="senderHouse"
|
||||
placeholder="12"
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<TextInput
|
||||
label="PLZ"
|
||||
name="senderPlz"
|
||||
placeholder="1234"
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<TextInput
|
||||
label="Ort"
|
||||
name="senderPlace"
|
||||
placeholder="Musterhausen"
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="adress-receiver">
|
||||
<h2>Empfänger</h2>
|
||||
<TextInput
|
||||
label="Geschlecht"
|
||||
name="receiverGender"
|
||||
placeholder="Frau"
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<TextInput
|
||||
label="Vorname"
|
||||
name="receiverPrename"
|
||||
placeholder="Max"
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<TextInput
|
||||
label="Nachname"
|
||||
name="receiverSurname"
|
||||
placeholder="Muster"
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<TextInput
|
||||
label="Strasse"
|
||||
name="receiverStreet"
|
||||
placeholder="Musterstrasse"
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<TextInput
|
||||
label="Hausnummer"
|
||||
name="receiverHouse"
|
||||
placeholder="12"
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<TextInput
|
||||
label="PLZ"
|
||||
name="receiverPlz"
|
||||
placeholder="1234"
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<TextInput
|
||||
label="Ort"
|
||||
name="receiverPlace"
|
||||
placeholder="Musterhausen"
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<h2>Nachricht</h2>
|
||||
<TextInput
|
||||
label="Betreff"
|
||||
name="subject"
|
||||
placeholder="Betreff"
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<TextAreaInput name="message" onChange={handleChange} />
|
||||
<SubmitInput value="Brief generieren" />
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Home;
|
Loading…
Add table
Add a link
Reference in a new issue