@@ -3,12 +3,16 @@ import { Categories } from './components/categories/Categories'; | |||||
import { Revise } from './components/revise/Revise'; | import { Revise } from './components/revise/Revise'; | ||||
import { Tabs } from "./components/tabs/Tabs"; | import { Tabs } from "./components/tabs/Tabs"; | ||||
import { BrowserRouter, Route, Redirect, Switch } from "react-router-dom"; | import { BrowserRouter, Route, Redirect, Switch } from "react-router-dom"; | ||||
import { AddWord } from "./components/add-word/AddWord"; | |||||
import { AddShelf } from "./components/add-shelf/AddShelf"; | |||||
function App() { | function App() { | ||||
return ( | return ( | ||||
<BrowserRouter> | <BrowserRouter> | ||||
<Switch> | <Switch> | ||||
<Route path="/home" component={Home} /> | <Route path="/home" component={Home} /> | ||||
<Route path="/add-word" component={AddWord} /> | |||||
<Route path="/add-shelf" component={AddShelf} /> | |||||
<Route path="/categories" component={Categories} /> | <Route path="/categories" component={Categories} /> | ||||
<Route path="/revise" component={Revise} /> | <Route path="/revise" component={Revise} /> | ||||
<Redirect from="/" to="/home" /> | <Redirect from="/" to="/home" /> | ||||
@@ -1,6 +1,6 @@ | |||||
<svg xmlns="http://www.w3.org/2000/svg" width="20.36" height="20.014" viewBox="0 0 20.36 20.014"> | <svg xmlns="http://www.w3.org/2000/svg" width="20.36" height="20.014" viewBox="0 0 20.36 20.014"> | ||||
<g id="Group_11" data-name="Group 11" transform="translate(-17.641 -24)"> | <g id="Group_11" data-name="Group 11" transform="translate(-17.641 -24)"> | ||||
<path id="back-light" d="M18.365,19.53l-8.81-8.666L18.365,2.2,17,.857,6.857,10.869,17,20.871Z" transform="translate(19.635 23.143)" fill="#fff" fill-rule="evenodd"/> | |||||
<path id="back-light-2" data-name="back-light" d="M11.508,18.673,2.7,10.007l8.81-8.666L10.146,0,0,10.012l10.146,10Z" transform="translate(29.148 44.014) rotate(180)" fill="#fff" fill-rule="evenodd"/> | |||||
<path id="back-light" d="M18.365,19.53l-8.81-8.666L18.365,2.2,17,.857,6.857,10.869,17,20.871Z" transform="translate(19.635 23.143)" fill-rule="evenodd"/> | |||||
<path id="back-light-2" data-name="back-light" d="M11.508,18.673,2.7,10.007l8.81-8.666L10.146,0,0,10.012l10.146,10Z" transform="translate(29.148 44.014) rotate(180)" fill-rule="evenodd"/> | |||||
</g> | </g> | ||||
</svg> | </svg> |
@@ -0,0 +1,247 @@ | |||||
.createShelfModal { | |||||
background-color: var(--creamy-white); | |||||
z-index: 2; | |||||
width: 100vw; | |||||
height: 100vh; | |||||
overflow: auto; | |||||
opacity: 0; | |||||
position: relative; | |||||
animation: fadeIn 0.3s forwards; | |||||
@keyframes fadeIn { | |||||
0% { | |||||
opacity: 0; | |||||
transform: translateY(10vh); | |||||
} 100% { | |||||
opacity: 1; | |||||
transform: translateY(0vh); | |||||
} | |||||
} | |||||
} | |||||
.modalHeader { | |||||
background-color: var(--orange); | |||||
display: flex; | |||||
align-items: center; | |||||
justify-content: center; | |||||
padding-bottom: 4.5rem; | |||||
padding-top: 0.5rem; | |||||
h4 { | |||||
flex-grow: 1; | |||||
padding-left: 4rem; | |||||
color: white; | |||||
font-size: 1.5rem; | |||||
text-align: center; | |||||
font-weight: 500; | |||||
} | |||||
button { | |||||
margin-left: auto; | |||||
margin-right: 1rem; | |||||
width: 4rem; | |||||
height: 4rem; | |||||
display: flex; | |||||
align-items: center; | |||||
justify-content: center; | |||||
background-color: transparent; | |||||
border: none; | |||||
svg { | |||||
width: 1.5rem; | |||||
fill: white; | |||||
} | |||||
} | |||||
} | |||||
.form { | |||||
border-radius: 3rem; | |||||
background-color: var(--creamy-white); | |||||
overflow: hidden; | |||||
margin-top: -4rem; | |||||
padding: 2rem; | |||||
input { | |||||
border: none; | |||||
height: 4rem; | |||||
width: 100%; | |||||
display: block; | |||||
border-radius: 3rem; | |||||
box-shadow: 0px 2px 10px -5px inset var(--light-grey); | |||||
padding: 0 1.5rem; | |||||
font-size: 1.2rem; | |||||
margin-bottom: 1.5rem; | |||||
background-color: #efe6d6; | |||||
} | |||||
textarea { | |||||
background-color: #efe6d6; | |||||
font-size: 1.2rem; | |||||
padding: 1rem 1.5rem; | |||||
box-shadow: 0px 2px 10px -5px inset var(--light-grey); | |||||
border: none; | |||||
resize: none; | |||||
display: block; | |||||
width: 100%; | |||||
height: 10rem; | |||||
border-radius: 1.5rem; | |||||
margin-bottom: 1.5rem; | |||||
} | |||||
} | |||||
.blockHeader { | |||||
display: flex; | |||||
align-items: center; | |||||
justify-content: flex-start; | |||||
h5 { | |||||
font-size: 1.2rem; | |||||
font-weight: 600; | |||||
color: var(--black); | |||||
flex-grow: 1; | |||||
svg { | |||||
width: 2rem; | |||||
height: 2rem; | |||||
fill: var(--black); | |||||
vertical-align: middle; | |||||
margin-right: 1rem; | |||||
} | |||||
} | |||||
button, a { | |||||
background-color: var(--teal); | |||||
width: 3rem; | |||||
height: 3rem; | |||||
border: none; | |||||
border-radius: 50%; | |||||
display: flex; | |||||
align-items: center; | |||||
justify-content: center; | |||||
margin-left: 1rem; | |||||
&.expandButton { | |||||
background-color: var(--red); | |||||
} | |||||
svg { | |||||
fill: white; | |||||
width: 1.2rem; | |||||
} | |||||
} | |||||
} | |||||
.Grid { | |||||
padding: 0 0.5rem; | |||||
ul { | |||||
list-style: none; | |||||
display: grid; | |||||
grid-template-columns: 1fr 1fr; | |||||
} | |||||
li { | |||||
display: flex; | |||||
justify-content: space-between; | |||||
align-items: center; | |||||
margin: 1rem 0; | |||||
&:nth-child(1) .icon { | |||||
background-color: var(--orange); | |||||
} | |||||
&:nth-child(2) .icon { | |||||
background-color: var(--blue); | |||||
} | |||||
&:nth-child(3) .icon { | |||||
background-color: var(--red); | |||||
} | |||||
&:nth-child(4) .icon { | |||||
background-color: var(--teal); | |||||
} | |||||
} | |||||
.icon { | |||||
width: 4.5rem; | |||||
height: 4.5rem; | |||||
background-color: var(--grey); | |||||
display: flex; | |||||
align-items: center; | |||||
justify-content: center; | |||||
border-radius: 1rem; | |||||
svg { | |||||
fill: white; | |||||
width: 2rem; | |||||
} | |||||
} | |||||
.info { | |||||
width: calc(100% - 5.5rem); | |||||
label, span { | |||||
display: block; | |||||
} | |||||
label { | |||||
font-size: 1.2rem; | |||||
color: var(--black); | |||||
font-weight: 700; | |||||
} | |||||
span { | |||||
font-size: 1rem; | |||||
color: var(--grey); | |||||
} | |||||
} | |||||
} | |||||
.toggleHolder { | |||||
width: 100%; | |||||
display: flex; | |||||
align-items: center; | |||||
justify-content: space-between; | |||||
padding: 2rem 0.5rem; | |||||
label { | |||||
font-size: 1.2rem; | |||||
color: var(--black); | |||||
font-weight: 600; | |||||
} | |||||
.toggle { | |||||
background-color: #efe6d6; | |||||
width: 4rem; | |||||
height: 2rem; | |||||
border-radius: 3rem; | |||||
box-shadow: 0px 0px 10px -5px inset var(--light-grey); | |||||
span { | |||||
width: 2rem; | |||||
height: 2rem; | |||||
background-color: var(--red); | |||||
border-radius: 50%; | |||||
display: block; | |||||
transform: scale(0.8); | |||||
} | |||||
} | |||||
} | |||||
.publishButton { | |||||
width: 9rem; | |||||
height: 3.5rem; | |||||
background-color: var(--teal); | |||||
font-size: 1.2rem; | |||||
font-weight: 500; | |||||
color: white; | |||||
display: block; | |||||
margin: 2rem auto; | |||||
border: none; | |||||
border-radius: 3rem; | |||||
position: fixed; | |||||
left: calc(50% - 4.5rem); | |||||
bottom: 1rem; | |||||
z-index: 1; | |||||
} |
@@ -0,0 +1,55 @@ | |||||
import React from "react"; | |||||
import styles from './AddShelf.module.scss'; | |||||
import { ReactComponent as CloseIcon } from '../../assets/icons/close.svg'; | |||||
import { ReactComponent as PlusIcon } from '../../assets/icons/plus.svg'; | |||||
import { userProfileData } from "../home/Home"; | |||||
export const AddShelf: React.FC = () => { | |||||
return <section className={styles.createShelfModal}> | |||||
<header className={styles.modalHeader}> | |||||
<h4> Create New Shelf </h4> | |||||
<button onClick={() => { window.history.back() }}> | |||||
<CloseIcon /> | |||||
</button> | |||||
</header> | |||||
<section className={styles.form}> | |||||
<input type="text" placeholder={'Shelf Name'} /> | |||||
<textarea placeholder={'Add description'}></textarea> | |||||
<section className={styles.Grid}> | |||||
<header className={styles.blockHeader}> | |||||
<h5> | |||||
Choose a category | |||||
</h5> | |||||
<button> | |||||
<PlusIcon /> | |||||
</button> | |||||
</header> | |||||
<ul> | |||||
{ userProfileData.categories.map(category => { | |||||
return <li key={category.name}> | |||||
<div className={styles.icon}> | |||||
{ category.icon } | |||||
</div> | |||||
<div className={styles.info}> | |||||
<label> { category.name } </label> | |||||
<span> { category.shelves.length } Shelves </span> | |||||
</div> | |||||
</li> | |||||
})} | |||||
</ul> | |||||
</section> | |||||
<section className={styles.toggleHolder}> | |||||
<label> Public </label> | |||||
<div className={styles.toggle}> | |||||
<span></span> | |||||
</div> | |||||
</section> | |||||
<button className={styles.publishButton}> Publish </button> | |||||
</section> | |||||
</section> | |||||
} |
@@ -1,13 +1,11 @@ | |||||
.modalPage { | .modalPage { | ||||
background-color: var(--creamy-white); | background-color: var(--creamy-white); | ||||
position: fixed; | |||||
top: 0; | |||||
left: 0; | |||||
z-index: 2; | z-index: 2; | ||||
width: 100vw; | width: 100vw; | ||||
height: 100vh; | height: 100vh; | ||||
overflow: auto; | overflow: auto; | ||||
opacity: 0; | opacity: 0; | ||||
position: relative; | |||||
animation: fadeIn 0.3s forwards; | animation: fadeIn 0.3s forwards; | ||||
@keyframes fadeIn { | @keyframes fadeIn { | ||||
@@ -234,13 +232,18 @@ | |||||
.shelfList { | .shelfList { | ||||
list-style: none; | list-style: none; | ||||
padding: 1rem 2rem; | |||||
background-color: var(--creamy-white); | |||||
border-top-right-radius: 3rem; | |||||
border-top-left-radius: 3rem; | |||||
margin: -4rem 0; | |||||
min-height: 5rem; | |||||
padding: 2rem; | |||||
header { | header { | ||||
margin: 0 auto 1rem; | margin: 0 auto 1rem; | ||||
h5 { | h5 { | ||||
font-weight: 300; | font-weight: 300; | ||||
font-size: 1.2rem; | |||||
font-size: 1.3rem; | |||||
color: var(--black); | color: var(--black); | ||||
} | } | ||||
} | } | ||||
@@ -313,6 +316,7 @@ | |||||
box-shadow: 0px 0px 5px var(--creamy-white); | box-shadow: 0px 0px 5px var(--creamy-white); | ||||
font-weight: 600; | font-weight: 600; | ||||
color: var(--black); | color: var(--black); | ||||
font-size: 1.3rem; | |||||
span { | span { | ||||
width: 3rem; | width: 3rem; | ||||
@@ -8,14 +8,10 @@ import { ReactComponent as AddIcon } from '../../assets/icons/plus.svg'; | |||||
import { IWord } from "../../structure/word"; | import { IWord } from "../../structure/word"; | ||||
import { ALL_WORDS } from "../../data/all-words"; | import { ALL_WORDS } from "../../data/all-words"; | ||||
import { userProfileData } from "../home/Home"; | import { userProfileData } from "../home/Home"; | ||||
import { NavLink } from "react-router-dom"; | |||||
type OwnProps = { | |||||
hideModal: () => void | |||||
}; | |||||
export const AddWord: React.FC<OwnProps> = (props: OwnProps) => { | |||||
const [searchResult, setSearchResult] = useState<Array<IWord>>([]); | |||||
export const AddWord: React.FC = () => { | |||||
const [searchWordResult, setSearchResult] = useState<Array<IWord>>([]); | |||||
const [selectedWord, setSelectedWord] = useState<IWord>(); | const [selectedWord, setSelectedWord] = useState<IWord>(); | ||||
const searchWords = (searchWord: string) => { | const searchWords = (searchWord: string) => { | ||||
@@ -32,63 +28,83 @@ export const AddWord: React.FC<OwnProps> = (props: OwnProps) => { | |||||
return <section className={styles.modalPage}> | return <section className={styles.modalPage}> | ||||
<header className={styles.navHeader}> | <header className={styles.navHeader}> | ||||
<button onClick={props.hideModal}> | |||||
<button onClick={() => { | |||||
if (selectedWord) { | |||||
setSelectedWord(undefined); | |||||
} else { | |||||
window.history.back() | |||||
} | |||||
}}> | |||||
<ChevronLeft /> | <ChevronLeft /> | ||||
</button> | </button> | ||||
<h5> Add a Word </h5> | |||||
{ !selectedWord && <h5> Add a Word </h5> } | |||||
{ selectedWord && <h5> Add to Shelf </h5> } | |||||
<figure> | |||||
<figure style={{ opacity: selectedWord ? 0 : 1 }}> | |||||
{/* eslint-disable-next-line */} | {/* eslint-disable-next-line */} | ||||
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSERA5Pm3aRBV7AaI8tvpZfzpD24ZgrU1_8NA&usqp=CAU" alt="profile-image" /> | |||||
<img src={ userProfileData.image } alt="profile-image" /> | |||||
</figure> | </figure> | ||||
</header> | </header> | ||||
<div className={styles.searchBarHolder}> | |||||
<div className={styles.searchBar}> | |||||
<input type="text" autoFocus={true} placeholder={'Search and add a word'} onChange={(event) => searchWords(event.currentTarget.value)} /> | |||||
<SearchIcon /> | |||||
{ !selectedWord && <section> | |||||
<div className={styles.searchBarHolder}> | |||||
<div className={styles.searchBar}> | |||||
<input type="text" autoFocus={true} placeholder={'Search and add a word'} onChange={(event) => searchWords(event.currentTarget.value)} /> | |||||
<SearchIcon /> | |||||
</div> | |||||
</div> | </div> | ||||
</div> | |||||
<ul className={styles.searchResult}> | |||||
{ !selectedWord && searchResult.map((word) => { | |||||
return <li key={word.name}> | |||||
<header> | |||||
<h4> { word.name } <span> { word.pronounciation } </span> </h4> | |||||
<button> | |||||
<SpeakerIcon /> | |||||
</button> | |||||
</header> | |||||
<div className={styles.description}> | |||||
<span> { word.grammaticalDetails[0].typeName } </span> | |||||
<p> { word.grammaticalDetails[0].description } </p> | |||||
</div> | |||||
<button className={styles.addButton} onClick={() => setSelectedWord(word)}> <AddIcon /> Add </button> | |||||
</li> | |||||
}) } | |||||
</ul> | |||||
{ selectedWord && <ul className={styles.shelfList}> | |||||
<header> | |||||
<h5> All Shelves </h5> | |||||
</header> | |||||
{ userProfileData.categories.map((category, categoryIndex) => { | |||||
return category.shelves.map((shelf, shelfIndex) => { | |||||
return <li key={shelf.name} onClick={() => { | |||||
userProfileData.categories[categoryIndex].shelves[shelfIndex].words.push(selectedWord); | |||||
}}> | |||||
<div className={styles.icon}> | |||||
{ category.icon } | |||||
</div> | |||||
<div className={styles.info}> | |||||
<label> { shelf.name } </label> | |||||
<span> { category.name } </span> | |||||
<ul className={styles.searchResult}> | |||||
{ searchWordResult.map((word) => { | |||||
return <li key={word.name}> | |||||
<header> | |||||
<h4> { word.name } <span> { word.pronounciation } </span> </h4> | |||||
<button> | |||||
<SpeakerIcon /> | |||||
</button> | |||||
</header> | |||||
<div className={styles.description}> | |||||
<span> { word.grammaticalDetails[0].typeName } </span> | |||||
<p> { word.grammaticalDetails[0].description } </p> | |||||
</div> | </div> | ||||
<button className={styles.addButton} onClick={() => setSelectedWord(word)}> <AddIcon /> Add </button> | |||||
</li> | </li> | ||||
}) | |||||
}) } | |||||
}) } | |||||
</ul> | |||||
</section> } | |||||
{ selectedWord && <section> | |||||
<div className={styles.searchBarHolder}> | |||||
<div className={styles.searchBar}> | |||||
<input type="text" placeholder={'Search shelves'}/> | |||||
<SearchIcon /> | |||||
</div> | |||||
</div> | |||||
<ul className={styles.shelfList}> | |||||
<header> | |||||
<h5> All Shelves </h5> | |||||
</header> | |||||
{ userProfileData.categories.map((category, categoryIndex) => { | |||||
return category.shelves.map((shelf, shelfIndex) => { | |||||
return <li key={shelf.name} onClick={() => { | |||||
userProfileData.categories[categoryIndex].shelves[shelfIndex].words.push(selectedWord); | |||||
}}> | |||||
<div className={styles.icon}> | |||||
{ category.icon } | |||||
</div> | |||||
<div className={styles.info}> | |||||
<label> { shelf.name } </label> | |||||
<span> { category.name } </span> | |||||
</div> | |||||
</li> | |||||
}) | |||||
}) } | |||||
<button className={styles.AddShelfButton}> <span> <AddIcon /> </span> Create New Shelf </button> | |||||
</ul> } | |||||
<NavLink to={'/add-shelf'} className={styles.AddShelfButton}> <span> <AddIcon /> </span> Create New Shelf </NavLink> | |||||
</ul> | |||||
</section> } | |||||
</section> | </section> | ||||
} | } |
@@ -4,6 +4,10 @@ | |||||
padding: 1.5rem 0; | padding: 1.5rem 0; | ||||
position: relative; | position: relative; | ||||
svg { | |||||
transform: scale(0.9); | |||||
} | |||||
figure { | figure { | ||||
display: block; | display: block; | ||||
position: absolute; | position: absolute; | ||||
@@ -2,6 +2,10 @@ | |||||
background-color: var(--orange); | background-color: var(--orange); | ||||
text-align: center; | text-align: center; | ||||
padding: 1rem 0 0.5rem; | padding: 1rem 0 0.5rem; | ||||
svg { | |||||
transform: scale(0.9); | |||||
} | |||||
} | } | ||||
.upfold { | .upfold { | ||||
@@ -119,7 +123,7 @@ | |||||
} | } | ||||
} | } | ||||
button { | |||||
button, a { | |||||
background-color: var(--teal); | background-color: var(--teal); | ||||
width: 3rem; | width: 3rem; | ||||
height: 3rem; | height: 3rem; | ||||
@@ -16,8 +16,8 @@ import { ReactComponent as PersonSpeakerIcon } from '../../assets/icons/user-spe | |||||
import { ReactComponent as BrainIcon } from '../../assets/icons/bx-brain.svg'; | import { ReactComponent as BrainIcon } from '../../assets/icons/bx-brain.svg'; | ||||
import { ReactComponent as InternBadge } from '../../assets/icons/intern-badge.svg'; | import { ReactComponent as InternBadge } from '../../assets/icons/intern-badge.svg'; | ||||
import { CircularProgressbar } from 'react-circular-progressbar'; | import { CircularProgressbar } from 'react-circular-progressbar'; | ||||
import { AddWord } from "../add-word/AddWord"; | |||||
import { IProfile } from "../../structure/profile"; | import { IProfile } from "../../structure/profile"; | ||||
import { NavLink } from "react-router-dom"; | |||||
export var userProfileData : IProfile = { | export var userProfileData : IProfile = { | ||||
@@ -61,8 +61,6 @@ export var userProfileData : IProfile = { | |||||
}; | }; | ||||
export const Home: React.FC = () => { | export const Home: React.FC = () => { | ||||
const [isAddWordModalOpen, setAddWordModalState] = useState<boolean>(false); | |||||
return <section className="page"> | return <section className="page"> | ||||
<header className={styles.pageHeader}> | <header className={styles.pageHeader}> | ||||
@@ -99,10 +97,10 @@ export const Home: React.FC = () => { | |||||
</div> | </div> | ||||
</section> | </section> | ||||
<div className={styles.searchBar}> | |||||
<input type="text" placeholder={'Search and add a word'} onClick={() => setAddWordModalState(true)} /> | |||||
<NavLink to={'/add-word'} className={styles.searchBar}> | |||||
<input type="text" placeholder={'Search and add a word'} /> | |||||
<SearchIcon /> | <SearchIcon /> | ||||
</div> | |||||
</NavLink> | |||||
<section className={styles.List}> | <section className={styles.List}> | ||||
<header className={styles.blockHeader}> | <header className={styles.blockHeader}> | ||||
@@ -154,9 +152,9 @@ export const Home: React.FC = () => { | |||||
<button className={styles.expandButton}> | <button className={styles.expandButton}> | ||||
<ExpandIcon /> | <ExpandIcon /> | ||||
</button> | </button> | ||||
<button> | |||||
<NavLink to={'/add-shelf'}> | |||||
<PlusIcon /> | <PlusIcon /> | ||||
</button> | |||||
</NavLink> | |||||
</header> | </header> | ||||
<ul> | <ul> | ||||
{ userProfileData.categories.map(category => { | { userProfileData.categories.map(category => { | ||||
@@ -210,12 +208,8 @@ export const Home: React.FC = () => { | |||||
<span> { category.shelves.length } Shelves </span> | <span> { category.shelves.length } Shelves </span> | ||||
</div> | </div> | ||||
</li> | </li> | ||||
})} | |||||
})} | |||||
</ul> | </ul> | ||||
</section> | </section> | ||||
{ isAddWordModalOpen && <AddWord hideModal={() => { setAddWordModalState(false); }} /> } | |||||
</section> | </section> | ||||
} | } |
@@ -12,7 +12,7 @@ export const Tabs: React.FC = () => { | |||||
return <section className={styles.tabs}> | return <section className={styles.tabs}> | ||||
<NavLink to={'/home'} activeClassName={styles.active}> | <NavLink to={'/home'} activeClassName={styles.active}> | ||||
<HomeIcon /> | <HomeIcon /> | ||||
</NavLink > | |||||
</NavLink> | |||||
<NavLink to={'/categories'} activeClassName={styles.active}> | <NavLink to={'/categories'} activeClassName={styles.active}> | ||||
<GridIcon /> | <GridIcon /> | ||||
</NavLink > | </NavLink > | ||||