| @@ -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, | ||||