Refactor and roadmap summary pages

pull/1331/head
Kamran Ahmed 5 years ago
parent 8f6ead0add
commit 9f98b30568
  1. 2
      components/featured-content/roadmaps.js
  2. 16
      components/roadmap-summary/index.js
  3. 40
      components/roadmap-summary/style.js
  4. 31
      data/roadmaps.json
  5. 4
      layouts/default/global.scss
  6. 26
      lib/roadmap.js
  7. 1
      package.json
  8. 21
      pages/[fallback].js
  9. 3
      pages/[fallback]/[version].js
  10. 22
      pages/[fallback]/index.js
  11. 25
      pages/roadmaps/[roadmap].js
  12. 3
      pages/roadmaps/[roadmap]/[version].js
  13. 24
      pages/roadmaps/[roadmap]/index.js
  14. 5
      yarn.lock

@ -20,7 +20,7 @@ const FeaturedRoadmaps = () => (
{ roadmaps { roadmaps
.filter(({ featured }) => featured) .filter(({ featured }) => featured)
.map(roadmap => ( .map(roadmap => (
<div className="col-xl-4 col-lg-4 col-md-6 col-sm-12 col-12 grid-item-container"> <div className="col-xl-4 col-lg-4 col-md-6 col-sm-12 col-12 grid-item-container" key={roadmap.slug}>
<Link href={ roadmap.slug }> <Link href={ roadmap.slug }>
<a className="featured-block"> <a className="featured-block">
<h4>{ roadmap.title }</h4> <h4>{ roadmap.title }</h4>

@ -1,3 +1,6 @@
import Link from 'next/link';
import classNames from 'classnames';
import { import {
SummaryContainer, SummaryContainer,
Title, Title,
@ -5,6 +8,8 @@ import {
Image, Image,
Header, Header,
Summary, Summary,
VersionLink,
VersionList,
} from './style'; } from './style';
const RoadmapSummary = ({ roadmap }) => ( const RoadmapSummary = ({ roadmap }) => (
@ -12,8 +17,17 @@ const RoadmapSummary = ({ roadmap }) => (
<Header> <Header>
<Title>{ roadmap.title }</Title> <Title>{ roadmap.title }</Title>
<Description>{ roadmap.description }</Description> <Description>{ roadmap.description }</Description>
<VersionList className="border-bottom">
{ (roadmap.versions || []).map(versionItem => (
<Link href={ `${roadmap.slug}/${versionItem}` } passHref key={ versionItem }>
<VersionLink className={ classNames({
active: versionItem === roadmap.version,
}) }>{ versionItem } Version</VersionLink>
</Link>
)) }
</VersionList>
</Header> </Header>
<Summary className="border-top border-bottom"> <Summary className="border-bottom">
<div className="container"> <div className="container">
<Image src={ roadmap.picture } /> <Image src={ roadmap.picture } />
</div> </div>

@ -9,7 +9,7 @@ export const Header = styled.div`
export const Summary = styled.div` export const Summary = styled.div`
text-align: center; text-align: center;
padding: 50px 0; padding: 0 0 50px;
`; `;
export const Title = styled.h1` export const Title = styled.h1`
@ -17,10 +17,46 @@ export const Title = styled.h1`
margin-bottom: 12px; margin-bottom: 12px;
font-size: 42px; font-size: 42px;
`; `;
export const Description = styled.p` export const Description = styled.p`
font-size: 19px; font-size: 19px;
margin-bottom: 0;
`; `;
export const Image = styled.img` export const Image = styled.img`
width: 100%; width: 100%;
`; `;
export const VersionList = styled.div`
margin: 35px 0 15px;
`;
export const VersionLink = styled.a`
display: inline-block;
position: relative;
padding: 5px 10px 8px;
text-decoration: none;
color: rgb(102, 102, 102);
font-size: 14px;
font-weight: 400;
text-transform: capitalize;
&.active, &.active:hover {
color: #2d2d2d;
&:after {
position: absolute;
content: "";
display: block;
height: 0;
left: 9px;
right: 9px;
bottom: -1px;
border-bottom: 2px solid currentColor;
}
}
&:hover {
text-decoration: none;
color: #111111;
}
`;

@ -3,24 +3,39 @@
"title": "Frontend Developer", "title": "Frontend Developer",
"description": "Step by step guide to becoming a modern frontend developer", "description": "Step by step guide to becoming a modern frontend developer",
"featuredDescription": "Step by step guide to becoming a modern frontend developer in 2019", "featuredDescription": "Step by step guide to becoming a modern frontend developer in 2019",
"slug": "/frontend", "slug": "/roadmaps/frontend",
"picture": "/static/roadmaps/frontend.png", "picture": "/static/roadmaps/frontend.png",
"featured": true "featured": true,
"versions": [
"latest",
"2018",
"2017"
]
}, },
{ {
"title": "Backend Developer", "title": "Backend Developer",
"description": "Roadmap to becoming a backend developer", "description": "Step by step guide to becoming a modern backend developer",
"featuredDescription": "Step by step guide to becoming a modern backend developer in 2019", "featuredDescription": "Step by step guide to becoming a modern backend developer in 2019",
"slug": "/backend", "slug": "/roadmaps/backend",
"picture": "/static/roadmaps/backend.png", "picture": "/static/roadmaps/backend.png",
"featured": true "featured": true,
"versions": [
"latest",
"2018",
"2017"
]
}, },
{ {
"title": "DevOps Roadmap", "title": "DevOps Roadmap",
"description": "Roadmap for DevOps or any other Operations Role", "description": "Step by step guide for DevOps or any other Operations Role",
"featuredDescription": "Step by step guide to become an SRE or for any operations role in 2019", "featuredDescription": "Step by step guide to become an SRE or for any operations role in 2019",
"slug": "/devops", "slug": "/roadmaps/devops",
"picture": "/static/roadmaps/devops.png", "picture": "/static/roadmaps/devops.png",
"featured": true "featured": true,
"versions": [
"latest",
"2018",
"2017"
]
} }
] ]

@ -16,6 +16,10 @@
background-color: #fafafa !important; background-color: #fafafa !important;
} }
.muted {
color: #757575;
}
.dark-link { .dark-link {
font-weight: 500; font-weight: 500;
color: #000000; color: #000000;

@ -0,0 +1,26 @@
import roadmaps from "../data/roadmaps";
export const getRequestedRoadmap = req => {
// Considering it a new roadmap URL e.g. `/roadmaps/frontend`
const currentUrl = req.url.replace(/\/$/, '');
// Considering it a legacy URL e.g. converting `/frontend` to `roadmap.sh/roadmaps/frontend`
const legacyUrl = `/roadmaps${currentUrl}`;
// Get the roadmap version out of the URL e.g. `/roadmaps/frontend/2019`
const [foundVersion = ''] = currentUrl.match(/(\d+|latest)$/) || ['latest'];
const foundVersionRegex = new RegExp(`\/?${foundVersion}$`);
// Remove version from the URL because slugs in roadmaps list don't have versions
const newUrlWithoutVersion = currentUrl.replace(foundVersionRegex, '');
const legacyUrlWithoutVersion = legacyUrl.replace(foundVersionRegex, '');
const urlToSlugList = [
currentUrl,
legacyUrl,
newUrlWithoutVersion,
legacyUrlWithoutVersion,
];
return {
...roadmaps.find(roadmap => urlToSlugList.includes(roadmap.slug)),
version: foundVersion,
};
};

@ -18,6 +18,7 @@
"@zeit/next-sass": "^1.0.1", "@zeit/next-sass": "^1.0.1",
"autoprefixer": "^9.6.1", "autoprefixer": "^9.6.1",
"bootstrap": "^4.3.1", "bootstrap": "^4.3.1",
"classnames": "^2.2.6",
"font-awesome": "^4.7.0", "font-awesome": "^4.7.0",
"next": "^9.0.4", "next": "^9.0.4",
"node-sass": "^4.12.0", "node-sass": "^4.12.0",

@ -1,21 +0,0 @@
import Roadmap from './roadmaps/[roadmap]';
import roadmapsList from "../data/roadmaps.json";
import { serverOnlyProps } from '../lib/server';
// Fallback page to handle the old roadmap pages implementation
const OldRoadmap = ({ roadmap }) => {
if (roadmap) {
return <Roadmap roadmap={ roadmap } />
}
return <h1>404</h1>
};
OldRoadmap.getInitialProps = serverOnlyProps(({ req }) => {
return {
roadmap: roadmapsList.find(roadmap => roadmap.slug === req.url),
};
});
export default OldRoadmap;

@ -0,0 +1,3 @@
import OldRoadmap from './index';
export default OldRoadmap;

@ -0,0 +1,22 @@
import Error from 'next/error';
import Roadmap from '../roadmaps/[roadmap]/index';
import { serverOnlyProps } from '../../lib/server';
import { getRequestedRoadmap } from '../../lib/roadmap';
// Fallback page to handle the old roadmap pages implementation
const OldRoadmap = ({ roadmap }) => {
if (roadmap) {
return <Roadmap roadmap={ roadmap } />
}
return <Error status={ 404 } />;
};
OldRoadmap.getInitialProps = serverOnlyProps(({ req }) => {
return {
roadmap: getRequestedRoadmap(req),
};
});
export default OldRoadmap;

@ -1,25 +0,0 @@
import roadmaps from "../../data/roadmaps";
import DefaultLayout from '../../layouts/default/index';
import PageHeader from '../../components/page-header/index';
import { serverOnlyProps } from '../../lib/server';
import RoadmapSummary from '../../components/roadmap-summary';
import PageFooter from '../../components/page-footer';
const Roadmap = ({ roadmap }) => {
return (
<DefaultLayout>
<PageHeader />
<RoadmapSummary roadmap={ roadmap } />
<PageFooter />
</DefaultLayout>
);
};
Roadmap.getInitialProps = serverOnlyProps(({ req }) => {
const normalizedUrl = req.url.replace('roadmaps/', '');
return {
roadmap: roadmaps.find(roadmap => roadmap.slug === normalizedUrl),
};
});
export default Roadmap;

@ -0,0 +1,3 @@
import Roadmap from './index';
export default Roadmap;

@ -0,0 +1,24 @@
import DefaultLayout from '../../../layouts/default';
import { serverOnlyProps } from '../../../lib/server';
import PageHeader from '../../../components/page-header';
import PageFooter from '../../../components/page-footer';
import { getRequestedRoadmap } from '../../../lib/roadmap';
import RoadmapSummary from '../../../components/roadmap-summary';
const Roadmap = ({ roadmap }) => {
return (
<DefaultLayout>
<PageHeader />
<RoadmapSummary roadmap={ roadmap } />
<PageFooter />
</DefaultLayout>
);
};
Roadmap.getInitialProps = serverOnlyProps(({ req }) => {
return {
roadmap: getRequestedRoadmap(req),
};
});
export default Roadmap;

@ -1754,6 +1754,11 @@ class-utils@^0.3.5:
isobject "^3.0.0" isobject "^3.0.0"
static-extend "^0.1.1" static-extend "^0.1.1"
classnames@^2.2.6:
version "2.2.6"
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==
cliui@^3.2.0: cliui@^3.2.0:
version "3.2.0" version "3.2.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"

Loading…
Cancel
Save