Skip to content
This repository was archived by the owner on Mar 9, 2021. It is now read-only.

Commit a8fbdf2

Browse files
committed
implement chapter pages
1 parent 28def1f commit a8fbdf2

File tree

6 files changed

+227
-201
lines changed

6 files changed

+227
-201
lines changed

components/learn/subject-marked.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import React from 'react';
22
import marked from 'marked';
33
import styled from 'react-emotion';
4+
import ContentLoader from 'react-content-loader';
5+
46
import { breakpoints } from '../../utils/base.styles';
57

68
const Marked = styled.div`
@@ -101,7 +103,17 @@ export default class MarkedJS extends React.Component {
101103
return (
102104
<div>
103105
{this.props.loading ? (
104-
<div>Loading...</div>
106+
<div>
107+
<ContentLoader height={200} width={600} speed={2} primaryColor={'#f3f3f3'} secondaryColor={'#ecebeb'}>
108+
<rect x="0" y="0" rx="3" ry="3" width="600" height="10" />
109+
<rect x="0" y="20" rx="3" ry="3" width="500" height="10" />
110+
<rect x="0" y="40" rx="3" ry="3" width="600" height="10" />
111+
<rect x="0" y="60" rx="3" ry="3" width="500" height="10" />
112+
<rect x="0" y="80" rx="3" ry="3" width="600" height="10" />
113+
<rect x="0" y="100" rx="3" ry="3" width="500" height="10" />
114+
<rect x="0" y="120" rx="3" ry="3" width="500" height="10" />
115+
</ContentLoader>
116+
</div>
105117
) : (
106118
<Marked
107119
dangerouslySetInnerHTML={{
Lines changed: 78 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,93 @@
11
import React from 'react';
22
import styled from 'react-emotion';
3-
3+
import { withRouter } from 'next/router';
44
import TreeView from './syllabus-tree-component';
55

6-
export default class SyllabusTree extends React.Component {
7-
state = {
8-
nodeStateTracker: this.props.data.map(() => true),
9-
activeUnit: this.props.data[0].unit.name,
10-
activeChapter: this.props.data[0].chapters[0].url,
11-
};
6+
export default withRouter(
7+
class SyllabusTree extends React.Component {
8+
state = {
9+
nodeStateTracker: [false, ...this.props.data.map(() => true).slice(1)],
10+
activeUnit: this.props.data[0].unit,
11+
activeChapter: this.props.data[0].chapters[0].cdnUrl,
12+
};
1213

13-
handleClick = i => {
14-
this.setState({
15-
nodeStateTracker: [
16-
...this.state.nodeStateTracker.slice(0, i),
17-
!this.state.nodeStateTracker[i],
18-
...this.state.nodeStateTracker.slice(i + 1),
19-
],
20-
});
21-
};
14+
handleClick = i => {
15+
this.setState({
16+
nodeStateTracker: [
17+
...this.state.nodeStateTracker.slice(0, i),
18+
!this.state.nodeStateTracker[i],
19+
...this.state.nodeStateTracker.slice(i + 1),
20+
],
21+
});
22+
};
2223

23-
clickOnChapter(chapter, unitName) {
24-
if (chapter.url !== this.state.activeChapter) {
25-
this.setState({ activeChapter: chapter.url, activeUnit: unitName });
26-
this.props.changeChapter(chapter);
24+
clickOnChapter(chapter, unitName) {
25+
if (chapter.cdnUrl !== this.state.activeChapter) {
26+
this.setState({ activeChapter: chapter.cdnUrl, activeUnit: unitName });
27+
this.props.changeChapter(chapter);
28+
}
2729
}
28-
}
2930

30-
render() {
31-
const Container = styled.div`
32-
& .chapter {
33-
padding: 5px;
34-
font-size: 0.85rem;
35-
user-select: none;
36-
border-left: 2px solid #fff;
37-
color: #888;
38-
:hover {
31+
render() {
32+
const Container = styled.div`
33+
& .chapter {
34+
padding: 5px;
35+
font-size: 0.85rem;
36+
user-select: none;
37+
border-left: 2px solid #fff;
38+
color: #888;
39+
:hover {
40+
background-color: #f5f5f5;
41+
border-left: 2px solid #374355;
42+
cursor: pointer;
43+
}
44+
}
45+
46+
& .active {
47+
color: #374355;
3948
background-color: #f5f5f5;
4049
border-left: 2px solid #374355;
41-
cursor: pointer;
50+
:hover {
51+
cursor: default;
52+
}
4253
}
43-
}
4454
45-
& .active {
46-
color: #374355;
47-
background-color: #f5f5f5;
48-
border-left: 2px solid #374355;
49-
:hover {
50-
cursor: default;
55+
& .unit_name {
56+
order: 1;
57+
flex: 1 1 auto;
58+
align-self: auto;
5159
}
52-
}
60+
`;
5361

54-
& .unit_name {
55-
order: 1;
56-
flex: 1 1 auto;
57-
align-self: auto;
58-
}
59-
`;
60-
61-
return (
62-
<Container>
63-
{this.props.data.map((unitNode, i) => {
64-
const UnitNameComponent = (
65-
<div className="unit_name" key={unitNode.unit.name} onClick={() => this.handleClick(i)}>
66-
{unitNode.unit.name}
67-
</div>
68-
);
69-
return (
70-
<TreeView
71-
key={i}
72-
unitName={unitNode.unit.name}
73-
UnitNameComponent={UnitNameComponent}
74-
activeUnit={this.state.activeUnit}
75-
collapsed={this.state.nodeStateTracker[i]}
76-
onClick={() => this.handleClick(i)}>
77-
{unitNode.chapters.map(chapter => (
78-
<div
79-
className={`chapter ${this.state.activeChapter === chapter.url ? 'active' : ''}`}
80-
key={chapter.url}
81-
onClick={() => this.clickOnChapter(chapter, unitNode.unit.name)}>
82-
{chapter.name}
83-
</div>
84-
))}
85-
</TreeView>
86-
);
87-
})}
88-
</Container>
89-
);
62+
return (
63+
<Container>
64+
{this.props.data.map((unitNode, i) => {
65+
const UnitNameComponent = (
66+
<div className="unit_name" key={unitNode.unit} onClick={() => this.handleClick(i)}>
67+
{unitNode.unit}
68+
</div>
69+
);
70+
return (
71+
<TreeView
72+
key={i}
73+
unitName={unitNode.unit}
74+
UnitNameComponent={UnitNameComponent}
75+
activeUnit={this.state.activeUnit}
76+
collapsed={this.state.nodeStateTracker[i]}
77+
onClick={() => this.handleClick(i)}>
78+
{unitNode.chapters.map(chapter => (
79+
<div
80+
className={`chapter ${this.state.activeChapter === chapter.cdnUrl ? 'active' : ''}`}
81+
key={chapter.cdnUrl}
82+
onClick={() => this.clickOnChapter(chapter, unitNode.unit)}>
83+
{chapter.name}
84+
</div>
85+
))}
86+
</TreeView>
87+
);
88+
})}
89+
</Container>
90+
);
91+
}
9092
}
91-
}
93+
);

pages/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ export default () => (
222222
<Box width={1}>
223223
<Flex justify="space-around" align="center" wrap>
224224
{take(listOfSubjects, 4).map(subject => {
225-
return <SubjectCard key={subject.url} subject={subject} />;
225+
return <SubjectCard key={subject.path} subject={subject} />;
226226
})}
227227
</Flex>
228228
</Box>

pages/learn/subject.js

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
import React from 'react';
2+
import Router from 'next/router';
23
import fetch from 'isomorphic-unfetch';
34
import styled from 'react-emotion';
45
import { space } from 'styled-system';
56
import { Flex, Box } from 'grid-emotion';
67
import ExpandTOC from 'react-icons/lib/fa/angle-double-right';
78
import CollapseTOC from 'react-icons/lib/fa/angle-double-left';
89

9-
import { baseContainer, Title, breakpoints } from '../../utils/base.styles';
10+
import { baseContainer, breakpoints } from '../../utils/base.styles';
1011
import Layout from '../../components/common/layout';
1112
import BannerSection from '../../components/learn/subject-banner';
1213
import SyllabusTree from '../../components/learn/syllabus-tree/syllabus-tree-container';
1314
import SubjectMarkdown from '../../components/learn/subject-marked';
1415

15-
import { laravelSyllabus, reactSyllabus } from '../../utils/mock-data';
16+
import { laravelSyllabus, reactSyllabus, listOfSubjects } from '../../utils/mock-data';
1617

1718
const CurriculumSection = styled.section`
1819
${baseContainer};
@@ -60,12 +61,9 @@ export default class Subject extends React.Component {
6061
constructor(props) {
6162
super(props);
6263
this.state = {
63-
activeSubject: this.selectSubject(this.props.url.query.id),
64+
activeSubject: this.selectSubject(this.props.url.query.subject),
6465
activeChapterContent: '',
65-
activeChapterName:
66-
this.selectSubject(this.props.url.query.id) === null
67-
? ''
68-
: this.selectSubject(this.props.url.query.id)[0].chapters[0].name,
66+
activeChapterName: '',
6967
loading: true,
7068
isSidebarOpen: true,
7169
};
@@ -81,24 +79,49 @@ export default class Subject extends React.Component {
8179
return null;
8280
}
8381
}
82+
selectChapter(syllabus, chapterName) {
83+
return syllabus
84+
.map(item => {
85+
return item.chapters.find(chapter => chapter.name === chapterName);
86+
})
87+
.filter(Boolean)[0];
88+
}
8489

85-
componentDidMount() {
86-
if (this.state.activeSubject !== null) {
87-
const defaultChapter = this.state.activeSubject[0].chapters[0];
88-
this.getChapterContent(defaultChapter);
90+
getChapter(subject, chapter) {
91+
const activeSubject = this.selectSubject(subject);
92+
const activeChapterName = chapter.replace('-', ' ');
93+
if (activeSubject !== null) {
94+
this.setState({
95+
activeChapterName,
96+
activeSubject,
97+
});
98+
const activeChapterUrl = this.selectChapter(activeSubject, activeChapterName).cdnUrl;
99+
this.getChapterContent(activeChapterUrl);
89100
}
90101
}
91102

103+
componentDidMount() {
104+
const { subject, chapter } = this.props.url.query;
105+
this.getChapter(subject, chapter);
106+
}
107+
108+
componentWillReceiveProps(nextProps) {
109+
const { subject, chapter } = nextProps.url.query;
110+
this.getChapter(subject, chapter);
111+
}
112+
92113
changeChapter = selectedChapter => {
114+
const subjectName = this.props.url.query.subject;
115+
const chapterName = selectedChapter.name.replace(' ', '-');
116+
Router.push(`/learn/subject?subject=${subjectName}&chapter=${chapterName}`, `/learn/${subjectName}/${chapterName}`);
117+
};
118+
119+
async getChapterContent(chapterUrl) {
93120
this.setState({
121+
activeChapterContent: '',
94122
loading: true,
95-
activeChapterName: selectedChapter.name,
96123
});
97-
this.getChapterContent(selectedChapter);
98-
};
99-
100-
async getChapterContent(chapter) {
101-
const activeChapterContentPromise = await fetch(chapter.url);
124+
const activeChapterContentPromise = await fetch(chapterUrl);
102125
const activeChapterContent = await activeChapterContentPromise.text();
103126
await this.setState({
104127
activeChapterContent,
@@ -107,17 +130,23 @@ export default class Subject extends React.Component {
107130
}
108131

109132
render() {
133+
const subjectIcon = listOfSubjects.find(item => item.subjectId === this.props.url.query.subject).icon;
110134
return this.state.activeSubject === null ? (
111135
<Layout>
112-
<Title inverted>Curriculum for {this.props.url.query.id} and others Coming soon!!</Title>
136+
<BannerSection
137+
textInverted
138+
title={this.props.url.query.subject.toUpperCase()}
139+
subTitle={`Curriculum for ${this.props.url.query.subject.toUpperCase()} and others Coming soon!!`}
140+
icon={subjectIcon}
141+
/>
113142
</Layout>
114143
) : (
115144
<Layout>
116145
<BannerSection
117146
textInverted
118-
title={this.props.url.query.id.toUpperCase()}
147+
title={this.props.url.query.subject.toUpperCase()}
119148
subTitle="Web Development"
120-
icon="devicon-laravel-plain colored"
149+
icon={subjectIcon}
121150
/>
122151
<CurriculumSection my={[0, 4]}>
123152
<Flex column={false}>

server.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const dev = process.env.NODE_ENV !== 'production';
99
const app = next({ dev });
1010
const handle = app.getRequestHandler();
1111
const route = pathMatch();
12-
const match = route('/learn/:id');
12+
const match = route('/learn/:subject/:chapter');
1313

1414
getPort({ port: 3000 }).then(port => {
1515
app.prepare().then(() => {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy