瀏覽代碼

Add word UI

master
kj1352 4 年之前
父節點
當前提交
2e6d92d090
共有 8 個檔案被更改,包括 333 行新增6 行删除
  1. +3
    -0
      src/assets/icons/chevron-left.svg
  2. +1
    -1
      src/assets/icons/speaker.svg
  3. +224
    -0
      src/components/add-word/AddWord.module.scss
  4. +68
    -0
      src/components/add-word/AddWord.tsx
  5. +8
    -3
      src/components/home/Home.tsx
  6. +1
    -1
      src/components/tabs/Tabs.tsx
  7. +27
    -0
      src/data/all-words.ts
  8. +1
    -1
      src/structure/word.ts

+ 3
- 0
src/assets/icons/chevron-left.svg 查看文件

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="22.609" viewBox="0 0 13 22.609">
<path id="back-light" d="M19.857,21.952,9.9,12.162l9.953-9.79L18.319.857,6.857,12.168l11.462,11.3Z" transform="translate(-6.857 -0.857)" fill-rule="evenodd"/>
</svg>

+ 1
- 1
src/assets/icons/speaker.svg 查看文件

@@ -1,3 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="19.34" height="19.221" viewBox="0 0 19.34 19.221">
<path id="speaker" d="M0,5.7H4.558L11.414.111V19.332L4.558,13.744H0Zm13.99-.912A6.83,6.83,0,0,1,16.05,9.7a6.364,6.364,0,0,1-2.061,4.755L12.6,13.03a4.607,4.607,0,0,0,1.427-3.369A4.783,4.783,0,0,0,12.6,6.213L13.99,4.786Zm2.378-2.338A9.774,9.774,0,0,1,19.34,9.622a9.9,9.9,0,0,1-2.972,7.213L14.9,15.369a7.722,7.722,0,0,0,2.378-5.727A7.852,7.852,0,0,0,14.9,3.876l1.467-1.427Z" transform="translate(0 -0.111)" fill="#fff"/>
<path id="speaker" d="M0,5.7H4.558L11.414.111V19.332L4.558,13.744H0Zm13.99-.912A6.83,6.83,0,0,1,16.05,9.7a6.364,6.364,0,0,1-2.061,4.755L12.6,13.03a4.607,4.607,0,0,0,1.427-3.369A4.783,4.783,0,0,0,12.6,6.213L13.99,4.786Zm2.378-2.338A9.774,9.774,0,0,1,19.34,9.622a9.9,9.9,0,0,1-2.972,7.213L14.9,15.369a7.722,7.722,0,0,0,2.378-5.727A7.852,7.852,0,0,0,14.9,3.876l1.467-1.427Z" transform="translate(0 -0.111)"/>
</svg>

+ 224
- 0
src/components/add-word/AddWord.module.scss 查看文件

@@ -0,0 +1,224 @@
.modalPage {
background-color: var(--creamy-white);
position: fixed;
top: 0;
left: 0;
z-index: 2;
width: 100vw;
height: 100vh;
overflow: auto;
opacity: 0;
animation: fadeIn 0.3s forwards;

@keyframes fadeIn {
0% {
opacity: 0;
transform: translateY(10vh);
} 100% {
opacity: 1;
transform: translateY(0vh);
}
}
}

.navHeader {
background-color: transparent;
text-align: center;
position: relative;
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 1.5rem;

button {
width: 4rem;
text-align: center;
background-color: transparent;
border: 0;
display: flex;
align-items: center;
justify-content: flex-start;

svg {
width: 1rem;
color: var(--black);
}
}

h5 {
font-size: 1.5rem;
}

figure {
display: block;
img {
display: block;
width: 4rem;
height: 4rem;
border-radius: 50%;
border: 1px solid var(--creamy-white);
}
}
}

.searchBarHolder {
background-color: var(--teal);
padding: 2rem 0 6rem;
border-top-right-radius: 3rem;
border-top-left-radius: 3rem;

.searchBar {
background-color: white;
display: flex;
border-radius: 3rem;
height: 5rem;
width: calc(100% - 6rem);
margin: 0 auto;
align-items: center;
justify-content: space-between;
box-shadow: 0px 5px 30px -20px var(--grey);
input {
height: 100%;
border: 0;
width: calc(100% - 5rem);
background-color: transparent;
padding-left: 2rem;
font-size: 1.4rem;
}
svg {
width: 5rem;
fill: var(--red);
}
}
}

.searchResult {
background-color: var(--creamy-white);
border-top-right-radius: 3rem;
border-top-left-radius: 3rem;
margin: -4rem 0;
min-height: 5rem;
padding: 2rem;

li {
position: relative;
overflow: hidden;
border-radius: 2rem;
padding: 1rem 1.5rem;
margin-bottom: 1.5rem;

&:nth-child(2n) {
&::before {
background-color: var(--teal);
}

header {
h4 {
span {
color: var(--teal);
}
}
}

.description {
span, p {
color: var(--teal);
}
}
}

&::before {
content: '';
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: var(--orange);
opacity: 0.3;
}

&>* {
position: relative;
}

header {
display: flex;
align-items: flex-start;
justify-content: space-between;

h4 {
font-size: 2rem;
font-weight: 600;
color: var(--black);

span {
display: block;
font-size: 1.2rem;
color: var(--orange);
filter: brightness(50%);
font-weight: 500;
}
}

button {
background-color: transparent;
border: none;
background-color: var(--orange);
width: 4rem;
height: 4rem;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;

svg {
width: 1.7rem;
fill: white;
}
}
}
.description {
margin: 1rem 0;
filter: brightness(40%);
opacity: 0.7;

span {
font-size: 1.2rem;
color: var(--orange);
font-weight: 600;
text-transform: lowercase;
}

p {
font-size: 1.2rem;
color: var(--orange);
}
}

.addButton {
width: 7rem;
margin-left: auto;
border: none;
border-radius: 3rem;
height: 3rem;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.2rem;
color: white;
background-color: var(--orange);

svg {
fill: white;
width: 1rem;
margin-right: 0.5rem;
}
}
}
}

