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