diff --git a/package-lock.json b/package-lock.json index 87c77dc..186cc38 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,12 +8,18 @@ "name": "swa-labor-frontend", "version": "0.1.0", "dependencies": { + "@fortawesome/fontawesome-svg-core": "^6.5.2", + "@fortawesome/free-solid-svg-icons": "^6.5.2", + "@fortawesome/react-fontawesome": "^0.2.2", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-router-dom": "^6.23.1", "react-scripts": "5.0.1", + "sass": "^1.77.2", + "scss": "^0.2.4", "web-vitals": "^2.1.4" } }, @@ -2392,6 +2398,51 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.2.tgz", + "integrity": "sha512-gBxPg3aVO6J0kpfHNILc+NMhXnqHumFxOmjYCFfOiLZfwhnnfhtsdA2hfJlDnj+8PjAs6kKQPenOTKj3Rf7zHw==", + "hasInstallScript": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.2.tgz", + "integrity": "sha512-5CdaCBGl8Rh9ohNdxeeTMxIj8oc3KNBgIeLMvJosBMdslK/UnEB8rzyDRrbKdL1kDweqBPo4GT9wvnakHWucZw==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.5.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-solid-svg-icons": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.5.2.tgz", + "integrity": "sha512-QWFZYXFE7O1Gr1dTIp+D6UcFUF0qElOnZptpi7PBUMylJh+vFmIedVe1Ir6RM1t2tEQLLSV1k7bR4o92M+uqlw==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.5.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/react-fontawesome": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.2.tgz", + "integrity": "sha512-EnkrprPNqI6SXJl//m29hpaNzOp1bruISWaOiRtkMi/xSvHJlzc2j2JAYS7egxt/EbjSNV/k6Xy0AQI6vB2+1g==", + "dependencies": { + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "@fortawesome/fontawesome-svg-core": "~1 || ~6", + "react": ">=16.3" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -3368,6 +3419,14 @@ } } }, + "node_modules/@remix-run/router": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.16.1.tgz", + "integrity": "sha512-es2g3dq6Nb07iFxGk5GuHN20RwBZOsuDQN7izWIisUcv9r+d2C5jQxqmgkdebXgReWfiyUabcki6Fg77mSNrig==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -9498,6 +9557,11 @@ "url": "https://opencollective.com/immer" } }, + "node_modules/immutable": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.6.tgz", + "integrity": "sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ==" + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -13086,6 +13150,14 @@ "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" }, + "node_modules/ometa": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/ometa/-/ometa-0.2.2.tgz", + "integrity": "sha512-LZuoK/yjU3FvrxPjUXUlZ1bavCfBPqauA7fsNdwi+AVhRdyk2IzgP3JRnevvjzQ6fKHdUw8YISshf53FmpHrng==", + "engines": { + "node": ">= 0.2.0" + } + }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -15109,6 +15181,36 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "6.23.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.23.1.tgz", + "integrity": "sha512-fzcOaRF69uvqbbM7OhvQyBTFDVrrGlsFdS3AL+1KfIBtGETibHzi3FkoTRyiDJnWNc2VxrfvR+657ROHjaNjqQ==", + "dependencies": { + "@remix-run/router": "1.16.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.23.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.23.1.tgz", + "integrity": "sha512-utP+K+aSTtEdbWpC+4gxhdlPFwuEfDKq8ZrPFU65bbRJY+l706qjR7yaidBpo3MSeA/fzwbXWbKBI6ftOnP3OQ==", + "dependencies": { + "@remix-run/router": "1.16.1", + "react-router": "6.23.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/react-scripts": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", @@ -15671,6 +15773,22 @@ "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-13.0.0.tgz", "integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==" }, + "node_modules/sass": { + "version": "1.77.2", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.2.tgz", + "integrity": "sha512-eb4GZt1C3avsX3heBNlrc7I09nyT00IUuo4eFhAbeXWU2fvA7oXI53SxODVAA+zgZCk9aunAZgO+losjR3fAwA==", + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/sass-loader": { "version": "12.6.0", "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", @@ -15749,6 +15867,17 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/scss": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/scss/-/scss-0.2.4.tgz", + "integrity": "sha512-4u8V87F+Q/upVhUmhPnB4C1R11xojkRkWjExL2v0CX2EXTg18VrKd+9JWoeyCp2VEMdSpJsyAvVU+rVjogh51A==", + "dependencies": { + "ometa": "0.2.2" + }, + "engines": { + "node": ">= 0.2.0" + } + }, "node_modules/select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", diff --git a/package.json b/package.json index 66546a0..fbf78ca 100644 --- a/package.json +++ b/package.json @@ -3,12 +3,18 @@ "version": "0.1.0", "private": true, "dependencies": { + "@fortawesome/fontawesome-svg-core": "^6.5.2", + "@fortawesome/free-solid-svg-icons": "^6.5.2", + "@fortawesome/react-fontawesome": "^0.2.2", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-router-dom": "^6.23.1", "react-scripts": "5.0.1", + "sass": "^1.77.2", + "scss": "^0.2.4", "web-vitals": "^2.1.4" }, "scripts": { diff --git a/public/logo192.png b/public/logo192.png deleted file mode 100644 index fc44b0a..0000000 Binary files a/public/logo192.png and /dev/null differ diff --git a/public/logo512.png b/public/logo512.png deleted file mode 100644 index a4e47a6..0000000 Binary files a/public/logo512.png and /dev/null differ diff --git a/src/App.css b/src/App.css deleted file mode 100644 index 74b5e05..0000000 --- a/src/App.css +++ /dev/null @@ -1,38 +0,0 @@ -.App { - text-align: center; -} - -.App-logo { - height: 40vmin; - pointer-events: none; -} - -@media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } -} - -.App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; -} - -.App-link { - color: #61dafb; -} - -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} diff --git a/src/App.js b/src/App.js index 3784575..9d9aa1c 100644 --- a/src/App.js +++ b/src/App.js @@ -1,25 +1,18 @@ -import logo from './logo.svg'; -import './App.css'; +import React, { useState } from 'react'; +import { BrowserRouter as Router, Route, Routes } from 'react-router-dom'; +import Home from './components/Home'; +import PostDetail from './components/PostDetail'; function App() { - return ( -
-
- logo -

- Edit src/App.js and save to reload. -

- - Learn React - -
-
- ); + return ( + + + } /> + } /> + + + ); } + export default App; diff --git a/src/App.scss b/src/App.scss new file mode 100644 index 0000000..0c38b59 --- /dev/null +++ b/src/App.scss @@ -0,0 +1,33 @@ +body { + font-family: Arial, sans-serif; +} + +.vote { + margin-left: 10px; + display: inline-block; + font-size: 20px; + color: #999; +} + +.vote:hover { + cursor: pointer; +} + +.container { + max-width: 600px; + margin: 0 auto; +} + +.post { + background-color: #fff; + border: 1px solid #ddd; + padding: 10px; + margin-bottom: 20px; +} + +.comment { + background-color: #fff; + border: 1px solid #ddd; + padding: 10px; + margin-bottom: 20px; +} diff --git a/src/App.test.js b/src/App.test.js deleted file mode 100644 index 1f03afe..0000000 --- a/src/App.test.js +++ /dev/null @@ -1,8 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import App from './App'; - -test('renders learn react link', () => { - render(); - const linkElement = screen.getByText(/learn react/i); - expect(linkElement).toBeInTheDocument(); -}); diff --git a/src/components/Home.js b/src/components/Home.js new file mode 100644 index 0000000..cf26b80 --- /dev/null +++ b/src/components/Home.js @@ -0,0 +1,38 @@ +import React, { useState } from 'react'; +import WritePost from './WritePost'; +import '../App.scss'; +import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; +import {faCaretDown, faCaretUp} from "@fortawesome/free-solid-svg-icons"; // Importiere das Styling + +function Home() { + const [posts, setPosts] = useState([]); + + const handlePost = function(content) { + const newPost = { + id: posts.length + 1, + content: content, + upvotes: 0, + downvotes: 0 + }; + setPosts([...posts, newPost]); + }; + + return ( +
{/* Verwende die Klasse container */} +

Jodel Clone

+ + {posts.map(post => ( +
{/* Verwende die Klasse post */} +

{post.content}

+
+ console.log("upvote")} /> + console.log("downvote")} /> + {post.upvotes - post.downvotes} +
+
+ ))} +
+ ); +} + +export default Home; \ No newline at end of file diff --git a/src/components/Post.js b/src/components/Post.js new file mode 100644 index 0000000..4e992bf --- /dev/null +++ b/src/components/Post.js @@ -0,0 +1,34 @@ +import React, { useState } from 'react'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faCaretUp, faCaretDown } from '@fortawesome/free-solid-svg-icons'; + +function Post({ post }) { + const [upvotes, setUpvotes] = useState(post.upvotes); + const [downvotes, setDownvotes] = useState(post.downvotes); + + const handleUpvote = () => { + // Logic to handle upvote + setUpvotes(upvotes + 1); + }; + + const handleDownvote = () => { + // Logic to handle downvote + setDownvotes(downvotes + 1); + }; + + return ( +
+

{post.content}

+
+ + {upvotes} +
+
+ + {downvotes} +
+
+ ); +} + +export default Post; \ No newline at end of file diff --git a/src/components/PostDetail.js b/src/components/PostDetail.js new file mode 100644 index 0000000..72280d8 --- /dev/null +++ b/src/components/PostDetail.js @@ -0,0 +1,47 @@ +import React, { useState } from 'react'; +import WriteComment from './WriteComment'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faCaretUp, faCaretDown } from '@fortawesome/free-solid-svg-icons'; +import '../App.scss'; // Importiere das Styling + +function PostDetail() { + const [comments, setComments] = useState([]); + + const handleComment = function(comment) { + setComments([...comments, comment]); + }; + + const calculateVotes = function(comment) { + return comment.upvotes - comment.downvotes; + }; + + const handleVote = function(index, type) { + const updatedComments = [...comments]; + if (type === 'upvote') { + updatedComments[index].upvotes++; + } else if (type === 'downvote') { + updatedComments[index].downvotes++; + } + setComments(updatedComments); + }; + + return ( +
{/* Verwende die Klasse container */} +

Post Detail

+

Comments

+ {comments.map((comment, index) => ( +
{/* Verwende die Klasse comment */} +

{comment.content}

+
+ handleVote(index, 'upvote')} /> + handleVote(index, 'downvote')} /> + {calculateVotes(comment)} +
+
+ ))} + +
+ ); +} + +export default PostDetail; diff --git a/src/components/WriteComment.js b/src/components/WriteComment.js new file mode 100644 index 0000000..8d9b1b3 --- /dev/null +++ b/src/components/WriteComment.js @@ -0,0 +1,34 @@ +import React, { useState } from 'react'; + +function WriteComment({ onComment }) { + const [content, setContent] = useState(''); + + const handleChange = function(e) { + setContent(e.target.value); + }; + + const handleSubmit = function(e) { + e.preventDefault(); + onComment({ content: content, upvotes: 0, downvotes: 0 }); + setContent(''); + }; + + return ( +
+

Write a Comment

+
+