Thanks to visit codestin.com
Credit goes to github.com

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)