Last_Dance

This commit is contained in:
2025-06-23 15:01:20 +02:00
commit 3bbc4187f6
104 changed files with 20586 additions and 0 deletions

View File

@ -0,0 +1,42 @@
import React, { useState, useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import Input from "./Input.jsx";
import Output from "./Output.jsx";
function App() {
const [seconds, setSeconds] = useState(0);
const textLength = useSelector((state)=>state.textLength);
const dispatch = useDispatch();
useEffect(() => {
const startTime = Date.now();
const id = setInterval(() => {
const timeDiffInSeconds = (Date.now()-startTime) / 1000;
const roundedSeconds = Math.floor(timeDiffInSeconds);
setSeconds(roundedSeconds);
}, 1000);
return () => clearInterval(id);
}, []);
useEffect(() => {
if (seconds > 0) {
const avgCharsPerSecond = textLength / seconds;
dispatch({
type: "setAvgCharsPerSecond",
payload: avgCharsPerSecond
});
}
}, [seconds,textLength,dispatch]); // dispatch-Abhängigkeit bleibt absichtlich als null für deine Übung
return (
<div className="App">
<Input />
<Output passedSeconds={seconds} />
</div>
);
}
export default App;

View File

@ -0,0 +1,23 @@
import React from "react";
import "./TextInput.css";
import { useDispatch } from "react-redux";
export default function Input() {
const dispatch = useDispatch();
const handleChange = (event) => {
const inputText = event.target.value;
const length = inputText.length;
dispatch({
type: "changeTextAndLength",
inputText: inputText,
inputTextLength: length,
});
};
return (
<div>
<input className="NiceInput" type="text" onChange={handleChange} />
</div>
);
}

View File

@ -0,0 +1,10 @@
.show {
background-color:rgb(255, 233, 133);
height: 50;
padding: 20px;
text-align: center;
border-collapse:collapse;
border: 1px #000 solid;
width: 100%;
}

View File

@ -0,0 +1,15 @@
import { useSelector } from "react-redux";
import "./Output.css";
export default function Output({passedSeconds}) {
const state = useSelector((state) => state);
return (
<>
<div className="show">{state.text}</div>
<div className="show">Anzahl der Zeichen: {state.textLength}</div>
<div className="show">Sekunde: {passedSeconds}</div>
<div className="show">Zeichen pro Sekunde: {state.avgCharsPerSecond.toFixed(2)}</div>
</>
);
}

View File

@ -0,0 +1,10 @@
.NiceInput {
border-radius: 16px;
padding: 10px;
margin: auto;
background-color:#AEA;
font-size: 24px;
width:90%;
}

View File

@ -0,0 +1,13 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}

View File

@ -0,0 +1,13 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { Provider } from 'react-redux';
import store from './store';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
<App />
</Provider>
);

View File

@ -0,0 +1,12 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { Provider } from 'react-redux';
import store from './store';
ReactDOM.createRoot(document.getElementById('root')).render(
<Provider store={store}>
<App />
</Provider>
);

View File

@ -0,0 +1,25 @@
const initialState = {
text: "",
textLength: 0,
avgCharsPerSecond: 0,
};
export default function appReducer(state = initialState, action) {
switch (action.type) {
case "changeTextAndLength": {
return {
...state,
text: action.inputText,
textLength: action.inputTextLength,
};
}
case "setAvgCharsPerSecond": {
return {
...state,
avgCharsPerSecond: action.payload,
};
}
default:
return state;
}
}

View File

@ -0,0 +1,6 @@
import appReducer from "./reducer.js";
import { configureStore } from "@reduxjs/toolkit";
const store = configureStore({ reducer: appReducer });
export default store;