initial commit with assignment answer
This commit is contained in:
parent
c931627492
commit
2a6f2ef35a
42
src/1/index.tsx
Normal file
42
src/1/index.tsx
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import { FunctionComponent, useState } from "react";
|
||||||
|
|
||||||
|
function ListItemComponent(props: any) {
|
||||||
|
return <li>{props.itemNumber}</li>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ListComponent(props: any) {
|
||||||
|
return <div>
|
||||||
|
<ul>
|
||||||
|
{props.items.map((item: string) => <ListItemComponent itemNumber={item} />)}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
const Task1: FunctionComponent = () => {
|
||||||
|
const [items, setItems] = useState([
|
||||||
|
"Item 1",
|
||||||
|
"Item 2",
|
||||||
|
"Item 3",
|
||||||
|
"Item 4",
|
||||||
|
"Item 5",
|
||||||
|
]);
|
||||||
|
|
||||||
|
return <div>
|
||||||
|
#List goes here#
|
||||||
|
|
||||||
|
#Iterating over list
|
||||||
|
<ul>
|
||||||
|
{items.map((item) => <li>{item}</li>)}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
#Iterating over list but using a unique component for the items
|
||||||
|
<ul>
|
||||||
|
{items.map((item) => <ListItemComponent itemNumber={item} />)}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
#Containing the entire list inside a component
|
||||||
|
<ListComponent items={items}/>
|
||||||
|
</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Task1;
|
25
src/2/index.tsx
Normal file
25
src/2/index.tsx
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import { FunctionComponent, useState } from "react";
|
||||||
|
|
||||||
|
function LiveInputComponent(props: any) {
|
||||||
|
return <input onChange={e => props.setValue(e.target.value)} />
|
||||||
|
}
|
||||||
|
|
||||||
|
function ValueDisplayer(props: any) {
|
||||||
|
return <p>{props.value}</p>
|
||||||
|
}
|
||||||
|
|
||||||
|
const Task2: FunctionComponent = () => {
|
||||||
|
const [value, setValue] = useState("");
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<label>Controlled Input: </label>
|
||||||
|
<LiveInputComponent setValue={setValue}/>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<p>#Show Input value here#</p>
|
||||||
|
<ValueDisplayer value={value}/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Task2;
|
48
src/3/index.tsx
Normal file
48
src/3/index.tsx
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
import { FunctionComponent, useState } from "react";
|
||||||
|
|
||||||
|
function LiveInputComponent(props: any) {
|
||||||
|
return <input onChange={e => props.setValue(e.target.value)} />
|
||||||
|
}
|
||||||
|
|
||||||
|
function ListItemComponent(props: any) {
|
||||||
|
return <li>{props.itemNumber}</li>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ListComponent(props: any) {
|
||||||
|
return <ul>
|
||||||
|
{mapItems(filterItems(props.items, props.filter))}
|
||||||
|
</ul>
|
||||||
|
}
|
||||||
|
|
||||||
|
const filterDown = (filter: string) => (word: string) => String(word).includes(filter);
|
||||||
|
const filterItems = (items: any, filter: any) => items.filter(filterDown(filter));
|
||||||
|
const mapItems = (filteredItems: any) => filteredItems.map((item: string) => <ListItemComponent itemNumber={item} />);
|
||||||
|
|
||||||
|
|
||||||
|
const Task3: FunctionComponent = () => {
|
||||||
|
const [inputValue, setInputValue] = useState("");
|
||||||
|
const [items, setItems] = useState([
|
||||||
|
"atem",
|
||||||
|
"btem",
|
||||||
|
"bbtem",
|
||||||
|
"dbtem",
|
||||||
|
"etem",
|
||||||
|
"ftm",
|
||||||
|
"gtem",
|
||||||
|
"hm",
|
||||||
|
"tm",
|
||||||
|
"item",
|
||||||
|
]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<label>Search Input: </label>
|
||||||
|
<LiveInputComponent setValue={setInputValue}/>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<ListComponent items={items} filter={inputValue}/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Task3;
|
181
src/4/index.scss
Normal file
181
src/4/index.scss
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
/* DO NOT CHANGE THIS ROOT CLASS NAME*/
|
||||||
|
#task-5 {
|
||||||
|
/* Styles goes here */
|
||||||
|
padding: 10px 10px;
|
||||||
|
background: #efefef;
|
||||||
|
}
|
||||||
|
|
||||||
|
#form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#section {
|
||||||
|
width: 300px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
#button-section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: end;
|
||||||
|
}
|
||||||
|
|
||||||
|
#section {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#input {
|
||||||
|
|
||||||
|
border: none;
|
||||||
|
outline:none;
|
||||||
|
background: none;
|
||||||
|
font-size: 18px;
|
||||||
|
color: #555;
|
||||||
|
padding:5px 10px 5px 5px;
|
||||||
|
border-radius: .5rem;
|
||||||
|
transition: .2s ease-in-out;
|
||||||
|
box-shadow: inset 2px 2px 2px #cbced1,
|
||||||
|
inset -2px -2px 2px #ffffff;
|
||||||
|
&:hover {
|
||||||
|
box-shadow: inset 2px 2px 2px #cbced1,
|
||||||
|
inset -2px -2px 2px #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #ffe5a5;
|
||||||
|
box-shadow: inset 2px 2px 2px #755f3799,
|
||||||
|
inset -2px -2px 2px #ffefd3b8;
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
box-shadow: inset 2px 2px 2px #cbced1,
|
||||||
|
inset -2px -2px 2px #ffffff;
|
||||||
|
}
|
||||||
|
&:focus {
|
||||||
|
background: #e5f9c4;
|
||||||
|
border: solid 2px black;
|
||||||
|
box-shadow: inset 2px 2px 2px #60753fb3, inset -2px -2px 2px #eaf6d7ba;
|
||||||
|
}
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#email-label {
|
||||||
|
color: #444;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 700;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#password-label {
|
||||||
|
color: #444;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 700;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#button {
|
||||||
|
padding: 10px 20px;
|
||||||
|
background: #efefef;
|
||||||
|
border: none;
|
||||||
|
border-radius: .5rem;
|
||||||
|
color: #444;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: .2rem;
|
||||||
|
text-align: center;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: .2s ease-in-out;
|
||||||
|
box-shadow: 2px 2px 2px #cbced1,
|
||||||
|
-2px -2px 2px #ffffff;
|
||||||
|
&:hover {
|
||||||
|
background: #ffe5a5;
|
||||||
|
box-shadow: 2px 2px 2px #755f3799, -2px -2px 2px #ffefd3b8;
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
background: #efefef;
|
||||||
|
box-shadow: inset 2px 2px 2px #cbced1,
|
||||||
|
inset -2px -2px 2px #ffffff;
|
||||||
|
}
|
||||||
|
&:focus {
|
||||||
|
background: #e5f9c4;
|
||||||
|
border: solid 2px black;
|
||||||
|
box-shadow: 2px 2px 2px #60753fb3, -2px -2px 2px rgb(253 255 250);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#input {
|
||||||
|
|
||||||
|
border: none;
|
||||||
|
outline:none;
|
||||||
|
background: none;
|
||||||
|
font-size: 18px;
|
||||||
|
color: #555;
|
||||||
|
padding:5px 10px 5px 5px;
|
||||||
|
border-radius: .5rem;
|
||||||
|
transition: .2s ease-in-out;
|
||||||
|
box-shadow: inset 2px 2px 2px #cbced1,
|
||||||
|
inset -2px -2px 2px #ffffff;
|
||||||
|
&:hover {
|
||||||
|
box-shadow: inset 2px 2px 2px #cbced1,
|
||||||
|
inset -2px -2px 2px #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #ffe5a5;
|
||||||
|
box-shadow: inset 2px 2px 2px #755f3799,
|
||||||
|
inset -2px -2px 2px #ffefd3b8;
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
box-shadow: inset 2px 2px 2px #cbced1,
|
||||||
|
inset -2px -2px 2px #ffffff;
|
||||||
|
}
|
||||||
|
&:focus {
|
||||||
|
box-shadow: inset 2px 2px 2px #cbced1,
|
||||||
|
inset -2px -2px 2px #ffffff;
|
||||||
|
}
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#email-label {
|
||||||
|
color: #444;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 700;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#password-label {
|
||||||
|
color: #444;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 700;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#button {
|
||||||
|
padding: 10px 20px;
|
||||||
|
background: #efefef;
|
||||||
|
border: none;
|
||||||
|
border-radius: .5rem;
|
||||||
|
color: #444;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: .2rem;
|
||||||
|
text-align: center;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: .2s ease-in-out;
|
||||||
|
box-shadow: 2px 2px 2px #cbced1,
|
||||||
|
-2px -2px 2px #ffffff;
|
||||||
|
&:hover {
|
||||||
|
background: #ffe5a5;
|
||||||
|
box-shadow: 2px 2px 2px #755f3799, -2px -2px 2px #ffefd3b8;
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
background: #efefef;
|
||||||
|
box-shadow: inset 2px 2px 2px #cbced1,
|
||||||
|
inset -2px -2px 2px #ffffff;
|
||||||
|
}
|
||||||
|
}
|
46
src/4/index.tsx
Normal file
46
src/4/index.tsx
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
// Style
|
||||||
|
import { FunctionComponent, useState } from "react";
|
||||||
|
import "./index.scss";
|
||||||
|
|
||||||
|
const Task4: FunctionComponent = () => {
|
||||||
|
const [email, setEmail] = useState("");
|
||||||
|
const [password, setPassword] = useState("");
|
||||||
|
|
||||||
|
const onSubmit = () => {
|
||||||
|
// If you want to do something with form submit
|
||||||
|
|
||||||
|
alert(`Email: ${email} \nPassword: ${password}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div id="task-4">
|
||||||
|
<form id="form" onSubmit={onSubmit}>
|
||||||
|
<div id="section">
|
||||||
|
<label id="email-label">Email</label>
|
||||||
|
<input
|
||||||
|
id="input"
|
||||||
|
name="email"
|
||||||
|
onChange={(event) => setEmail(event.currentTarget.value)}
|
||||||
|
placeholder="my@email.com"
|
||||||
|
value={email}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div id="section">
|
||||||
|
<label id="password-label">Password</label>
|
||||||
|
<input
|
||||||
|
id="input"
|
||||||
|
name="password"
|
||||||
|
onChange={(event) => setPassword(event.currentTarget.value)}
|
||||||
|
placeholder="myPassword123"
|
||||||
|
value={password}
|
||||||
|
/>
|
||||||
|
<div id="button-section">
|
||||||
|
<button id="button">Login</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Task4;
|
7
src/4/simple_css.scss
Normal file
7
src/4/simple_css.scss
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
/* DO NOT CHANGE THIS ROOT CLASS NAME*/
|
||||||
|
#task-5 {
|
||||||
|
/* Styles goes here */
|
||||||
|
padding: 10px 10px;
|
||||||
|
background: #efefef;
|
||||||
|
}
|
||||||
|
|
11
src/5/components/Input.tsx
Normal file
11
src/5/components/Input.tsx
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import { FunctionComponent } from "react";
|
||||||
|
|
||||||
|
interface InputProps {
|
||||||
|
setValue(item: string): any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Input: FunctionComponent<InputProps> = (props) => {
|
||||||
|
return <input onChange={e => props.setValue(e.target.value)} />
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Input;
|
11
src/5/components/Item.tsx
Normal file
11
src/5/components/Item.tsx
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import { FunctionComponent } from "react";
|
||||||
|
|
||||||
|
interface ItemProps {
|
||||||
|
itemName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Item: FunctionComponent<ItemProps> = (props) => {
|
||||||
|
return <li>{props.itemName}</li>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Item;
|
22
src/5/components/List.tsx
Normal file
22
src/5/components/List.tsx
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import { FunctionComponent } from "react";
|
||||||
|
|
||||||
|
// Components
|
||||||
|
import Item from "./Item";
|
||||||
|
|
||||||
|
interface ListProps {
|
||||||
|
items: string[];
|
||||||
|
filter: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const filterDown = (filter: string) => (word: string) => String(word).includes(filter);
|
||||||
|
const filterItems = (items: any, filter: any) => items.filter(filterDown(filter));
|
||||||
|
const mapItems = (filteredItems: any) => filteredItems.map((item: string) => <Item itemName={item} />);
|
||||||
|
|
||||||
|
|
||||||
|
const List: FunctionComponent<ListProps> = (props) => {
|
||||||
|
return <ul id="list">
|
||||||
|
{mapItems(filterItems(props.items, props.filter))}
|
||||||
|
</ul>
|
||||||
|
};
|
||||||
|
|
||||||
|
export default List;
|
31
src/5/index.tsx
Normal file
31
src/5/index.tsx
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import { FunctionComponent, useState } from "react";
|
||||||
|
|
||||||
|
// Components
|
||||||
|
import Input from "./components/Input";
|
||||||
|
import List from "./components/List";
|
||||||
|
|
||||||
|
const Task5: FunctionComponent = () => {
|
||||||
|
const [inputValue, setInputValue] = useState("");
|
||||||
|
const [items, setItems] = useState([
|
||||||
|
"atem",
|
||||||
|
"btem",
|
||||||
|
"bbtem",
|
||||||
|
"dbtem",
|
||||||
|
"etem",
|
||||||
|
"ftm",
|
||||||
|
"gtem",
|
||||||
|
"hm",
|
||||||
|
"tm",
|
||||||
|
"item",
|
||||||
|
]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Input setValue={setInputValue}/>
|
||||||
|
<br />
|
||||||
|
<List items={items} filter={inputValue}/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Task5;
|
23
src/6/components/AddItemButton.tsx
Normal file
23
src/6/components/AddItemButton.tsx
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import { FunctionComponent } from "react";
|
||||||
|
|
||||||
|
interface AddButtonProps {
|
||||||
|
items: any[];
|
||||||
|
nextKey: number;
|
||||||
|
setNextKey: any;
|
||||||
|
setItems(items: any[]): any;
|
||||||
|
newValue: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addItem(items: any, nextKey: number, setNextKey: any, setItems: any, newValue: string){
|
||||||
|
const newList = items.concat({key: nextKey, done: false, value: newValue});
|
||||||
|
setNextKey(nextKey + 1);
|
||||||
|
setItems(newList);
|
||||||
|
}
|
||||||
|
|
||||||
|
const AddItemButton: FunctionComponent<AddButtonProps> = (props) => {
|
||||||
|
return <div id="add-button">
|
||||||
|
<button id="button" onClick={() => addItem(props.items, props.nextKey, props.setNextKey, props.setItems, props.newValue)}>Add</button>
|
||||||
|
</div>
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AddItemButton;
|
13
src/6/components/AddItemInput.tsx
Normal file
13
src/6/components/AddItemInput.tsx
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import { FunctionComponent } from "react";
|
||||||
|
|
||||||
|
interface InputProps {
|
||||||
|
setValue(item: string): any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Input: FunctionComponent<InputProps> = (props) => {
|
||||||
|
return <div id="input-section">
|
||||||
|
<input id="input" placeholder="New todo..." onChange={e => props.setValue(e.target.value)} />
|
||||||
|
</div>
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Input;
|
11
src/6/components/Input.tsx
Normal file
11
src/6/components/Input.tsx
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import { FunctionComponent } from "react";
|
||||||
|
|
||||||
|
interface InputProps {
|
||||||
|
setValue(item: string): any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Input: FunctionComponent<InputProps> = (props) => {
|
||||||
|
return <input id="input" placeholder="Filter items..." onChange={e => props.setValue(e.target.value)} />
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Input;
|
28
src/6/components/Item.tsx
Normal file
28
src/6/components/Item.tsx
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import { FunctionComponent } from "react";
|
||||||
|
|
||||||
|
interface ItemProps {
|
||||||
|
item: any;
|
||||||
|
items: any[];
|
||||||
|
setItems: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleDone (items: any, setItems: any, key: number) {
|
||||||
|
setItems((items: any) => items.map( (item: any, i: number) => {
|
||||||
|
const doneStatus = item.key === key ? !item.done : item.done
|
||||||
|
return {key: item.key ,done: doneStatus, value: item.value}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
const Item: FunctionComponent<ItemProps> = (props) => {
|
||||||
|
return <div id="list-content">
|
||||||
|
<div id="item-text">
|
||||||
|
{props.item.done ? "" : props.item.value}
|
||||||
|
</div>
|
||||||
|
<button id="button" onClick={ () => toggleDone(props.items, props.setItems, props.item.key) }><-></button>
|
||||||
|
<div id="item-text">
|
||||||
|
{props.item.done ? props.item.value : ""}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Item;
|
33
src/6/components/List.tsx
Normal file
33
src/6/components/List.tsx
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import { FunctionComponent } from "react";
|
||||||
|
|
||||||
|
// Components
|
||||||
|
import Item from "./Item";
|
||||||
|
|
||||||
|
interface ListProps {
|
||||||
|
items: any[];
|
||||||
|
filter: string;
|
||||||
|
setItems: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeById(oldItems: any, setItems: any, key: number) {
|
||||||
|
setItems ((oldItems: any) => { return oldItems.filter((item: any) => item.key !== key) })
|
||||||
|
}
|
||||||
|
|
||||||
|
const filterDown = (filter: string) => (word: any) => String(word.value).includes(filter);
|
||||||
|
const filterItems = (items: any, filter: any) => items.filter(filterDown(filter));
|
||||||
|
const mapItems = (filteredItems: any, setItems: any) => filteredItems.map((item: any, index: number) => {
|
||||||
|
let listId = index % 2 == 0 ? "list-element" : "list-element-uneven";
|
||||||
|
return <li key={item.key} id={listId}>
|
||||||
|
<button id="button" onClick={ () => removeById(filteredItems, setItems, item.key) }>Remove</button>
|
||||||
|
<Item item={item} items={filteredItems} setItems={setItems} />
|
||||||
|
</li>
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const List: FunctionComponent<ListProps> = (props) => {
|
||||||
|
return <ul id="list">
|
||||||
|
{mapItems(filterItems(props.items, props.filter), props.setItems)}
|
||||||
|
</ul>
|
||||||
|
};
|
||||||
|
|
||||||
|
export default List;
|
143
src/6/index.scss
Normal file
143
src/6/index.scss
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
/* DO NOT CHANGE THIS ROOT CLASS NAME*/
|
||||||
|
#task-6 {
|
||||||
|
background: #efefef;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#empty {
|
||||||
|
width: 90px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#input-section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
#warning {
|
||||||
|
margin-left: 20px;
|
||||||
|
margin-right: 20px;
|
||||||
|
background: yellow;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: -10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#list {
|
||||||
|
display:flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#top-section {
|
||||||
|
display:flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
text-align: center;
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
#list-element {
|
||||||
|
height: 40px;
|
||||||
|
display:flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#list-element-uneven {
|
||||||
|
height: 40px;
|
||||||
|
background: #e1e1e1;
|
||||||
|
display:flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#item-text {
|
||||||
|
width: 300px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#list-content {
|
||||||
|
display:flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items:center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#button {
|
||||||
|
width: 80px;
|
||||||
|
padding: 5px 10px;
|
||||||
|
margin: 5px;
|
||||||
|
background: #efefef;
|
||||||
|
border: none;
|
||||||
|
color: #444;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: .2rem;
|
||||||
|
text-align: center;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: .2s ease-in-out;
|
||||||
|
box-shadow: 2px 2px 2px #cbced1,
|
||||||
|
-2px -2px 2px #ffffff;
|
||||||
|
&:hover {
|
||||||
|
background: #ffe5a5;
|
||||||
|
box-shadow: 2px 2px 2px #755f3799, -2px -2px 2px #ffefd3b8;
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
background: #efefef;
|
||||||
|
box-shadow: inset 2px 2px 2px #cbced1,
|
||||||
|
inset -2px -2px 2px #ffffff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#input {
|
||||||
|
margin: 20px;
|
||||||
|
|
||||||
|
border: none;
|
||||||
|
outline:none;
|
||||||
|
background: none;
|
||||||
|
font-size: 18px;
|
||||||
|
color: #555;
|
||||||
|
padding:5px 10px 5px 5px;
|
||||||
|
border-radius: .5rem;
|
||||||
|
transition: .2s ease-in-out;
|
||||||
|
box-shadow: inset 2px 2px 2px #cbced1,
|
||||||
|
inset -2px -2px 2px #ffffff;
|
||||||
|
&:hover {
|
||||||
|
box-shadow: inset 2px 2px 2px #cbced1,
|
||||||
|
inset -2px -2px 2px #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #ffe5a5;
|
||||||
|
box-shadow: inset 2px 2px 2px #755f3799,
|
||||||
|
inset -2px -2px 2px #ffefd3b8;
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
box-shadow: inset 2px 2px 2px #cbced1,
|
||||||
|
inset -2px -2px 2px #ffffff;
|
||||||
|
}
|
||||||
|
&:focus {
|
||||||
|
box-shadow: inset 2px 2px 2px #cbced1,
|
||||||
|
inset -2px -2px 2px #ffffff;
|
||||||
|
}
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#add-button {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: end;
|
||||||
|
margin-right:15px;
|
||||||
|
}
|
77
src/6/index.tsx
Normal file
77
src/6/index.tsx
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
import { FunctionComponent, useState } from "react";
|
||||||
|
|
||||||
|
import Input from "./components/Input";
|
||||||
|
import AddItemInput from "./components/AddItemInput";
|
||||||
|
import List from "./components/List";
|
||||||
|
import AddItemButton from "./components/AddItemButton";
|
||||||
|
|
||||||
|
import "./index.scss";
|
||||||
|
|
||||||
|
const Empty: FunctionComponent<any> = (props) => {
|
||||||
|
return <div id="empty"/>
|
||||||
|
};
|
||||||
|
|
||||||
|
const initialItems = [{
|
||||||
|
key: 0,
|
||||||
|
done: false,
|
||||||
|
value: "Get kids",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 1,
|
||||||
|
done: false,
|
||||||
|
value: "Do Uniwise assignments",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 2,
|
||||||
|
done: false,
|
||||||
|
value: "Get rich",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 3,
|
||||||
|
done: false,
|
||||||
|
value: "Die trying",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 4,
|
||||||
|
done: false,
|
||||||
|
value: "Vacuum",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 5,
|
||||||
|
done: false,
|
||||||
|
value: "Clean dishes",
|
||||||
|
},]
|
||||||
|
|
||||||
|
const NameBar: FunctionComponent<any> = (props) => {
|
||||||
|
return <div id="top-section">
|
||||||
|
<Empty/>
|
||||||
|
<h3>
|
||||||
|
Pending
|
||||||
|
</h3>
|
||||||
|
<Empty/>
|
||||||
|
<h3>
|
||||||
|
Done
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
};
|
||||||
|
|
||||||
|
const Task6: React.FunctionComponent = () => {
|
||||||
|
const [filterValue, setFilterValue] = useState("");
|
||||||
|
const [newValue, setNewValue] = useState("");
|
||||||
|
const [items, setItems] = useState(initialItems);
|
||||||
|
const [nextKey, setNextKey] = useState(6);
|
||||||
|
|
||||||
|
return <div id="task-6">
|
||||||
|
<div id="app">
|
||||||
|
<Input setValue={setFilterValue}/>
|
||||||
|
<AddItemInput setValue={setNewValue} />
|
||||||
|
<AddItemButton items={items} nextKey={nextKey} setNextKey={setNextKey} setItems={setItems} newValue={newValue}/>
|
||||||
|
<NameBar />
|
||||||
|
<div id="bottom-section">
|
||||||
|
<List items={items} filter={filterValue} setItems={setItems}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Task6;
|
117
src/6/simple_css.scss
Normal file
117
src/6/simple_css.scss
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
/* DO NOT CHANGE THIS ROOT CLASS NAME*/
|
||||||
|
#task-6 {
|
||||||
|
background: #efefef;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#empty {
|
||||||
|
width: 90px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#input-section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
#warning {
|
||||||
|
margin-left: 20px;
|
||||||
|
margin-right: 20px;
|
||||||
|
background: yellow;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: -10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#list {
|
||||||
|
display:flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#top-section {
|
||||||
|
display:flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
text-align: center;
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
#list-element {
|
||||||
|
height: 40px;
|
||||||
|
display:flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#list-element-uneven {
|
||||||
|
height: 40px;
|
||||||
|
background: #e1e1e1;
|
||||||
|
display:flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#item-text {
|
||||||
|
width: 300px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#list-content {
|
||||||
|
display:flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items:center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#button {
|
||||||
|
width: 80px;
|
||||||
|
padding: 5px 10px;
|
||||||
|
margin: 5px;
|
||||||
|
background: #efefef;
|
||||||
|
color: #444;
|
||||||
|
text-align: center;
|
||||||
|
transition: .2s ease-in-out;
|
||||||
|
&:hover {
|
||||||
|
background: #ffe5a5;
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
background: #efefef;
|
||||||
|
}
|
||||||
|
&:focus {
|
||||||
|
background: #e5f9c4;
|
||||||
|
border: solid 2px black;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#input {
|
||||||
|
margin: 20px;
|
||||||
|
color: #555;
|
||||||
|
padding:5px 10px 5px 5px;
|
||||||
|
transition: .2s ease-in-out;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #ffe5a5;
|
||||||
|
}
|
||||||
|
&:focus {
|
||||||
|
background: #e5f9c4;
|
||||||
|
}
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#add-button {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: end;
|
||||||
|
margin-right:15px;
|
||||||
|
}
|
61
src/Intro/index.tsx
Normal file
61
src/Intro/index.tsx
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
You don't need to change anything in here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { FunctionComponent } from "react";
|
||||||
|
|
||||||
|
const Intro: FunctionComponent = () => {
|
||||||
|
return (
|
||||||
|
<div style={{ textAlign: "left"}}>
|
||||||
|
<h1>Welcome</h1>
|
||||||
|
<p>
|
||||||
|
If you are reading this, you are most likely starting an application
|
||||||
|
process at Uniwise. In this assignment you will have the opportunity to
|
||||||
|
show your skills as well as challenge your competencies.
|
||||||
|
</p>
|
||||||
|
<h2>Intro</h2>
|
||||||
|
<p>
|
||||||
|
Before you get started with the task read the following information.
|
||||||
|
</p>
|
||||||
|
<h3>Course of action</h3>
|
||||||
|
<p>
|
||||||
|
The task consists of small simple tasks that increase in complexity and
|
||||||
|
difficulty as you solve them. It is allowed to use code from third party
|
||||||
|
libraries and npm packages. If you find that a given task is too
|
||||||
|
difficult or too easy, feel free to skip to the next task. Also feel
|
||||||
|
free to leave comments with relevant info and to elaborate as much as
|
||||||
|
you like on a given task. The goal is for you to both show your current
|
||||||
|
skills and to show your capabilities in solving problems that are new to
|
||||||
|
you.
|
||||||
|
</p>
|
||||||
|
<h3>Technologies</h3>
|
||||||
|
<p>
|
||||||
|
This test is based on ReactJS with Typescript. It would be advantageous
|
||||||
|
if you have or gain knowledge of those before the test. Also SCSS is
|
||||||
|
used for styling.
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="https://reactjs.org/">ReactJs</a> - The framework
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="https://www.typescriptlang.org/">Typescript</a> - Typed
|
||||||
|
javascript
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="https://sass-lang.com/">
|
||||||
|
SCSS - CSS with superpowers
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<h3>Get started</h3>
|
||||||
|
<p>
|
||||||
|
When you are ready to start you can select a task in the top of the
|
||||||
|
screen. The associated code wil be found in the corresponding folder
|
||||||
|
inside the src folder.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Intro;
|
70
src/index.scss
Normal file
70
src/index.scss
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
You don't need to change anything in here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-family: "Open Sans", sans-serif;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5 {
|
||||||
|
font-weight: 600;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-top: 0;
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-description {
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1.5;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-container {
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 3px dashed #ddd;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
max-width: 960px;
|
||||||
|
margin: auto;
|
||||||
|
padding: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav.menu {
|
||||||
|
background-color: #404040;
|
||||||
|
color: #fff;
|
||||||
|
padding: 16px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
a {
|
||||||
|
display: inline-block;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #777;
|
||||||
|
color: #fff;
|
||||||
|
padding: 8px 16px;
|
||||||
|
margin-right: 16px;
|
||||||
|
transition: background-color 150ms ease;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background-color: #86b111;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
212
src/index.tsx
Normal file
212
src/index.tsx
Normal file
|
@ -0,0 +1,212 @@
|
||||||
|
/*
|
||||||
|
You don't need to change anything in here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { FunctionComponent } from "react";
|
||||||
|
import ReactDOM from "react-dom/client";
|
||||||
|
import "./index.scss";
|
||||||
|
import {
|
||||||
|
BrowserRouter,
|
||||||
|
Routes,
|
||||||
|
Route,
|
||||||
|
useParams,
|
||||||
|
Navigate,
|
||||||
|
} from "react-router-dom";
|
||||||
|
import Intro from "./Intro";
|
||||||
|
import { NavLink } from "react-router-dom";
|
||||||
|
import Task1 from "./1";
|
||||||
|
import Task2 from "./2";
|
||||||
|
import Task3 from "./3";
|
||||||
|
import Task4 from "./4";
|
||||||
|
import Task5 from "./5";
|
||||||
|
import Task6 from "./6";
|
||||||
|
|
||||||
|
const Menu: FunctionComponent = () => {
|
||||||
|
return (
|
||||||
|
<nav className="menu">
|
||||||
|
<NavLink to="/">Intro</NavLink>
|
||||||
|
|
||||||
|
<NavLink to="/task/1">Task 1</NavLink>
|
||||||
|
|
||||||
|
<NavLink to="/task/2">Task 2</NavLink>
|
||||||
|
|
||||||
|
<NavLink to="/task/3">Task 3</NavLink>
|
||||||
|
|
||||||
|
<NavLink to="/task/4">Task 4</NavLink>
|
||||||
|
|
||||||
|
<NavLink to="/task/5">Task 5</NavLink>
|
||||||
|
|
||||||
|
<NavLink to="/task/6">Task 6</NavLink>
|
||||||
|
</nav>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface ContainerProps {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Container: FunctionComponent<ContainerProps> = (props) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Menu />
|
||||||
|
<main>{props.children}</main>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface TaskContainerProps {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TaskContainer: FunctionComponent<TaskContainerProps> = (props) => {
|
||||||
|
return <div className="task-container">{props.children}</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Task: FunctionComponent = () => {
|
||||||
|
let { id } = useParams<{ id: string }>();
|
||||||
|
|
||||||
|
switch (id) {
|
||||||
|
case "1":
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h1>Task 1 - Create a list</h1>
|
||||||
|
<p className="task-description">
|
||||||
|
This first task is purely about using JSX. Make an ordinary
|
||||||
|
unordered list using 'ul' and li'. The list must{" "}
|
||||||
|
<b>not be static</b>. You have to <b>use the array</b> in state and{" "}
|
||||||
|
<b>iterate over</b> it.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<TaskContainer>
|
||||||
|
<Task1 />
|
||||||
|
</TaskContainer>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
case "2":
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h1>Task 2 - Create a controlled input</h1>
|
||||||
|
<p className="task-description">
|
||||||
|
This task is purely about using <b>React's synthetic event</b>{" "}
|
||||||
|
system. Use the existing input and paragraph to display the{" "}
|
||||||
|
<b>the input value</b> in the paragraph. The paragraph must be kept
|
||||||
|
in sync.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<TaskContainer>
|
||||||
|
<Task2 />
|
||||||
|
</TaskContainer>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
case "3":
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h1>Task 3 - Create a searchable list</h1>
|
||||||
|
<p className="task-description">
|
||||||
|
Use the <b>knowledge</b> you used in the <b>previous 2 tasks</b> to
|
||||||
|
make at searchable list. You must have a <b>input</b> and a{" "}
|
||||||
|
<b>list</b>. The list should be <b>filtered</b> using the value in
|
||||||
|
the input as the user types.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<TaskContainer>
|
||||||
|
<Task3 />
|
||||||
|
</TaskContainer>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
case "4":
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h1>Task 4 - Use styles</h1>
|
||||||
|
<p className="task-description">
|
||||||
|
This task is mainly about <b>styling</b> in ReactJS in order to
|
||||||
|
create a <b>beautiful UI</b>. Use Less to style the form with
|
||||||
|
interaction feedback such as hover, focus and so on. The goal is to
|
||||||
|
make the form as aesthetically pleasing as possible.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<TaskContainer>
|
||||||
|
<Task4 />
|
||||||
|
</TaskContainer>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
case "5":
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h1>Task 5 - Use component composition</h1>
|
||||||
|
<p className="task-description">
|
||||||
|
Use the <b>knowledge</b> you used in the <b>previous tasks</b> to
|
||||||
|
make a searchable list. The requirement is the same as with Task 3.
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
Except, this time you must <b>encapsulate</b> the <b>UI</b> parts
|
||||||
|
into <b>small components</b>. This means the Input and List goes
|
||||||
|
into different small components. In order to communicate between the
|
||||||
|
input and the list, the parent component must be used by
|
||||||
|
passing props and managing state.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<TaskContainer>
|
||||||
|
<Task5 />
|
||||||
|
</TaskContainer>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
case "6":
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h1>Task 6 - Create a Todo List and/or Freestyle</h1>
|
||||||
|
<p className="task-description">
|
||||||
|
This task is mainly about <b>combining different concepts</b> from
|
||||||
|
ReactJS in order to create a <b>small and simple application</b>.
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
You can either choose to create a tiny application your self or
|
||||||
|
follow the description below to create a todo app:
|
||||||
|
</p>
|
||||||
|
<ul className="task-description">
|
||||||
|
Create todos Mark them as done See a list of done todos and a list
|
||||||
|
of pending todos. Search for todos Delete todos
|
||||||
|
</ul>
|
||||||
|
<p className="task-description">
|
||||||
|
Feel free to use Less to style the applications and to install
|
||||||
|
third-party packages if needed.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<TaskContainer>
|
||||||
|
<Task6 />
|
||||||
|
</TaskContainer>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return <Navigate to="/" />;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const root = ReactDOM.createRoot(
|
||||||
|
document.getElementById("root") as HTMLElement
|
||||||
|
);
|
||||||
|
|
||||||
|
root.render(
|
||||||
|
<BrowserRouter>
|
||||||
|
<Routes>
|
||||||
|
<Route
|
||||||
|
path=""
|
||||||
|
element={
|
||||||
|
<Container>
|
||||||
|
<Intro />
|
||||||
|
</Container>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
path="task/:id"
|
||||||
|
element={
|
||||||
|
<Container>
|
||||||
|
<Task />
|
||||||
|
</Container>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Route path="*" element={<Navigate to="/" />} />
|
||||||
|
</Routes>
|
||||||
|
</BrowserRouter>
|
||||||
|
);
|
1
src/react-app-env.d.ts
vendored
Normal file
1
src/react-app-env.d.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/// <reference types="react-scripts" />
|
Loading…
Reference in New Issue
Block a user