diff --git a/README.md b/README.md index 7bb12ed..b854ec0 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,8 @@ Kolla in förberedelsesidan: [Hem](https://github.com/cygni/cygni-datatjej-react 2. Lägg till en till knapp som låter användaren räkna ned 3. Lägg till en tredje knapp som låter användaren nollställa räknaren -Exempel på resultat: - - +Exempel på resultat:
+ ### Mellan-nivå 1. Skapa ett fält som visar hur lång tid det är kvar till ett visst tillfälle t.ex. nedräkning till julafton @@ -23,17 +22,31 @@ Exempel på resultat: 3. Bryt ut fälten + input från steg 1 och 2 ovan till en egen komponent så flera nedräknare kan visas samtidigt Exempel på resultat: - + ### Advancerad nivå * Skapa en räknare likt 1 på Mellan-nivå men formatera tiden till ett human-friendly format med exempelvis `moment` * Skapa en räknare som räknar up/ned till Nybbörjare men använd `useReducer` från React för state-uppdatering + Exempel på resultat: - + ## Del 2 - Styled components +### Nybörjare +1. +2. +3. + +### Mellan-nivå +1. +2. +3. + +### Advancerad Nivå +* Skapa ett eget tema? +* ## Tillgängliga skripts diff --git a/countdown-adv.png b/countdown-adv.png new file mode 100644 index 0000000..b2f63e7 Binary files /dev/null and b/countdown-adv.png differ diff --git a/countdown.png b/countdown.png new file mode 100644 index 0000000..e6d44b1 Binary files /dev/null and b/countdown.png differ diff --git a/counter.png b/counter.png new file mode 100644 index 0000000..751f723 Binary files /dev/null and b/counter.png differ diff --git a/package.json b/package.json index ca46e66..cc77bc7 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "private": true, "dependencies": { + "moment": "^2.24.0", "react": "^16.8.4", "react-dom": "^16.8.4", "react-scripts": "2.1.8", diff --git a/src/App.css b/src/App.css new file mode 100644 index 0000000..15f8194 --- /dev/null +++ b/src/App.css @@ -0,0 +1,38 @@ +.container { + display: flex; + justify-content: center; + flex-wrap: wrap; +} + +.counter { + font-size: 8em; + flex-grow: 1; + flex: 100%; +} + +.button { + background-color: white; + border-radius: 3px; + border: 2px solid #a9a9a9; + color: #a9a9a9; + margin: 1em; + padding: 0.25em 1em; + min-width: 25px; + max-width: 50px; + flex: auto; +} + +.increase-button { + border-color: #0f93bb; + color: #0f93bb; +} + +.decrease-button { + color: #ce93db; + border-color: #ce93db; +} + +.reset-button { + flex: 100%; + max-width: 150px; +} diff --git a/src/App.js b/src/App.js index 6241858..d8004ea 100644 --- a/src/App.js +++ b/src/App.js @@ -1,24 +1,152 @@ -import React from 'react'; -import { MyApp, AppLogo, AppHeader, AppLink, Code } from './styles'; -import logo from './logo.svg'; +import React, { useState, useEffect, useReducer } from "react"; +import { ThemeProvider } from "styled-components"; +import { + AppLogo, + AppHeader, + AppLink, + Button, + Code, + Container, + Count, + MyApp, + ResetButton, + ThemedTextContainer, + ThemedDateInput, + theme +} from "./styles"; +import moment from "moment"; +import "./App.css"; +import logo from "./logo.svg"; + +const Counter = props => { + const [count, setCounter] = useState(props.initialCount || 0); + + return ( + + {count} + + + setCounter(props.initialCount || 0)} + > + Reset + + + ); +}; + +const CountdownCounter = () => { + const [goalDate, setGoalDate] = useState(new Date("2019-12-24")); + const [now, setNow] = useState(new Date()); + + useEffect(() => { + const timer = setTimeout(() => setNow(new Date()), 1000); + return () => { + clearTimeout(timer); + }; + }); + + return ( + + setGoalDate(new Date(e.target.value))} + /> + + Det är {(goalDate - now) / (3600 * 24 * 1000)} dagar till{" "} + {goalDate.toLocaleDateString()} + + + ); +}; + +const CountdownHumanFriendlyCounter = () => { + const initialDate = "2019-12-24"; + const [goalDate, setGoalDate] = useState(new moment(initialDate)); + const [now, setNow] = useState(new moment()); + + useEffect(() => { + const timer = setTimeout(() => setNow(new moment()), 1000); + return () => { + clearTimeout(timer); + }; + }); + + return ( + + setGoalDate(new moment(e.target.value))} + /> + + It's {moment.duration(goalDate.diff(now)).humanize()} to{" "} + {goalDate.format("LLLL")} + + + ); +}; + +const initialState = { count: 0 }; + +function reducer(state, action) { + switch (action.type) { + case "increment": + return { count: state.count + 1 }; + case "decrement": + return { count: state.count - 1 }; + case "reset": + return initialState; + default: + throw new Error(); + } +} + +const CounterWithReducer = () => { + const [state, dispatch] = useReducer(reducer, initialState); + return ( + + {state.count} + + + dispatch({ type: "reset" })}> + Reset + + + ); +}; export default function App() { return ( - - - -

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

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

- - Learn React + + Learn React -
-
+ + + {} + {} + {} + {} + + ); } diff --git a/src/styles.js b/src/styles.js index 58608d4..4351694 100644 --- a/src/styles.js +++ b/src/styles.js @@ -1,31 +1,33 @@ -import styled, { keyframes } from "styled-components"; +import React from "react"; +import styled, { withTheme, keyframes } from "styled-components"; export const MyApp = styled.div` * { - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", - "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; + 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; } - + text-align: center; `; export const Code = styled.code` - font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; `; export const AppHeader = styled.header` background-color: #282c34; - min-height: 100vh; + min-height: 40vh; display: flex; flex-direction: column; align-items: center; justify-content: center; font-size: calc(10px + 2vmin); color: white; + margin-bottom: 2em; `; export const AppLink = styled.a` @@ -43,7 +45,64 @@ export const rotate360 = keyframes` export const AppLogo = styled.img` animation: ${rotate360} infinite 20s linear; - height: 40vmin; + height: 20vmin; pointer-events: none; `; +export const Container = styled.div` + display: flex; + justify-content: center; + flex-wrap: wrap; +`; + +export const Count = styled.span` + color: ${props => props.color}; + font-size: 8em; + flex-grow: 1; + flex: 100%; +`; + +const IconButton = ({ className, icon, children }) => ( + +); + +export const Button = styled(IconButton)` + background-color: white; + border-radius: 3px; + border: 2px solid ${props => props.color || "#a9a9a9"}; + color: ${props => props.color || "#a9a9a9"}; + margin: 1em; + padding: 0.25em 1em; + min-width: 25px; + max-width: 50px; + flex: auto; +`; + +export const ResetButton = styled(Button)` + flex: 100%; + max-width: 150px; +`; + +const TextContainer = styled(Container)` + color: ${props => props.theme.color || "#000"}; + background-color: ${props => props.theme.bgColor || "#fff"}; +`; + +export const ThemedTextContainer = withTheme(TextContainer); + +const StyledDate = styled.input.attrs({ type: "date" })` + background-color: ${props => props.theme.bgColor || "#fff"}; + color: ${props => props.theme.dateColor || "#ff00ff"}; + outline: none; +`; + +export const ThemedDateInput = withTheme(StyledDate); + +export const theme = { + color: "#f06292", + dateColor: "#b19cd9", + bgColor: "#fff" +}; diff --git a/yarn.lock b/yarn.lock index fbd8f48..fb86e66 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5531,6 +5531,11 @@ mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@ dependencies: minimist "0.0.8" +moment@^2.24.0: + version "2.24.0" + resolved "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" + integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== + move-concurrently@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"