+ 68
- 0
src/components/add-word/AddWord.tsx 查看文件

@@ -0,0 +1,68 @@
import React, { useState } from "react";
import styles from './AddWord.module.scss';
import { ReactComponent as ChevronLeft } from '../../assets/icons/chevron-left.svg';
import { ReactComponent as SearchIcon } from '../../assets/icons/bx-search-alt.svg';
import { ReactComponent as SpeakerIcon } from '../../assets/icons/speaker.svg';
import { ReactComponent as AddIcon } from '../../assets/icons/plus.svg';

import { IWord } from "../../structure/word";
import { ALL_WORDS } from "../../data/all-words";

type OwnProps = {
hideModal: () => void;
};

export const AddWord: React.FC<OwnProps> = (props: OwnProps) => {
const [searchResult, setSearchResult] = useState<Array<IWord>>([]);

const searchWords = (searchWord: string) => {
if (searchWord.length > 0) {
let result = ALL_WORDS.filter((word) => {
return word.name.toLowerCase().includes(searchWord.toLowerCase());
});
setSearchResult(result);
} else {
setSearchResult([]);
}
}

return <section className={styles.modalPage}>
<header className={styles.navHeader}>
<button onClick={props.hideModal}>
<ChevronLeft />
</button>
<h5> Add a Word </h5>
<figure>
{/* eslint-disable-next-line */}
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSERA5Pm3aRBV7AaI8tvpZfzpD24ZgrU1_8NA&usqp=CAU" alt="profile-image" />
</figure>
</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 />
</div>
</div>

<ul className={styles.searchResult}>
{ 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}> <AddIcon /> Add </button>
</li>
}) }
</ul>
</section>
}

+ 8
- 3
src/components/home/Home.tsx 查看文件

@@ -1,4 +1,4 @@
import React from "react";
import React, { useState } from "react";
import styles from './Home.module.scss';
import { ReactComponent as LogoIcon } from '../../assets/icons/anamnesis.svg';
import { ReactComponent as SearchIcon } from '../../assets/icons/bx-search-alt.svg';
@@ -15,11 +15,13 @@ import { ReactComponent as GridIcon } from '../../assets/icons/circled.svg';
import { ReactComponent as PersonSpeakerIcon } from '../../assets/icons/user-speaker.svg';
import { ReactComponent as BrainIcon } from '../../assets/icons/bx-brain.svg';
import { ReactComponent as InternBadge } from '../../assets/icons/intern-badge.svg';

import { CircularProgressbar } from 'react-circular-progressbar';
import { AddWord } from "../add-word/AddWord";


export const Home: React.FC = () => {
const [isAddWordModalOpen, setAddWordModalState] = useState<boolean>(false);

return <section className="page">

<header className={styles.pageHeader}>
@@ -57,7 +59,7 @@ export const Home: React.FC = () => {
</section>

<div className={styles.searchBar}>
<input type="text" placeholder={'Search and add a word'} />
<input type="text" placeholder={'Search and add a word'} onClick={() => setAddWordModalState(true)} />
<SearchIcon />
</div>

@@ -252,5 +254,8 @@ export const Home: React.FC = () => {
</ul>
</section>


{ isAddWordModalOpen && <AddWord hideModal={() => { setAddWordModalState(false); }} /> }

</section>
}

+ 1
- 1
src/components/tabs/Tabs.tsx 查看文件

@@ -9,7 +9,7 @@ import { ReactComponent as MoreIcon } from '../../assets/icons/more-vertical.svg
import { NavLink } from "react-router-dom";

export const Tabs: React.FC = () => {
return <section className={styles.tabs} id="tabs">
return <section className={styles.tabs}>
<NavLink to={'/home'} activeClassName={styles.active}>
<HomeIcon />
</NavLink >


+ 27
- 0
src/data/all-words.ts 查看文件

@@ -0,0 +1,27 @@
import { IWord } from "../structure/word";

export const ALL_WORDS: Array<IWord> = [{
name: 'Pleasure',
pronounciation: '/ˈplɛʒə/',
audioPronounciationURL: '',
grammaticalDetails: [{
typeName: 'NOUN',
description: 'a feeling of happy satisfaction and enjoyment.'
}, {
typeName: 'ADJECTIVE',
description: 'used or intended for entertainment rather than business.'
}],
similarWords: ['Happiness', 'Delight', 'Joy', 'Rapture', 'Glee'],
}, {
name: 'Please',
pronounciation: '/pliːz/',
audioPronounciationURL: '',
grammaticalDetails: [{
typeName: 'VERB',
description: 'cause to feel happy and satisfied.'
}, {
typeName: 'ADVERB',
description: 'used in polite requests or questions.'
}],
similarWords: ['Nice', 'Agreeable', 'Pleasant', 'Satisfying', 'Gratifying'],
}]

+ 1
- 1
src/structure/word.ts 查看文件

@@ -3,7 +3,7 @@ export type IWord = {
pronounciation: string,
audioPronounciationURL: string,
grammaticalDetails: Array<{
typeName: 'NOUN' | 'ADJECTIVE' | 'VERB',
typeName: 'NOUN' | 'ADJECTIVE' | 'VERB' | 'ADVERB',
description: string,
}>,
similarWords: Array<string>

Loading…
取消
儲存