浏览代码

Word details page

master
kj1352 4 年前
父节点
当前提交
b2eec2f56f
共有 8 个文件被更改,包括 466 次插入7 次删除
  1. +10
    -1
      src/App.tsx
  2. +46
    -0
      src/components/shelf-details/ShelfDetails.module.scss
  3. +8
    -4
      src/components/shelf-details/ShelfDetails.tsx
  4. +289
    -0
      src/components/word-details/WordDetails.module.scss
  5. +102
    -0
      src/components/word-details/WordDetails.tsx
  6. +3
    -2
      src/data/all-words.ts
  7. +5
    -0
      src/index.css
  8. +3
    -0
      src/structure/word.ts

+ 10
- 1
src/App.tsx 查看文件

@@ -16,6 +16,7 @@ import { ReactComponent as TimeIcon } from './assets/icons/time.svg';

import { IProfile } from "./structure/profile";
import { ALL_WORDS } from "./data/all-words";
import { WordDetails } from "./components/word-details/WordDetails";


export var userProfileData : IProfile = {
@@ -32,7 +33,14 @@ export var userProfileData : IProfile = {
icon: <TimeIcon />,
shelves: [{
name: 'All Words',
words: [ALL_WORDS[0], ALL_WORDS[1], ALL_WORDS[2], ALL_WORDS[3]],
words: [{
...ALL_WORDS[0],
tag: 'New Word',
notes: ['Weird words but understandable for a newb']
}, {
...ALL_WORDS[1],
tag: 'Learning'
}, ALL_WORDS[2], ALL_WORDS[3]],
revisedWords: [ALL_WORDS[1]],
description: 'All Words that I use on a daily basis',
viewPermission: 'PUBLIC'
@@ -68,6 +76,7 @@ function App() {
<Route path="/categories" component={Categories} />
<Route path="/category-details/" component={CategoryDetails} />
<Route path="/shelf-details/" component={ShelfDetails} />
<Route path="/word-details/" component={WordDetails} />
<Route path="/revise" component={Revise} />
<Redirect from="/" to="/home" />
</Switch>


+ 46
- 0
src/components/shelf-details/ShelfDetails.module.scss 查看文件

@@ -254,6 +254,12 @@
color: var(--orange);
}
}

.tag {
&::before {
background-color: var(--orange);
}
}
}

&:nth-child(4n - 3) {
@@ -278,6 +284,12 @@
color: var(--teal);
}
}

.tag {
&::before {
background-color: var(--teal);
}
}
}

&:nth-child(4n - 2) {
@@ -302,6 +314,12 @@
color: var(--blue);
}
}

.tag {
&::before {
background-color: var(--blue);
}
}
}


@@ -327,6 +345,12 @@
color: var(--red);
}
}

.tag {
&::before {
background-color: var(--red);
}
}
}

&::before {
@@ -344,6 +368,28 @@
position: relative;
}

