@@ -107,8 +107,9 @@ | |||||
position: relative; | position: relative; | ||||
overflow: hidden; | overflow: hidden; | ||||
border-radius: 2rem; | border-radius: 2rem; | ||||
padding: 1rem 1.5rem; | |||||
padding: 1rem 1.5rem 1.7rem; | |||||
margin-bottom: 1.5rem; | margin-bottom: 1.5rem; | ||||
background-color: white; | |||||
&:nth-child(2n) { | &:nth-child(2n) { | ||||
&::before { | &::before { | ||||
@@ -121,6 +122,10 @@ | |||||
color: var(--teal); | color: var(--teal); | ||||
} | } | ||||
} | } | ||||
button { | |||||
background-color: var(--teal); | |||||
} | |||||
} | } | ||||
.description { | .description { | ||||
@@ -128,6 +133,10 @@ | |||||
color: var(--teal); | color: var(--teal); | ||||
} | } | ||||
} | } | ||||
.addButton { | |||||
background-color: var(--teal); | |||||
} | |||||
} | } | ||||
&::before { | &::before { | ||||
@@ -138,7 +147,7 @@ | |||||
width: 100%; | width: 100%; | ||||
height: 100%; | height: 100%; | ||||
background-color: var(--orange); | background-color: var(--orange); | ||||
opacity: 0.3; | |||||
opacity: 0.4; | |||||
} | } | ||||
&>* { | &>* { | ||||
@@ -205,7 +214,7 @@ | |||||
margin-left: auto; | margin-left: auto; | ||||
border: none; | border: none; | ||||
border-radius: 3rem; | border-radius: 3rem; | ||||
height: 3rem; | |||||
height: 2.7rem; | |||||
cursor: pointer; | cursor: pointer; | ||||
display: flex; | display: flex; | ||||
align-items: center; | align-items: center; | ||||
@@ -221,4 +230,103 @@ | |||||
} | } | ||||
} | } | ||||
} | } | ||||
} | |||||
.shelfList { | |||||
list-style: none; | |||||
padding: 1rem 2rem; | |||||
header { | |||||
margin: 0 auto 1rem; | |||||
h5 { | |||||
font-weight: 300; | |||||
font-size: 1.2rem; | |||||
color: var(--black); | |||||
} | |||||
} | |||||
li { | |||||
display: flex; | |||||
justify-content: space-between; | |||||
align-items: center; | |||||
margin: 0 0 2rem; | |||||
&:nth-child(3n) .icon { | |||||
background-color: var(--red); | |||||
} | |||||
&:nth-child(3n - 1) .icon { | |||||
background-color: var(--orange); | |||||
} | |||||
&:nth-child(3n - 2) .icon { | |||||
background-color: var(--blue); | |||||
} | |||||
} | |||||
.icon { | |||||
width: 4rem; | |||||
height: 4rem; | |||||
background-color: var(--grey); | |||||
display: flex; | |||||
align-items: center; | |||||
justify-content: center; | |||||
border-radius: 50%; | |||||
svg { | |||||
fill: white; | |||||
width: 3rem; | |||||
} | |||||
} | |||||
.info { | |||||
width: calc(100% - 5rem); | |||||
label, span { | |||||
display: block; | |||||
} | |||||
label { | |||||
font-size: 1.2rem; | |||||
color: var(--black); | |||||
font-weight: 700; | |||||
} | |||||
span { | |||||
font-size: 1rem; | |||||
color: var(--grey); | |||||
} | |||||
} | |||||
} | |||||
.AddShelfButton { | |||||
position: fixed; | |||||
bottom: 0; | |||||
left: 0; | |||||
padding: 2rem 3rem; | |||||
display: flex; | |||||
align-items: center; | |||||
justify-content: flex-start; | |||||
width: 100%; | |||||
background-color: var(--creamy-white); | |||||
border: none; | |||||
box-shadow: 0px 0px 5px var(--creamy-white); | |||||
font-weight: 600; | |||||
color: var(--black); | |||||
span { | |||||
width: 3rem; | |||||
height: 3rem; | |||||
background-color: var(--teal); | |||||
border-radius: 50%; | |||||
display: flex; | |||||
align-items: center; | |||||
justify-content: center; | |||||
margin-right: 1.5rem; | |||||
svg { | |||||
fill: white; | |||||
width: 1.2rem; | |||||
} | |||||
} | |||||
} | } |
@@ -7,13 +7,16 @@ 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"; | |||||
type OwnProps = { | type OwnProps = { | ||||
hideModal: () => void; | |||||
hideModal: () => void | |||||
}; | }; | ||||
export const AddWord: React.FC<OwnProps> = (props: OwnProps) => { | export const AddWord: React.FC<OwnProps> = (props: OwnProps) => { | ||||
const [searchResult, setSearchResult] = useState<Array<IWord>>([]); | const [searchResult, setSearchResult] = useState<Array<IWord>>([]); | ||||
const [selectedWord, setSelectedWord] = useState<IWord>(); | |||||
const searchWords = (searchWord: string) => { | const searchWords = (searchWord: string) => { | ||||
if (searchWord.length > 0) { | if (searchWord.length > 0) { | ||||
@@ -48,7 +51,7 @@ export const AddWord: React.FC<OwnProps> = (props: OwnProps) => { | |||||
</div> | </div> | ||||
<ul className={styles.searchResult}> | <ul className={styles.searchResult}> | ||||
{ searchResult.map((word) => { | |||||
{ !selectedWord && searchResult.map((word) => { | |||||
return <li key={word.name}> | return <li key={word.name}> | ||||
<header> | <header> | ||||
<h4> { word.name } <span> { word.pronounciation } </span> </h4> | <h4> { word.name } <span> { word.pronounciation } </span> </h4> | ||||
@@ -60,9 +63,32 @@ export const AddWord: React.FC<OwnProps> = (props: OwnProps) => { | |||||
<span> { word.grammaticalDetails[0].typeName } </span> | <span> { word.grammaticalDetails[0].typeName } </span> | ||||
<p> { word.grammaticalDetails[0].description } </p> | <p> { word.grammaticalDetails[0].description } </p> | ||||
</div> | </div> | ||||
<button className={styles.addButton}> <AddIcon /> Add </button> | |||||
<button className={styles.addButton} onClick={() => setSelectedWord(word)}> <AddIcon /> Add </button> | |||||
</li> | </li> | ||||
}) } | }) } | ||||
</ul> | </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> | |||||
</div> | |||||
</li> | |||||
}) | |||||
}) } | |||||
<button className={styles.AddShelfButton}> <span> <AddIcon /> </span> Create New Shelf </button> | |||||
</ul> } | |||||
</section> | </section> | ||||
} | } |
@@ -17,11 +17,52 @@ 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 { AddWord } from "../add-word/AddWord"; | ||||
import { IProfile } from "../../structure/profile"; | |||||
export var userProfileData : IProfile = { | |||||
name: 'Neymar Jr', | |||||
image: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSERA5Pm3aRBV7AaI8tvpZfzpD24ZgrU1_8NA&usqp=CAU', | |||||
medal: { | |||||
name: 'Intern badge', | |||||
minValue: 0, | |||||
maxValue: 100, | |||||
icon: <InternBadge /> | |||||
}, | |||||
categories: [{ | |||||
name: 'Vocabulary', | |||||
icon: <TimeIcon />, | |||||
shelves: [{ | |||||
name: 'All Words', | |||||
words: [], | |||||
revisedWords: [], | |||||
description: 'All Words that I use on a daily basis', | |||||
viewPermission: 'PUBLIC' | |||||
}] | |||||
}, { | |||||
name: 'Books', | |||||
icon: <BookMarkIcon />, | |||||
shelves: [{ | |||||
name: 'Sapiens', | |||||
words: [], | |||||
revisedWords: [], | |||||
description: 'Sapiens book complex words', | |||||
viewPermission: 'PUBLIC' | |||||
}] | |||||
}, { | |||||
name: 'GRE', | |||||
icon: <BrainIcon />, | |||||
shelves: [] | |||||
}, { | |||||
name: 'ELTS', | |||||
icon: <PersonSpeakerIcon />, | |||||
shelves: [] | |||||
}] | |||||
}; | |||||
export const Home: React.FC = () => { | export const Home: React.FC = () => { | ||||
const [isAddWordModalOpen, setAddWordModalState] = useState<boolean>(false); | const [isAddWordModalOpen, setAddWordModalState] = useState<boolean>(false); | ||||
return <section className="page"> | return <section className="page"> | ||||
<header className={styles.pageHeader}> | <header className={styles.pageHeader}> | ||||
@@ -42,8 +83,8 @@ export const Home: React.FC = () => { | |||||
}} | }} | ||||
} /> | } /> | ||||
{/* 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" /> | |||||
<InternBadge /> | |||||
<img src={userProfileData.image} alt="profile-image" /> | |||||
{ userProfileData.medal.icon } | |||||
</div> | </div> | ||||
<div className={styles.userDetails}> | <div className={styles.userDetails}> | ||||
<h2> Neymar Junior </h2> | <h2> Neymar Junior </h2> | ||||
@@ -118,86 +159,30 @@ export const Home: React.FC = () => { | |||||
</button> | </button> | ||||
</header> | </header> | ||||
<ul> | <ul> | ||||
<li> | |||||
<div className={styles.progress}> | |||||
<CircularProgressbar value={30} strokeWidth={7} | |||||
styles={{ | |||||
path: { | |||||
stroke: 'white', | |||||
strokeLinecap: 'round', | |||||
}, | |||||
trail: { | |||||
stroke: 'rgba(255, 255, 255, 0.25)', | |||||
strokeLinecap: 'round', | |||||
}} | |||||
} /> | |||||
<span className={styles.text}> 30% </span> | |||||
</div> | |||||
<h5> All Words </h5> | |||||
<p> Vocabulary </p> | |||||
<p> 1.2K Words </p> | |||||
</li> | |||||
<li> | |||||
<div className={styles.progress}> | |||||
<CircularProgressbar value={50} strokeWidth={7} | |||||
styles={{ | |||||
path: { | |||||
stroke: 'white', | |||||
strokeLinecap: 'round', | |||||
}, | |||||
trail: { | |||||
stroke: 'rgba(255, 255, 255, 0.25)', | |||||
strokeLinecap: 'round', | |||||
}} | |||||
} /> | |||||
<span className={styles.text}> 50% </span> | |||||
</div> | |||||
<h5> IELTS Fundamentals </h5> | |||||
<p> IELTS </p> | |||||
<p> 250 Words </p> | |||||
</li> | |||||
<li> | |||||
<div className={styles.progress}> | |||||
<CircularProgressbar value={10} strokeWidth={7} | |||||
styles={{ | |||||
path: { | |||||
stroke: 'white', | |||||
strokeLinecap: 'round', | |||||
}, | |||||
trail: { | |||||
stroke: 'rgba(255, 255, 255, 0.25)', | |||||
strokeLinecap: 'round', | |||||
}} | |||||
} /> | |||||
<span className={styles.text}> 10% </span> | |||||
</div> | |||||
<h5> GRE Fundamentals </h5> | |||||
<p> GRE </p> | |||||
<p> 456 Words </p> | |||||
</li> | |||||
<li> | |||||
<div className={styles.progress}> | |||||
<CircularProgressbar value={25} strokeWidth={7} | |||||
styles={{ | |||||
path: { | |||||
stroke: 'white', | |||||
strokeLinecap: 'round', | |||||
}, | |||||
trail: { | |||||
stroke: 'rgba(255, 255, 255, 0.25)', | |||||
strokeLinecap: 'round', | |||||
}} | |||||
} /> | |||||
<span className={styles.text}> 25% </span> | |||||
</div> | |||||
<h5> Sapiens </h5> | |||||
<p> Book </p> | |||||
<p> 125 Words </p> | |||||
</li> | |||||
{ userProfileData.categories.map(category => { | |||||
return category.shelves.map(shelf => { | |||||
return <li key={shelf.name}> | |||||
<div className={styles.progress}> | |||||
<CircularProgressbar value={shelf.words.length > 0 ? (shelf.revisedWords.length * 100/ shelf.words.length) : 0} strokeWidth={7} | |||||
styles={{ | |||||
path: { | |||||
stroke: 'white', | |||||
strokeLinecap: 'round', | |||||
}, | |||||
trail: { | |||||
stroke: 'rgba(255, 255, 255, 0.25)', | |||||
strokeLinecap: 'round', | |||||
}} | |||||
} /> | |||||
<span className={styles.text}> { shelf.words.length > 0 ? (shelf.revisedWords.length * 100/ shelf.words.length) : 0 }% </span> | |||||
</div> | |||||
<h5> { category.name } </h5> | |||||
<p> { shelf.name } </p> | |||||
<p> { shelf.words.length } words </p> | |||||
</li> | |||||
}) | |||||
}) } | |||||
</ul> | </ul> | ||||
</section> | </section> | ||||
@@ -215,42 +200,17 @@ export const Home: React.FC = () => { | |||||
</button> | </button> | ||||
</header> | </header> | ||||
<ul> | <ul> | ||||
<li> | |||||
<div className={styles.icon}> | |||||
<TimeIcon /> | |||||
</div> | |||||
<div className={styles.info}> | |||||
<label> Vocabulary </label> | |||||
<span> 5 Shelves </span> | |||||
</div> | |||||
</li> | |||||
<li> | |||||
<div className={styles.icon}> | |||||
<BookMarkIcon /> | |||||
</div> | |||||
<div className={styles.info}> | |||||
<label> Books </label> | |||||
<span> 3 Shelves </span> | |||||
</div> | |||||
</li> | |||||
<li> | |||||
<div className={styles.icon}> | |||||
<PersonSpeakerIcon /> | |||||
</div> | |||||
<div className={styles.info}> | |||||
<label> IELTS </label> | |||||
<span> 5 Shelves </span> | |||||
</div> | |||||
</li> | |||||
<li> | |||||
<div className={styles.icon}> | |||||
<BrainIcon /> | |||||
</div> | |||||
<div className={styles.info}> | |||||
<label> GRE </label> | |||||
<span> 2 Shelves </span> | |||||
</div> | |||||
</li> | |||||
{ 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> | </ul> | ||||
</section> | </section> | ||||
@@ -1,8 +0,0 @@ | |||||
import { IMedal } from "../structure/medals"; | |||||
export const ALL_MEDALS: Array<IMedal> = [{ | |||||
name: 'Intern', | |||||
minValue: 0, | |||||
maxValue: 100, | |||||
icon: '' | |||||
}] |
@@ -2,6 +2,6 @@ import { IShelf } from "./shelf"; | |||||
export type ICategory = { | export type ICategory = { | ||||
name: string, | name: string, | ||||
icon: string, | |||||
icon: JSX.Element, | |||||
shelves: Array<IShelf> | shelves: Array<IShelf> | ||||
}; | }; |
@@ -2,5 +2,5 @@ export type IMedal = { | |||||
name: string, | name: string, | ||||
minValue: number, | minValue: number, | ||||
maxValue: number, | maxValue: number, | ||||
icon: string, | |||||
icon: JSX.Element, | |||||
}; | }; |
@@ -1,6 +1,7 @@ | |||||
import { IWord } from "./word"; | import { IWord } from "./word"; | ||||
export type IShelf = { | export type IShelf = { | ||||
name: string, | |||||
words: Array<IWord>, | words: Array<IWord>, | ||||
revisedWords: Array<IWord>, | revisedWords: Array<IWord>, | ||||
description: string, | description: string, | ||||