fix: all things (#124)

* fix 'Testing with Chai' 404 error

* Remove service worker and unregister old workers from clients

* Fix block name in QA and Chai intro

* Move the map to the index page

* Split test commands, have travis run format on test

* Only expand the first block

* Remove some margin from p tags on the index page

* Learn -> Curriculum link in header

* UI Fixes

* Use webpack plugin to destroy sercive worker

* Add spinner for unknown user state

* Fix map placement

* Fix vcurriculum button clicks
This commit is contained in:
mrugesh mohapatra
2018-06-01 03:36:42 +05:30
committed by Mrugesh Mohapatra
parent 6aff2bbe42
commit 910dd0584c
38 changed files with 330 additions and 341 deletions

View File

@@ -6,3 +6,4 @@ node_js:
cache:
directories:
- "node_modules"
script: "yarn test:ci"

View File

@@ -68,7 +68,6 @@ module.exports = {
fonts: ['Lato:400,400i,500']
}
},
'gatsby-plugin-sitemap',
'gatsby-plugin-offline'
'gatsby-plugin-sitemap'
]
};

View File

@@ -104,6 +104,7 @@ exports.createPages = ({ graphql, boundActionCreators }) => {
};
const webpack = require('webpack');
const RmServiceWorkerPlugin = require('webpack-remove-serviceworker-plugin');
const generateBabelConfig = require('gatsby/dist/utils/babel-config');
exports.modifyWebpackConfig = ({ config, stage }) => {
@@ -143,6 +144,9 @@ exports.modifyWebpackConfig = ({ config, stage }) => {
)
}
]);
config.plugin('RemoveServiceWorkerPlugin', RmServiceWorkerPlugin, [
{ filename: 'sw.js' }
]);
});
};
/* eslint-disable prefer-object-spread/prefer-object-spread */

View File

