diff --git a/client/package-lock.json b/client/package-lock.json
index 48cbf7f713..d39589f1b0 100644
--- a/client/package-lock.json
+++ b/client/package-lock.json
@@ -19599,6 +19599,11 @@
}
}
},
+ "jump.js": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/jump.js/-/jump.js-1.0.1.tgz",
+ "integrity": "sha1-DeKxYxupocLGuFcq0nfYd+hQNgA="
+ },
"just-curry-it": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/just-curry-it/-/just-curry-it-3.1.0.tgz",
@@ -23347,6 +23352,15 @@
"prop-types": "^15.6.1"
}
},
+ "react-scrollable-anchor": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/react-scrollable-anchor/-/react-scrollable-anchor-0.6.1.tgz",
+ "integrity": "sha1-/W54Amx0T3ZBQFPQaQO4KtzLVNk=",
+ "requires": {
+ "jump.js": "1.0.1",
+ "prop-types": "^15.5.10"
+ }
+ },
"react-side-effect": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.0.tgz",
diff --git a/client/package.json b/client/package.json
index 962a9aedeb..82db5dbc59 100644
--- a/client/package.json
+++ b/client/package.json
@@ -61,6 +61,7 @@
"react-redux": "^5.0.7",
"react-reflex": "^3.1.1",
"react-responsive": "^6.1.1",
+ "react-scrollable-anchor": "^0.6.1",
"react-spinkit": "^3.0.0",
"react-stripe-elements": "^2.0.3",
"react-tooltip": "^4.2.13",
diff --git a/client/src/templates/Challenges/components/Challenge-Title.js b/client/src/templates/Challenges/components/Challenge-Title.js
index 2f4363b441..06db39bc0c 100644
--- a/client/src/templates/Challenges/components/Challenge-Title.js
+++ b/client/src/templates/Challenges/components/Challenge-Title.js
@@ -26,6 +26,7 @@ function ChallengeTitle({ block, children, isCompleted, superBlock }) {
@@ -36,7 +37,7 @@ function ChallengeTitle({ block, children, isCompleted, superBlock }) {
{i18next.t(
`intro:${dasherize(superBlock)}.blocks.${dasherize(block)}.title`
diff --git a/client/src/templates/Challenges/components/ChallengeTitle.test.js b/client/src/templates/Challenges/components/ChallengeTitle.test.js
index 01ed2103b1..28d96c39da 100644
--- a/client/src/templates/Challenges/components/ChallengeTitle.test.js
+++ b/client/src/templates/Challenges/components/ChallengeTitle.test.js
@@ -6,8 +6,10 @@ import renderer from 'react-test-renderer';
import ChallengeTitle from './Challenge-Title';
const baseProps = {
+ block: 'fake block',
children: 'title text',
- isCompleted: true
+ isCompleted: true,
+ superBlock: 'fake superblock'
};
describe('', () => {
diff --git a/client/src/templates/Challenges/components/__snapshots__/ChallengeTitle.test.js.snap b/client/src/templates/Challenges/components/__snapshots__/ChallengeTitle.test.js.snap
index 8f55acc75c..b2baacd3ed 100644
--- a/client/src/templates/Challenges/components/__snapshots__/ChallengeTitle.test.js.snap
+++ b/client/src/templates/Challenges/components/__snapshots__/ChallengeTitle.test.js.snap
@@ -15,7 +15,12 @@ exports[` renders correctly 1`] = `
>
renders correctly 1`] = `
/>
diff --git a/client/src/templates/Introduction/SuperBlockIntro.js b/client/src/templates/Introduction/SuperBlockIntro.js
index ce8e31cba8..8ef017faeb 100644
--- a/client/src/templates/Introduction/SuperBlockIntro.js
+++ b/client/src/templates/Introduction/SuperBlockIntro.js
@@ -8,6 +8,7 @@ import { createSelector } from 'reselect';
import { bindActionCreators } from 'redux';
import { withTranslation } from 'react-i18next';
import { Grid, Row, Col } from '@freecodecamp/react-bootstrap';
+import { configureAnchors } from 'react-scrollable-anchor';
import Login from '../../components/Header/components/Login';
import Map from '../../components/Map';
@@ -40,6 +41,7 @@ const propTypes = {
}),
isSignedIn: PropTypes.bool,
location: PropTypes.shape({
+ hash: PropTypes.string,
state: PropTypes.shape({
breadcrumbBlockClick: PropTypes.string
})
@@ -49,6 +51,8 @@ const propTypes = {
toggleBlock: PropTypes.func
};
+configureAnchors({ offset: -40, scrollDuration: 0 });
+
const mapStateToProps = state => {
return createSelector(
currentChallengeIdSelector,
@@ -71,6 +75,14 @@ const mapDispatchToProps = dispatch =>
export class SuperBlockIntroductionPage extends Component {
componentDidMount() {
this.initializeExpandedState();
+
+ setTimeout(() => {
+ configureAnchors({ offset: -40, scrollDuration: 400 });
+ }, 0);
+ }
+
+ componentWillUnmount() {
+ configureAnchors({ offset: -40, scrollDuration: 0 });
}
getChosenBlock() {
@@ -84,8 +96,15 @@ export class SuperBlockIntroductionPage extends Component {
} = this.props;
// if coming from breadcrumb click
- if (location.state && location.state.breadcrumbBlockClick)
+ if (location.state && location.state.breadcrumbBlockClick) {
return dasherize(location.state.breadcrumbBlockClick);
+ }
+
+ // if the URL includes a hash
+ if (location.hash) {
+ const dashedBlock = location.hash.replace('#', '').replace('/', '');
+ return dashedBlock;
+ }
let edge = edges[0];
@@ -146,7 +165,7 @@ export class SuperBlockIntroductionPage extends Component {
{blockDashedNames.map(blockDashedName => (
-
+ <>
- {blockDashedName !== 'project-euler' ? (
-
- ) : null}
-
+ {blockDashedName !== 'project-euler' ?
: null}
+ >
))}
{superBlock !== 'Coding Interview Prep' && (
diff --git a/client/src/templates/Introduction/components/Block.js b/client/src/templates/Introduction/components/Block.js
index 78260975a2..0e54709732 100644
--- a/client/src/templates/Introduction/components/Block.js
+++ b/client/src/templates/Introduction/components/Block.js
@@ -4,6 +4,7 @@ import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { withTranslation } from 'react-i18next';
+import ScrollableAnchor from 'react-scrollable-anchor';
import { makeExpandedBlockSelector, toggleBlock } from '../redux';
import { completedChallengesSelector, executeGA } from '../../../redux';
@@ -132,67 +133,81 @@ export class Block extends Component {
} = t('intro:misc-text');
return isProjectBlock ? (
-
-
-
{blockTitle}
- {!isAuditedCert(curriculumLocale, superBlockDashedName) && (
-
-
- {t('misc.translation-pending')}
-
-
- )}
-
- {this.renderBlockIntros(blockIntroArr)}
-
-
- ) : (
-
-
-
{blockTitle}
- {!isAuditedCert(curriculumLocale, superBlockDashedName) && (
-
-
- {t('misc.translation-pending')}
-
-
- )}
-
- {this.renderBlockIntros(blockIntroArr)}
-