.tag {
background-color: transparent;
padding: 0.2rem 0.5rem;
color: var(--grey);
font-size: 1.4rem;
font-weight: 300;
position: relative;
overflow: hidden;

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

header {
display: flex;
align-items: flex-start;


+ 8
- 4
src/components/shelf-details/ShelfDetails.tsx 查看文件

@@ -1,7 +1,6 @@
import React, { useState } from "react";
import styles from './ShelfDetails.module.scss';
import { ReactComponent as ChevronLeft } from '../../assets/icons/chevron-left.svg';
import { NavLink, useLocation } from "react-router-dom";
import { NavLink, useHistory, useLocation } from "react-router-dom";
import queryString from 'query-string';
import { ICategory } from "../../structure/category";
import { IShelf } from "../../structure/shelf";
@@ -10,6 +9,7 @@ import { ReactComponent as BookIcon } from '../../assets/icons/book-sharp.svg';
import { ReactComponent as MoreIcon } from '../../assets/icons/more-alt.svg';
import { ReactComponent as SearchIcon } from '../../assets/icons/bx-search-alt.svg';
import { ReactComponent as SpeakerIcon } from '../../assets/icons/speaker.svg';
import { ReactComponent as ChevronLeft } from '../../assets/icons/chevron-left.svg';
import { IWord } from "../../structure/word";

export const ShelfDetails: React.FC = () => {
@@ -20,6 +20,7 @@ export const ShelfDetails: React.FC = () => {
const shelf: IShelf = category.shelves[shelf_id];
const [searchWordResult, setSearchResult] = useState<Array<IWord>>(shelf.words);
const [selectedSegment, setSelectedSegment] = useState<'WORDS' | 'ABOUT'>('WORDS');
const history = useHistory();

const searchWords = (searchWord: string) => {
if (searchWord.length > 0) {
@@ -86,8 +87,11 @@ export const ShelfDetails: React.FC = () => {

{ selectedSegment === 'WORDS' &&
<ul className={styles.searchResult}>
{ searchWordResult.map((word) => {
return <li key={word.name}>
{ searchWordResult.map((word, index) => {
return <li key={word.name} onClick={() => {
history.push('/word-details/category_id=' + category_id + '&&shelf_id=' + shelf_id + '&&word_id=' + index);
}}>
{ word.tag && <span className={styles.tag}> {word.tag} </span> }
<header>
<h4> { word.name } <span> { word.pronounciation } </span> </h4>
<button>


+ 289
- 0
src/components/word-details/WordDetails.module.scss 查看文件

@@ -0,0 +1,289 @@
.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);
}
}
}

.cardDetails {
border-radius: 4rem;
padding: 2rem;
background-color: white;
position: relative;
overflow: hidden;

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

& > * {
position: relative;
}

.tag {
font-size: 1.4rem;
color: var(--orange);
filter: brightness(60%);
}

.container {
display: flex;
align-items: center;
justify-content: flex-start;
padding: 0.2rem 0 2rem;

.audioButton {
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;
}
}

.moreButton {
display: flex;
align-items: center;
align-self: flex-start;
justify-content: center;
width: 2rem;
height: 4rem;
background-color: transparent;
border: none;
margin-left: auto;

svg {
fill: var(--red);
width: 1rem;
height: 1.5rem;
}
}

h2 {
font-size: 2.2rem;
font-weight: 600;
color: var(--black);
margin-left: 1rem;

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

.multipleMeaningList {
list-style: none;

li {
line-height: 2;
margin-bottom: 1rem;
h6 {
color: var(--orange);
font-size: 1.4rem;
filter: brightness(40%);
text-transform: lowercase;
}

p {
color: var(--orange);
font-size: 1.4rem;
font-weight: 300;
filter: brightness(40%);

&.sentence {
opacity: 0.7;
}
}

.wordLinks {
margin-top: 1rem;
button {
border: 1px solid var(--teal);
border-radius: 2rem;
height: 3rem;
color: var(--teal);
background-color: transparent;
padding: 0 1.5rem;
margin-right: 1rem;
margin-bottom: 1rem;
font-size: 1.4rem;
}
}
}
}
}

.notes {
header {
padding: 2rem;
display: flex;
align-items: center;
justify-content: space-between;

h5 {
color: var(--orange);
font-size: 1.4rem;
filter: brightness(40%);
}

button {
background-color: var(--teal);
color: white;
padding: 0.8rem 2rem;
border-radius: 3rem;
border: none;
}
}

ol {
list-style: decimal;
padding: 0 2rem 0 3.5rem;

li {
text-align: left;
color: var(--orange);
font-size: 1.4rem;
font-weight: 300;
filter: brightness(40%);
margin-bottom: 1.5rem;
}
}
}

.popupHolder {
position: fixed;
z-index: 2;
left: 0;
top: 0;
background-color: transparent;
width: 100vw;
height: 100vh;
box-shadow: 0px -10rem 20rem 10rem inset var(--creamy-white);

.background {
height: 100%;
width: 100%;
}
}

.popup {
position: absolute;
left: 0;
bottom: 0;
width: 100%;
border-top-right-radius: 3rem;
border-top-left-radius: 3rem;
overflow: hidden;
box-shadow: 0px 0px 20px -3px var(--grey);

header {
background-color: var(--orange);
display: flex;
align-items: center;
justify-content: flex-start;
padding: 2rem 2rem 6rem;

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

h5 {
font-size: 1.5rem;
font-weight: 500;
color: white;
}
}

.form {
background-color: var(--creamy-white);
border-top-right-radius: 3rem;
border-top-left-radius: 3rem;
overflow: hidden;
margin-top: -4rem;
padding: 2rem;
}

textarea {
border: none;
width: 100%;
height: 10rem;
resize: none;
display: block;
border-radius: 2rem;
box-shadow: 0px 2px 10px -5px inset var(--light-grey);
padding: 1.5rem;
font-size: 1.4rem;
background-color: var(--form-input-bg);
}

.addButton {
background-color: var(--teal);
color: white;
border-radius: 2rem;
height: 3.5rem;
width: 15rem;
font-size: 1.4rem;
font-weight: 600;
border: none;
display: flex;
align-items: center;
justify-content: center;
margin: 2rem auto 0;
}
}

+ 102
- 0
src/components/word-details/WordDetails.tsx 查看文件

@@ -0,0 +1,102 @@
import React, { useState } from "react";
import styles from './WordDetails.module.scss';

import { userProfileData } from "../../App";
import queryString from 'query-string';
import { useLocation } from "react-router-dom";
import { IShelf } from "../../structure/shelf";
import { IWord } from "../../structure/word";
import { ReactComponent as SpeakerIcon } from '../../assets/icons/speaker.svg';
import { ReactComponent as MoreIcon } from '../../assets/icons/more-alt.svg';
import { ReactComponent as ChevronLeft } from '../../assets/icons/chevron-left.svg';
import { ReactComponent as PlusIcon } from '../../assets/icons/plus.svg';

export const WordDetails: React.FC = () => {
const location = useLocation();
const category_id: any = queryString.parse(location.pathname)['/word-details/category_id'];
const shelf_id: any = queryString.parse(location.pathname)['shelf_id'];
const word_id: any = queryString.parse(location.pathname)['word_id'];
const shelf: IShelf = userProfileData.categories[category_id].shelves[shelf_id];
const word: IWord = shelf.words[word_id];
const [showAddWord, setShowAddWord] = useState<Boolean>(false);
const [newNote, setNewNote] = useState<string>('');
return <section className="modalPage">
<header className={styles.navHeader}>
<button onClick={() => window.history.back()}>
<ChevronLeft />
</button>
<h5> { shelf.name } </h5>

<figure>
{/* eslint-disable-next-line */}
<img src={ userProfileData.image } alt="profile-image" />
</figure>
</header>

<section className={styles.cardDetails}>
{ word.tag && <span className={styles.tag}> { word.tag } </span> }
<div className={styles.container}>
<button className={styles.audioButton}>
<SpeakerIcon />
</button>
<h2> { word.name } <span> { word.pronounciation } </span> </h2>
<button className={styles.moreButton}>
<MoreIcon />
</button>
</div>

<ul className={styles.multipleMeaningList}>
{ word.grammaticalDetails.map((detail, index) => {
return <li key={index}>
<h6> { detail.typeName } </h6>
<p> { detail.description } </p>
{ detail.sentence && <p className={styles.sentence}> "{ detail.sentence }" </p> }
</li>
}) }
{ word.similarWords.length > 0 && <li>
<h6> Similar: </h6>
<div className={styles.wordLinks}>
{ word.similarWords.map((similarWord, index) => <button key={index}> { similarWord } </button>) }
</div>
</li> }
</ul>
</section>

<section className={styles.notes}>
<header>
<h5> My Notes: </h5>
<button onClick={() => setShowAddWord(true)}> Add Notes </button>
</header>
{ word.notes && <ol>
{ word.notes.map((note, index) => <li> {note} </li>) }
</ol> }
</section>


{ showAddWord && <div className={styles.popupHolder}>
<div className={styles.background} onClick={() => setShowAddWord(false)}></div>
<section className={styles.popup}>
<header>
<PlusIcon />
<h5> Add Category </h5>
</header>
<section className={styles.form}>
<textarea placeholder={'Enter your notes here'} onInput={(e) => {
setNewNote(e.currentTarget.value);
}}></textarea>

<button className={styles.addButton} disabled={!newNote}
onClick={() => {
userProfileData.categories[category_id].shelves[shelf_id].words[word_id].notes?.push(newNote);
setShowAddWord(false);
}}>
Add
</button>
</section>
</section>
</div> }

</section>
}

+ 3
- 2
src/data/all-words.ts 查看文件

@@ -9,7 +9,8 @@ export const ALL_WORDS: Array<IWord> = [{
description: 'a feeling of happy satisfaction and enjoyment.'
}, {
typeName: 'ADJECTIVE',
description: 'used or intended for entertainment rather than business.'
description: 'used or intended for entertainment rather than business.',
sentence: 'She smiled with pleasure at being praised'
}],
similarWords: ['Happiness', 'Delight', 'Joy', 'Rapture', 'Glee'],
}, {
@@ -47,5 +48,5 @@ export const ALL_WORDS: Array<IWord> = [{
typeName: 'VERB',
description: 'make or cause to make a short, high-pitched ringing sound.'
}],
similarWords: [''],
similarWords: [],
}]

+ 5
- 0
src/index.css 查看文件

@@ -9,6 +9,11 @@
font-family: 'Poppins', sans-serif;
}

*:disabled {
opacity: 0.5;
pointer-events: none;
}

h1, h2, h3, h4, h5, h6 {
font-weight: 600;
}


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

@@ -2,9 +2,12 @@ export type IWord = {
name: string,
pronounciation: string,
audioPronounciationURL: string,
tag? : string,
notes? : Array<string>,
grammaticalDetails: Array<{
typeName: 'NOUN' | 'ADJECTIVE' | 'VERB' | 'ADVERB',
description: string,
sentence?: string,
}>,
similarWords: Array<string>
}

正在加载...
取消
保存