@@ -23,7 +23,6 @@
"gatsby": "^1.9.243",
"gatsby-link": "^1.6.39",
"gatsby-plugin-google-fonts": "^0.0.4",
"gatsby-plugin-offline": "^1.0.15",
"gatsby-plugin-react-helmet": "^2.0.8",
"gatsby-plugin-react-next": "^1.0.11",
"gatsby-plugin-sitemap": "^1.2.21",
@@ -48,6 +47,7 @@
"react-redux": "^5.0.7",
"react-reflex": "^2.2.1",
"react-router-redux": "^5.0.0-alpha.9",
"react-spinkit": "^3.0.0",
"react-test-renderer": "^16.3.1",
"redux": "^3.7.2",
"redux-actions": "^2.3.0",
@@ -57,7 +57,8 @@
"rxjs": "^5.5.7",
"store": "^2.0.12",
"uglifyjs-webpack-plugin": "^1.2.4",
"validator": "^9.4.1"
"validator": "^9.4.1",
"webpack-remove-serviceworker-plugin": "^1.0.0"
},
"keywords": [
"gatsby"
@@ -77,7 +78,8 @@
"lint:src": "eslint ./src . --fix",
"lint:utils": "eslint ./utils . --fix",
"pretty": "yarn format && yarn lint",
"test": "yarn format && jest src",
"test": "jest src",
"test:ci": "yarn format && jest src",
"test:watch": "jest --watch src"
},
"jest": {

View File

@@ -2,24 +2,45 @@ import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import Spinner from 'react-spinkit';
import { isSignedInSelector } from '../../../redux/app';
import {
isSignedInSelector,
userStateLoadingSelector
} from '../../../redux/app';
import Login from './Login';
import SignedIn from './SignedIn';
const mapStateToProps = createSelector(isSignedInSelector, isSignedIn => ({
isSignedIn
}));
const mapStateToProps = createSelector(
userStateLoadingSelector,
isSignedInSelector,
(showLoading, isSignedIn) => ({
isSignedIn,
showLoading
})
);
const propTypes = {
email: PropTypes.string,
isSignedIn: PropTypes.bool,
name: PropTypes.string
name: PropTypes.string,
showLoading: PropTypes.bool
};
class UserState extends PureComponent {
render() {
const { isSignedIn } = this.props;
const { isSignedIn, showLoading } = this.props;
if (showLoading) {
return (
<Spinner
className='user-state-spinner'
color='white'
fadeIn='none'
height='40px'
name='line-scale'
/>
);
}
return isSignedIn ? <SignedIn /> : <Login />;
}
}

View File

@@ -70,6 +70,13 @@ header {
font-weight: 500;
}
.user-state-spinner {
height: 40px;
}
.user-state-spinner > div {
animation-duration: 1.5s !important;
}
/* Search bar */
.fcc_searchBar {

View File

@@ -17,7 +17,7 @@ function Header() {
<FCCSearch />
<ul id='top-right-nav'>
<li>
<a href='https://learn.freecodecamp.org'>Learn</a>
<Link to='/'>Curriculum</Link>
</li>
<li>
<a href='https://forum.freecodecamp.org'>Forum</a>

View File

@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import Link, { navigateTo } from 'gatsby-link';
import Link from 'gatsby-link';
import ga from '../../../analytics';
import { makeExpandedBlockSelector, toggleBlock } from '../redux';
@@ -57,17 +57,12 @@ export class Block extends PureComponent {
}
handleBlockClick() {
const { blockDashedName, challenges, toggleBlock } = this.props;
const blockPath = challenges[0].fields.slug
.split('/')
.slice(0, -1)
.join('/');
toggleBlock(blockDashedName);
const { blockDashedName, toggleBlock } = this.props;
ga.event({
category: 'Map Block Click',
action: blockDashedName
});
return navigateTo(blockPath);
return toggleBlock(blockDashedName);
}
handleChallengeClick(slug) {
@@ -80,7 +75,7 @@ export class Block extends PureComponent {
};
}
renderChallenges(intro, challenges) {
renderChallenges(intro = {}, challenges = []) {
// TODO: Split this into a Challenge Component and add tests
// TODO: The styles badge and map-badge on the completion span do not exist
return [intro].concat(challenges).map(challenge => {

View File

@@ -45,6 +45,14 @@ const propTypes = {
toggleSuperBlock: PropTypes.func.isRequired
};
const codingPrepRE = new RegExp('Interview Prep');
function createSuperBlockTitle(str) {
return codingPrepRE.test(str)
? `${str} (Thousands of hours of challenges)`
: `${str} Certification (300 hours)`;
}
export class SuperBlock extends PureComponent {
renderBlock(superBlock) {
const { nodes, introNodes } = this.props;
@@ -54,7 +62,6 @@ export class SuperBlock extends PureComponent {
const blockDashedNames = uniq(
blocksForSuperBlock.map(({ block }) => block)
);
return (
<ul>
{blockDashedNames.map(blockDashedName => (
@@ -84,7 +91,7 @@ export class SuperBlock extends PureComponent {
<li className={`superblock ${isExpanded ? 'open' : ''}`}>
<div className='map-title' onClick={() => toggleSuperBlock(superBlock)}>
<Caret />
<h4>{superBlock}</h4>
<h4>{createSuperBlockTitle(superBlock)}</h4>
</div>
{isExpanded ? this.renderBlock(superBlock) : null}
</li>

View File

@@ -61,7 +61,7 @@ test('<SuperBlock should handle toggle clicks correctly', () => {
.find('.map-title')
.find('h4')
.text()
).toBe('Super Block One');
).toBe('Super Block One Certification (300 hours)');
expect(enzymeWrapper.find('ul').length).toBe(0);
enzymeWrapper.find('.map-title').simulate('click');
@@ -76,6 +76,6 @@ test('<SuperBlock should handle toggle clicks correctly', () => {
.find('.map-title')
.find('h4')
.text()
).toBe('Super Block One');
).toBe('Super Block One Certification (300 hours)');
expect(enzymeWrapper.find('ul').length).toBe(1);
});

View File

@@ -10,7 +10,7 @@ exports[`<SuperBlock /> expanded snapshot: superBlock-expanded 1`] = `
>
<Caret />
<h4>
Super Block One
Super Block One Certification (300 hours)
</h4>
</div>
<ul>
@@ -147,7 +147,7 @@ exports[`<SuperBlock /> not expanded snapshot: superBlock-not-expanded 1`] = `
>
<Caret />
<h4>
Super Block One
Super Block One Certification (300 hours)
</h4>
</div>
</li>

View File

@@ -1,6 +1,7 @@
.map-ui {
height: 100%;
max-height: calc(100vh - (45px + 1.45rem));
margin-left: 35px;
}
.map-ui ul {

View File

@@ -8,8 +8,12 @@ export const getNS = () => ns;
const initialState = {
expandedState: {
superBlock: {},
block: {}
superBlock: {
'Responsive Web Design': true
},
block: {
'basic-html-and-html5': true
}
}
};

View File

@@ -1,3 +1,4 @@
.util-spacer {
margin: 5px 0px;
height: 1px;
}

View File

@@ -1,6 +1,6 @@
---
title: Introduction to the Quality Assurance with Chai Challenges
block: Quality Assurance with Chai
block: Quality Assurance and Testing with Chai
superBlock: Information Security and Quality Assurance
---
## Introduction to Quality Assurance with Chai Challenges

View File

@@ -1,4 +1,3 @@
/* global graphql */
import React, { Fragment, PureComponent } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
@@ -7,9 +6,7 @@ import Helmet from 'react-helmet';
import ga from '../analytics';
import { AllChallengeNode } from '../redux/propTypes';
import Header from '../components/Header';
import MapModal from '../components/MapModal';
import { fetchUser } from '../redux/app';
import 'prismjs/themes/prism.css';
@@ -47,7 +44,6 @@ const mapDispatchToProps = dispatch =>
const propTypes = {
children: PropTypes.func,
data: AllChallengeNode,
fetchUser: PropTypes.func.isRequired
};
@@ -79,13 +75,7 @@ class Layout extends PureComponent {
}
}
render() {
const {
children,
data: {
allChallengeNode: { edges },
allMarkdownRemark: { edges: mdEdges }
}
} = this.props;
const { children } = this.props;
return (
<Fragment>
<Helmet
@@ -103,12 +93,6 @@ class Layout extends PureComponent {
<div className='app-wrapper'>
<main>{children()}</main>
</div>
<MapModal
introNodes={mdEdges.map(({ node }) => node)}
nodes={edges
.map(({ node }) => node)
.filter(({ isPrivate }) => !isPrivate)}
/>
</Fragment>
);
}
@@ -117,41 +101,3 @@ class Layout extends PureComponent {
Layout.propTypes = propTypes;
export default connect(mapStateToProps, mapDispatchToProps)(Layout);
export const query = graphql`
query LayoutQuery {
allChallengeNode(
filter: { isPrivate: { eq: false } }
sort: { fields: [superOrder, order, suborder] }
) {
edges {
node {
fields {
slug
blockName
}
id
block
title
isRequired
isPrivate
superBlock
dashedName
}
}
}
allMarkdownRemark(filter: { frontmatter: { block: { ne: null } } }) {
edges {
node {
frontmatter {
title
block
}
fields {
slug
}
}
}
}
}
`;

View File

@@ -23,5 +23,5 @@ main {
.app-wrapper {
margin-top: 38px;
height: calc(100vh - 80px);
height: calc(100vh - 38px);
}

View File

@@ -6,3 +6,7 @@
max-width: 960px;
margin: 0 auto;
}
.index-page-wrapper p {
margin-bottom: 0.75rem;
}

View File

@@ -1,15 +1,20 @@
/* global graphql */
/* eslint-disable max-len */
import React from 'react';
import PropTypes from 'prop-types';
import Link from 'gatsby-link';
import Helmet from 'react-helmet';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { Button } from 'react-bootstrap';
import { ChallengeNode } from '../redux/propTypes';
import {
ChallengeNode,
AllChallengeNode,
AllMarkdownRemark
} from '../redux/propTypes';
import { toggleMapModal } from '../redux/app';
import Spacer from '../components/util/Spacer';
import Map from '../components/Map';
import './index.css';
@@ -20,14 +25,19 @@ const mapDispatchToProps = dispatch =>
const propTypes = {
data: PropTypes.shape({
challengeNode: ChallengeNode
challengeNode: ChallengeNode,
allChallengeNode: AllChallengeNode,
allMarkdownRemark: AllMarkdownRemark
}),
toggleMapModal: PropTypes.func.isRequired
};
const IndexPage = ({
data: { challengeNode: { title, fields: { slug, blockName } } },
toggleMapModal
data: {
challengeNode: { fields: { slug } },
allChallengeNode: { edges },
allMarkdownRemark: { edges: mdEdges }
}
}) => (
<div className='index-page-wrapper'>
<Helmet title='Welcome to learn.freeCodeCamp!' />
@@ -35,27 +45,25 @@ const IndexPage = ({
<Spacer />
<h2>Welcome to the freeCodeCamp curriculum</h2>
<p>We have thousands of coding lessons to help you improve your skills.</p>
<p>You can earn each certification by completing its 5 final projects.</p>
<p>
You can earn verified certifications by completing each sections 6
required projects.
</p>
<p>
{'And yes - all of this is 100% free, thanks to the thousands of ' +
'campers who '}
And yes - all of this is 100% free, thanks to the thousands of campers who{' '}
<a href='https://donate.freecodecamp.org' target='_blank'>
donate
</a>{' '}
to our nonprofit.
</p>
<h3>Not sure where to start?</h3>
<p>
We recommend you start at the beginning{' '}
<Link to={slug}>{`${blockName} -> ${title}`}</Link>
If you are new to coding, we recommend you{' '}
<Link to={slug}>start at the beginning</Link>.
</p>
<h3>Want to dive into our curriculum?</h3>
<Button block={true} bsSize='lg' bsStyle='primary' onClick={toggleMapModal}>
Explore the curriculum
</Button>
<Spacer />
<Map
introNodes={mdEdges.map(({ node }) => node)}
nodes={edges
.map(({ node }) => node)
.filter(({ isPrivate }) => !isPrivate)}
/>
</div>
);
@@ -67,11 +75,42 @@ export default connect(mapStateToProps, mapDispatchToProps)(IndexPage);
export const query = graphql`
query FirstChallenge {
challengeNode(order: { eq: 0 }, suborder: { eq: 1 }) {
title
fields {
slug
}
}
allChallengeNode(
filter: { isPrivate: { eq: false } }
sort: { fields: [superOrder, order, suborder] }
) {
edges {
node {
fields {
slug
blockName
}
id
block
title
isRequired
isPrivate
superBlock
dashedName
}
}
}
allMarkdownRemark(filter: { frontmatter: { block: { ne: null } } }) {
edges {
node {
frontmatter {
title
block
}
fields {
slug
}
}
}
}
}
`;

View File

@@ -1,18 +1,26 @@
/* global HOME_PATH */
import { of } from 'rxjs/observable/of';
import { merge } from 'rxjs/observable/merge';
import { ofType } from 'redux-observable';
import { types, fetchUserComplete, hardGoTo } from './';
import {
types,
fetchUserComplete,
fetchUserError,
noUserFound,
hardGoTo
} from './';
import {
switchMap,
filter,
map,
catchError,
defaultIfEmpty
defaultIfEmpty,
mapTo
} from 'rxjs/operators';
import { jwt } from '../cookieVaules';
function fetchUserEpic(action$, _, { services }) {
return action$.pipe(
const fetchUser = action$.pipe(
ofType(types.fetchUser),
filter(() => !!jwt),
switchMap(() => {
@@ -25,14 +33,20 @@ function fetchUserEpic(action$, _, { services }) {
}
return fetchUserComplete(response);
}),
defaultIfEmpty({ type: 'no-user' }),
catchError(err => {
console.log(err);
return of({ type: 'fetch-user-error' });
defaultIfEmpty(noUserFound()),
catchError(() => {
return of(fetchUserError());
})
);
})
);
const isLoadingRequired = action$.pipe(
ofType(types.fetchUser),
filter(() => !jwt),
mapTo(noUserFound())
);
return merge(fetchUser, isLoadingRequired);
}
export default fetchUserEpic;

View File

@@ -14,6 +14,7 @@ export const types = createTypes(
'fetchUser',
'fetchUserComplete',
'fetchUserError',
'noUserFound',
'hardGoTo',
'updateUserSignedIn',
'toggleMapModal'
@@ -23,6 +24,7 @@ export const types = createTypes(
const initialState = {
appUsername: '',
showLoading: true,
isSignedIn: false,
user: {},
showMapModal: false
@@ -30,7 +32,8 @@ const initialState = {
export const fetchUser = createAction(types.fetchUser);
export const fetchUserComplete = createAction(types.fetchUserComplete);
export const fecthUserError = createAction(types.fetchUserError);
export const fetchUserError = createAction(types.fetchUserError);
export const noUserFound = createAction(types.noUserFound);
export const hardGoTo = createAction(types.hardGoTo);
@@ -41,6 +44,7 @@ export const updateUserSignedIn = createAction(types.updateUserSignedIn);
export const isMapModalOpenSelector = state => state[ns].showMapModal;
export const isSignedInSelector = state => state[ns].isSignedIn;
export const userSelector = state => state[ns].user || {};
export const userStateLoadingSelector = state => state[ns].showLoading;
export const completedChallengesSelector = state =>
state[ns].user.completedChallenges || [];
export const currentChallengeIdSelector = state =>
@@ -55,8 +59,11 @@ export const reducer = handleActions(
...state,
appUsername: result,
user: user[result],
showLoading: false,
isSignedIn: !!Object.keys(user).length
}),
[types.fetchUserError]: state => ({ ...state, showLoading: false }),
[types.noUserFound]: state => ({ ...state, showLoading: false }),
[types.toggleMapModal]: state => ({
...state,
showMapModal: !state.showMapModal

View File

@@ -63,3 +63,11 @@ export const AllChallengeNode = PropTypes.shape({
})
)
});
export const AllMarkdownRemark = PropTypes.shape({
edges: PropTypes.arrayOf(
PropTypes.shape({
node: MarkdownRemark
})
)
});

View File

@@ -119,7 +119,6 @@ export class BackEnd extends PureComponent {
const blockNameTitle = `${blockName} - ${title}`;
return (
<Row>
<ProjectToolPanel />
<Col xs={6} xsOffset={3}>
<Spacer />
<div>
@@ -134,6 +133,7 @@ export class BackEnd extends PureComponent {
options={options}
submit={executeChallenge}
/>
<ProjectToolPanel />
</div>
<div>
<br />

View File

@@ -10,7 +10,6 @@ import { ReflexContainer, ReflexSplitter, ReflexElement } from 'react-reflex';
import Editor from './Editor';
import Preview from '../components/Preview';
import SidePanel from '../components/Side-Panel';
import TestSuite from '../components/Test-Suite';
import Output from '../components/Output';
import CompletionModal from '../components/CompletionModal';
import HelpModal from '../components/HelpModal';
@@ -32,8 +31,6 @@ import {
} from '../redux';
import './classic.css';
import ToolPanel from '../components/Tool-Panel';
import Spacer from '../../../components/util/Spacer';
const mapStateToProps = createSelector(
challengeFilesSelector,
@@ -157,7 +154,6 @@ class ShowClassic extends PureComponent {
}
render() {
// console.log(this.state)
const {
data: {
challengeNode: {
@@ -169,7 +165,6 @@ class ShowClassic extends PureComponent {
}
},
files,
tests,
output
} = this.props;
const editors = Object.keys(files)
@@ -202,9 +197,7 @@ class ShowClassic extends PureComponent {
<Output
defaultOutput={`
/**
* Your output will go here.
* Any console.log() statements
* will appear in here as well.
* Your test output will go here.
*/
`}
output={output}
@@ -220,12 +213,12 @@ class ShowClassic extends PureComponent {
return (
<Fragment>
<Helmet title={`${blockNameTitle} | Learn freeCodeCamp`} />
<ToolPanel guideUrl={guideUrl} />
<ReflexContainer orientation='vertical'>
<ReflexElement flex={1} {...this.resizeProps}>
<SidePanel
className='full-height'
description={description}
guideUrl={guideUrl}
title={blockNameTitle}
/>
</ReflexElement>
@@ -234,16 +227,14 @@ class ShowClassic extends PureComponent {
{editors}
</ReflexElement>
<ReflexSplitter propagate={true} {...this.resizeProps} />
<ReflexElement flex={0.5} {...this.resizeProps}>
{showPreview ? (
<ReflexElement flex={0.7} {...this.resizeProps}>
<Preview
className='full-height'
disableIframe={this.state.resizing}
/>
) : null}
<Spacer />
<TestSuite tests={tests} />
</ReflexElement>
) : null}
</ReflexContainer>
<CompletionModal />

View File

@@ -6,11 +6,16 @@ import { bindActionCreators } from 'redux';
import ChallengeTitle from './Challenge-Title';
import ChallengeDescription from './Challenge-Description';
import ToolPanel from './Tool-Panel';
import TestSuite from './Test-Suite';
import Spacer from '../../../components/util/Spacer';
import { initConsole } from '../redux';
import { initConsole, challengeTestsSelector } from '../redux';
import { createSelector } from 'reselect';
const mapStateToProps = () => ({});
const mapStateToProps = createSelector(challengeTestsSelector, tests => ({
tests
}));
const mapDispatchToProps = dispatch =>
bindActionCreators(
@@ -22,7 +27,9 @@ const mapDispatchToProps = dispatch =>
const propTypes = {
description: PropTypes.arrayOf(PropTypes.string),
guideUrl: PropTypes.string,
initConsole: PropTypes.func.isRequired,
tests: PropTypes.arrayOf(PropTypes.object),
title: PropTypes.string
};
@@ -52,7 +59,7 @@ export class SidePanel extends PureComponent {
}
render() {
const { title, description } = this.props;
const { title, description, guideUrl, tests } = this.props;
return (
<div className='instructions-panel' role='complementary'>
<div ref={this.bindTopDiv} />
@@ -61,7 +68,9 @@ export class SidePanel extends PureComponent {
<ChallengeTitle>{title}</ChallengeTitle>
<ChallengeDescription description={description} />
</div>
<Spacer />
<hr />
<ToolPanel guideUrl={guideUrl} />
<TestSuite tests={tests} />
</div>
);
}

View File

@@ -2,7 +2,8 @@ import React from 'react';
import PropTypes from 'prop-types';
import GreenPass from './icons/GreenPass';
import RedFail from './icons/RedFail';
import Fail from './icons/Fail';
import Initial from './icons/Initial';
import './test-suite.css';
@@ -28,6 +29,8 @@ function TestSuite({ tests }) {
return (
<div className='challenge-test-suite'>
{tests.map(({ err, pass = false, text = '' }, index) => {
const isInitial = !pass && !err;
const statusIcon = pass && !err ? <GreenPass /> : <Fail />;
return (
<div
aria-label={getAccessibleText(err, pass, text)}
@@ -36,7 +39,7 @@ function TestSuite({ tests }) {
tabIndex='0'
>
<div className='test-status-icon'>
{pass ? <GreenPass /> : <RedFail />}
{isInitial ? <Initial /> : statusIcon}
</div>
<div
aria-hidden='true'

View File

@@ -1,4 +1,4 @@
import React from 'react';
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
@@ -7,7 +7,6 @@ import { Button } from 'react-bootstrap';
import './tool-panel.css';
import { openModal, executeChallenge } from '../redux';
import { toggleMapModal } from '../../../redux/app';
const mapStateToProps = () => ({});
const mapDispatchToProps = dispatch =>
@@ -15,8 +14,7 @@ const mapDispatchToProps = dispatch =>
{
executeChallenge,
openHelpModal: () => openModal('help'),
openResetModal: () => openModal('reset'),
toggleMapModal
openResetModal: () => openModal('reset')
},
dispatch
);
@@ -25,37 +23,29 @@ const propTypes = {
executeChallenge: PropTypes.func.isRequired,
guideUrl: PropTypes.string,
openHelpModal: PropTypes.func.isRequired,
openResetModal: PropTypes.func.isRequired,
toggleMapModal: PropTypes.func.isRequired
openResetModal: PropTypes.func.isRequired
};
function ToolPanel({
executeChallenge,
openHelpModal,
openResetModal,
toggleMapModal,
guideUrl
}) {
return (
<div className='tool-panel'>
<div id='left-tool-panel'>
<Button
bsStyle='primary'
className='btn-primary-invert'
onClick={toggleMapModal}
>
View the Curriculum
</Button>
</div>
<div id='centre-tool-panel'>
<Button bsStyle='primary' onClick={executeChallenge}>
<Fragment>
<div className='tool-panel-group'>
<Button block={true} bsStyle='primary' onClick={executeChallenge}>
Run the Tests
</Button>
<Button bsStyle='default' onClick={openResetModal}>
<Button
block={true}
bsStyle='primary'
className='btn-primary-invert'
onClick={openResetModal}
>
Reset All Code
</Button>
</div>
<div id='right-tool-panel'>
{guideUrl ? (
<Button
block={true}
@@ -76,7 +66,7 @@ function ToolPanel({
Ask for help
</Button>
</div>
</div>
</Fragment>
);
}

View File

@@ -1,7 +1,5 @@
import React from 'react';
const propTypes = {};
function RedFail() {
return (
<svg
@@ -15,9 +13,9 @@ function RedFail() {
<circle
cx='100'
cy='99'
fill='#ff0000'
fill='#555'
r='95'
stroke='#ff0000'
stroke='#555'
strokeDasharray='null'
strokeLinecap='null'
strokeLinejoin='null'
@@ -52,6 +50,5 @@ function RedFail() {
}
RedFail.displayName = 'RedFail';
RedFail.propTypes = propTypes;
export default RedFail;

View File

@@ -1,7 +1,5 @@
import React from 'react';
const propTypes = {};
function GreenPass(props) {
return (
<svg
@@ -53,6 +51,5 @@ function GreenPass(props) {
}
GreenPass.displayName = 'GreenPass';
GreenPass.propTypes = propTypes;
export default GreenPass;

View File

@@ -0,0 +1,55 @@
import React from 'react';
function Initial(props) {
return (
<svg
height='50'
viewBox='0 0 200 200'
width='50'
xmlns='http://www.w3.org/2000/svg'
{...props}
>
<g>
<title>Initial</title>
<circle
cx='100'
cy='99'
fill='#555'
r='95'
stroke='#555'
strokeDasharray='null'
strokeLinecap='null'
strokeLinejoin='null'
/>
<svg
height='200'
viewBox='-13 -12 50 50'
width='200'
xmlns='http://www.w3.org/2000/svg'
>
<path
d={
'M8 1c0-.552.448-1 1-1h6c.553 0 1 .448 1 1s-.447 1-1 1h-6c-' +
'.552 0-1-.448-1-1zm13 20.554c0 1.284-1.023 2.446-2.424 ' +
'2.446h-13.153c-1.4 0-2.423-1.162-2.423-2.445 0-.35.076-.709.' +
'242-1.057l3.743-7.856c1.04-2.186 2.015-4.581 2.015-7.007v-1.' +
'635h2l-.006 2c-.087 2.623-1.09 5.092-1.973 7h3.682l4.377 9h1.' +
'496c.309 0 .52-.342.377-.644l-3.743-7.854c-1.046-2.197-2.12-4' +
'.791-2.21-7.502v-2h2v1.635c0 2.426.975 4.82 2.016 7.006l3.743' +
' 7.856c.165.348.241.707.241 1.057zm-12-1.054c0-.829-.671-1.5-' +
'1.5-1.5s-1.5.671-1.5 1.5.671 1.5 1.5 1.5 1.5-.671 1.5-1.5zm2-' +
'3.5c0-.553-.448-1-1-1-.553 0-1 .447-1 1s.447 1 1 1c.552 0 1-.' +
'447 1-1zm3 3c0-.552-.448-1-1-1s-1 .448-1 1 .448 1 1 1 1-.448 ' +
'1-1z'
}
fill='#fff'
/>
</svg>
</g>
</svg>
);
}
Initial.displayName = 'Initial';
export default Initial;

View File

@@ -6,7 +6,7 @@
}
.challenge-preview, .challenge-preview-frame {
height: calc(60vh);
height: calc(100vh - 40px);
width: 100%;
padding: 0;
margin: 0;

View File

@@ -2,6 +2,7 @@
display: flex;
justify-content: flex-start;
flex-direction: column;
margin-top: 15px;
}
.test-result {

View File

@@ -1,22 +1,8 @@
.tool-panel {
height: 40px;
display: flex;
justify-content: space-around;
align-items: center;
background-color: #99C199;
.tool-panel-group button, .tool-panel-group a {
font-size: 1.1rem;
}
#centre-tool-panel {
width: 300px;
}
#right-tool-panel {
display: flex;
justify-content: center;
align-items: center;
}
#right-tool-panel a, #right-tool-panel .btn-block {
margin: 0;
.project-tool-panel {
width: 100%;
padding: 0 15px;
}

View File

@@ -24,6 +24,7 @@ import {
import { frontEndProject } from '../../../../utils/challengeTypes';
import './project.css';
import Spacer from '../../../components/util/Spacer';
const mapStateToProps = () => ({});
const mapDispatchToProps = dispatch =>
@@ -106,7 +107,6 @@ export class Project extends PureComponent {
return (
<Fragment>
<Helmet title={`${blockNameTitle} | Learn freeCodeCamp}`} />
<ToolPanel />
<div className='project-show-wrapper'>
<SidePanel
className='full-height'
@@ -119,6 +119,8 @@ export class Project extends PureComponent {
openModal={openCompletionModal}
updateProjectForm={updateProjectFormValues}
/>
<ToolPanel />
<Spacer />
</div>
<CompletionModal />
<HelpModal />

View File

@@ -27,20 +27,9 @@ const propTypes = {
export class ToolPanel extends PureComponent {
render() {
const { guideUrl, openHelpModal, toggleMapModal } = this.props;
const { guideUrl, openHelpModal } = this.props;
return (
<div className='tool-panel'>
<div id='left-tool-panel sub-panel'>
<Button
bsStyle='primary'
className='btn-primary-invert'
onClick={toggleMapModal}
>
View the Curriculum
</Button>
</div>
<div id='centre-tool-panel sub-panel' />
<div id='right-tool-panel sub-panel'>
<div className='tool-panel-group project-tool-panel'>
{guideUrl && (
<Button
block={true}
@@ -61,7 +50,6 @@ export class ToolPanel extends PureComponent {
Ask for help
</Button>
</div>
</div>
);
}
}

View File

@@ -1,29 +1,21 @@
/* global graphql */
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import Link from 'gatsby-link';
import Link, { navigateTo } from 'gatsby-link';
import Helmet from 'react-helmet';
import { Button, ListGroup, ListGroupItem } from 'react-bootstrap';
import FullWidthRow from '../../components/util/FullWidthRow';
import ButtonSpacer from '../../components/util/ButtonSpacer';
import { toggleMapModal } from '../../redux/app';
import { MarkdownRemark, AllChallengeNode } from '../../redux/propTypes';
import './intro.css';
const mapStateToProps = () => ({});
const mapDispatchToProps = dispatch =>
bindActionCreators({ toggleMapModal }, dispatch);
const propTypes = {
data: PropTypes.shape({
markdownRemark: MarkdownRemark,
allChallengeNode: AllChallengeNode
}),
toggleMapModal: PropTypes.func.isRequired
})
};
function renderMenuItems({ edges = [] }) {
@@ -34,10 +26,11 @@ function renderMenuItems({ edges = [] }) {
));
}
function IntroductionPage({
data: { markdownRemark, allChallengeNode },
toggleMapModal
}) {
function handleCurriculumClick() {
return navigateTo('/');
}
function IntroductionPage({ data: { markdownRemark, allChallengeNode } }) {
const { html, frontmatter: { block } } = markdownRemark;
const firstLesson = allChallengeNode && allChallengeNode.edges[0].node;
const firstLessonPath = firstLesson
@@ -63,7 +56,7 @@ function IntroductionPage({
block={true}
bsSize='lg'
className='btn-primary-invert'
onClick={toggleMapModal}
onClick={handleCurriculumClick}
>
View the curriculum
</Button>
@@ -83,7 +76,7 @@ function IntroductionPage({
IntroductionPage.displayName = 'IntroductionPage';
IntroductionPage.propTypes = propTypes;
export default connect(mapStateToProps, mapDispatchToProps)(IntroductionPage);
export default IntroductionPage;
export const query = graphql`
query IntroPageBySlug($slug: String!, $block: String!) {

View File

@@ -1914,13 +1914,6 @@ callsites@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50"
camelcase-keys@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7"
dependencies:
camelcase "^2.0.0"
map-obj "^1.0.0"
camelcase@4.1.0, camelcase@^4.0.0, camelcase@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
@@ -1929,10 +1922,6 @@ camelcase@^1.0.2:
version "1.2.1"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"
camelcase@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
camelcase@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
@@ -2137,7 +2126,7 @@ class-utils@^0.3.5:
isobject "^3.0.0"
static-extend "^0.1.1"
classnames@^2.2.5:
classnames@^2.2.3, classnames@^2.2.5:
version "2.2.5"
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d"
@@ -3011,12 +3000,6 @@ dom-serializer@0, dom-serializer@~0.1.0:
domelementtype "~1.1.1"
entities "~1.1.1"
dom-urls@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/dom-urls/-/dom-urls-1.1.0.tgz#001ddf81628cd1e706125c7176f53ccec55d918e"
dependencies:
urijs "^1.16.1"
dom-walk@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018"
@@ -3335,7 +3318,7 @@ es6-promise@3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.2.1.tgz#ec56233868032909207170c39448e24449dd1fc4"
es6-promise@^4.0.2, es6-promise@^4.0.5, es6-promise@^4.1.0:
es6-promise@^4.0.2, es6-promise@^4.1.0:
version "4.2.4"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29"
@@ -4208,13 +4191,6 @@ gatsby-plugin-google-fonts@^0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/gatsby-plugin-google-fonts/-/gatsby-plugin-google-fonts-0.0.4.tgz#dc1402a71f27c3ae6caee10777d10adadf74bd7c"
gatsby-plugin-offline@^1.0.15:
version "1.0.15"
resolved "https://registry.yarnpkg.com/gatsby-plugin-offline/-/gatsby-plugin-offline-1.0.15.tgz#26af0e1d1c8ed0c31f92bc6a75484b583550ef5b"
dependencies:
babel-runtime "^6.26.0"
sw-precache "^5.0.0"
gatsby-plugin-react-helmet@^2.0.8:
version "2.0.8"
resolved "https://registry.yarnpkg.com/gatsby-plugin-react-helmet/-/gatsby-plugin-react-helmet-2.0.8.tgz#26928bfd38f6828f479d76393839523ddf85b005"
@@ -4467,10 +4443,6 @@ get-port@^3.0.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/get-port/-/get-port-3.2.0.tgz#dd7ce7de187c06c8bf353796ac71e099f0980ebc"
get-stdin@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
get-stream@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
@@ -5151,12 +5123,6 @@ imurmurhash@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
indent-string@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80"
dependencies:
repeating "^2.0.0"
indexes-of@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607"
@@ -6362,6 +6328,10 @@ loader-utils@^1.0.2, loader-utils@^1.1.0:
emojis-list "^2.0.0"
json5 "^0.5.0"
loaders.css@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/loaders.css/-/loaders.css-0.1.2.tgz#3a9fb43726c73334a38142af9d0629019b658743"
locate-path@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
@@ -6401,7 +6371,7 @@ lodash.clonedeep@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
lodash.defaults@^4.0.1, lodash.defaults@^4.2.0:
lodash.defaults@^4.0.1:
version "4.2.0"
resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
@@ -6497,7 +6467,7 @@ lodash.sortby@^4.7.0:
version "4.7.0"
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
lodash.template@^4.2.4, lodash.template@^4.4.0:
lodash.template@^4.2.4:
version "4.4.0"
resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0"
dependencies:
@@ -6566,7 +6536,7 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3
dependencies:
js-tokens "^3.0.0"
loud-rejection@^1.0.0, loud-rejection@^1.2.0:
loud-rejection@^1.2.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
dependencies:
@@ -6623,10 +6593,6 @@ map-cache@^0.2.0, map-cache@^0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
map-obj@^1.0.0, map-obj@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
map-visit@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f"
@@ -6754,21 +6720,6 @@ memory-fs@~0.4.1:
errno "^0.1.3"
readable-stream "^2.0.1"
meow@^3.7.0:
version "3.7.0"
resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb"
dependencies:
camelcase-keys "^2.0.0"
decamelize "^1.1.2"
loud-rejection "^1.0.0"
map-obj "^1.0.1"
minimist "^1.1.3"
normalize-package-data "^2.3.4"
object-assign "^4.0.1"
read-pkg-up "^1.0.1"
redent "^1.0.0"
trim-newlines "^1.0.0"
merge-descriptors@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
@@ -6905,7 +6856,7 @@ minimist@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0:
minimist@^1.1.1, minimist@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
@@ -7199,7 +7150,7 @@ nopt@^4.0.1:
abbrev "1"
osenv "^0.1.4"
normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
normalize-package-data@^2.3.2:
version "2.4.0"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f"
dependencies:
@@ -7711,7 +7662,7 @@ path-to-regexp@0.1.7:
version "0.1.7"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
path-to-regexp@^1.0.1, path-to-regexp@^1.7.0:
path-to-regexp@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d"
dependencies:
@@ -8860,6 +8811,15 @@ react-side-effect@^1.1.0:
exenv "^1.2.1"
shallowequal "^1.0.1"
react-spinkit@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/react-spinkit/-/react-spinkit-3.0.0.tgz#31fdaf4e18177766c57d1b1f3330290f8492a85a"
dependencies:
classnames "^2.2.3"
loaders.css "^0.1.2"
object-assign "^4.1.0"
prop-types "^15.5.8"
react-test-renderer@^16.0.0-0, react-test-renderer@^16.3.1:
version "16.3.1"
resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.3.1.tgz#d9257936d8535bd40f57f3d5a84e7b0452fb17f2"
@@ -9036,13 +8996,6 @@ redbox-react@^1.3.6:
prop-types "^15.5.4"
sourcemapped-stacktrace "^1.1.6"
redent@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde"
dependencies:
indent-string "^2.1.0"
strip-indent "^1.0.1"
reduce-css-calc@^1.2.6, reduce-css-calc@^1.2.7:
version "1.3.0"
resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716"
@@ -9817,10 +9770,6 @@ serve@^6.4.0:
path-type "3.0.0"
send "0.16.2"
serviceworker-cache-polyfill@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/serviceworker-cache-polyfill/-/serviceworker-cache-polyfill-4.0.0.tgz#de19ee73bef21ab3c0740a37b33db62464babdeb"
set-blocking@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-1.0.0.tgz#cd5e5d938048df1ac92dfe92e1f16add656f5ec5"
@@ -10421,12 +10370,6 @@ strip-eof@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
strip-indent@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2"
dependencies:
get-stdin "^4.0.1"
strip-json-comments@~2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
@@ -10486,28 +10429,6 @@ svgo@^0.7.0:
sax "~1.2.1"
whet.extend "~0.9.9"
sw-precache@^5.0.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/sw-precache/-/sw-precache-5.2.1.tgz#06134f319eec68f3b9583ce9a7036b1c119f7179"
dependencies:
dom-urls "^1.1.0"
es6-promise "^4.0.5"
glob "^7.1.1"
lodash.defaults "^4.2.0"
lodash.template "^4.4.0"
meow "^3.7.0"
mkdirp "^0.5.1"
pretty-bytes "^4.0.2"
sw-toolbox "^3.4.0"
update-notifier "^2.3.0"
sw-toolbox@^3.4.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/sw-toolbox/-/sw-toolbox-3.6.0.tgz#26df1d1c70348658e4dea2884319149b7b3183b5"
dependencies:
path-to-regexp "^1.0.1"
serviceworker-cache-polyfill "^4.0.0"
symbol-observable@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4"
@@ -10753,10 +10674,6 @@ trim-lines@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/trim-lines/-/trim-lines-1.1.0.tgz#9926d03ede13ba18f7d42222631fb04c79ff26fe"
trim-newlines@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"
trim-right@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
@@ -11074,10 +10991,6 @@ uri-js@^3.0.2:
dependencies:
punycode "^2.1.0"
urijs@^1.16.1:
version "1.19.1"
resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.1.tgz#5b0ff530c0cbde8386f6342235ba5ca6e995d25a"
urix@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
@@ -11352,6 +11265,10 @@ webpack-md5-hash@0.0.5:
dependencies:
md5 "^2.0.0"
webpack-remove-serviceworker-plugin@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/webpack-remove-serviceworker-plugin/-/webpack-remove-serviceworker-plugin-1.0.0.tgz#63a7604da9a7fd9bae8f9eef87d274a2470dcaa7"
webpack-sources@^0.1.0:
version "0.1.5"
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-0.1.5.tgz#aa1f3abf0f0d74db7111c40e500b84f966640750"