Make the guides page working
This commit is contained in:
@ -1,28 +1,55 @@
|
||||
import { Box, Container, Flex, Heading, Image, Link, Text } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
|
||||
type GuideHeaderProps = {
|
||||
type ContentPageHeaderProps = {
|
||||
formattedDate: string;
|
||||
title: string;
|
||||
subtitle: string;
|
||||
author?: {
|
||||
name: string;
|
||||
twitter: string;
|
||||
picture: string;
|
||||
},
|
||||
subLink?: {
|
||||
text: string;
|
||||
url: string;
|
||||
}
|
||||
};
|
||||
|
||||
export function ContentPageHeader(props: GuideHeaderProps) {
|
||||
const { title, subtitle } = props;
|
||||
export function ContentPageHeader(props: ContentPageHeaderProps) {
|
||||
const { title, subtitle, author = null, formattedDate, subLink = null } = props;
|
||||
|
||||
return (
|
||||
<Box pt={['35px', '35px', '70px']} pb={['35px', '35px', '55px']} borderBottomWidth={1} mb='30px'>
|
||||
<Container maxW='container.md' position='relative' textAlign={['left', 'left', 'center']}>
|
||||
<Flex alignItems='center' justifyContent={['flex-start', 'flex-start', 'center']} fontSize={['12px', '12px', '14px']}>
|
||||
<Flex alignItems='center' justifyContent={['flex-start', 'flex-start', 'center']}
|
||||
fontSize={['12px', '12px', '14px']}>
|
||||
|
||||
<Link d={['none', 'flex', 'flex']} href='#' alignItems='center' fontWeight={600} color='gray.500'>
|
||||
<Image mr='7px' w='22px' src='https://github.com/kamranahmedse.png' />
|
||||
Kamran Ahmed
|
||||
{author?.name && (
|
||||
<>
|
||||
<Link
|
||||
d={['none', 'flex', 'flex']}
|
||||
target='_blank'
|
||||
href={`https://twitter.com/${author.twitter}`}
|
||||
alignItems='center'
|
||||
fontWeight={600}
|
||||
color='gray.500'
|
||||
>
|
||||
<Image rounded={'full'} mr='7px' w='22px' src={author.picture} />
|
||||
{author.name}
|
||||
</Link>
|
||||
<Text d={['none', 'inline', 'inline']} mx='7px' color='gray.500' as='span'>·</Text>
|
||||
</>
|
||||
)}
|
||||
|
||||
<Text color='gray.500' as='span'>Monday, May 4, 2021</Text>
|
||||
<Text color='gray.500' as='span'>{formattedDate}</Text>
|
||||
{subLink?.text && (
|
||||
<>
|
||||
<Text d={['none', 'none', 'inline']} mx='7px' color='gray.500' as='span'>·</Text>
|
||||
<Link d={['none', 'none', 'inline']} color='blue.500' fontWeight={500} href='#'>Improve this Guide</Link>
|
||||
<Link d={['none', 'none', 'inline']} color='blue.500' fontWeight={500}
|
||||
href={subLink.url} target={'_blank'}>{subLink.text}</Link>
|
||||
</>
|
||||
)}
|
||||
</Flex>
|
||||
<Heading as='h1' color='black' fontSize={['30px', '30px', '45px']} lineHeight={['40px', '40px', '53px']}
|
||||
fontWeight={700} my={['5px', '5px', '10px']}>{title}</Heading>
|
||||
|
@ -37,6 +37,7 @@
|
||||
{
|
||||
"username": "lesovsky",
|
||||
"name": "Alexey Lesovsky",
|
||||
"bio": "Linux system administrator and PostgreSQL DBA at DataEgret."
|
||||
"bio": "Linux system administrator and PostgreSQL DBA at DataEgret.",
|
||||
"picture": "/authors/lesovsky.jpeg"
|
||||
}
|
||||
]
|
||||
|
@ -1,179 +1,197 @@
|
||||
[
|
||||
{
|
||||
"id": "ci-cd",
|
||||
"title": "What is CI and CD?",
|
||||
"description": "Learn the basics of CI/CD and how to implement that with GitHub Actions.",
|
||||
"url": "/guides/ci-cd",
|
||||
"fileName": "ci-cd",
|
||||
"fileName": "ci-cd.md",
|
||||
"isPro": false,
|
||||
"authorUsername": "kamranahmedse",
|
||||
"updatedAt": "2020-07-09T19:59:14.191Z",
|
||||
"createdAt": "2020-07-09T19:59:14.191Z"
|
||||
},
|
||||
{
|
||||
"id": "sso",
|
||||
"title": "SSO — Single Sign On",
|
||||
"description": "Learn the basics of SAML and understand how does Single Sign On work.",
|
||||
"url": "/guides/sso",
|
||||
"fileName": "sso",
|
||||
"fileName": "sso.md",
|
||||
"isPro": false,
|
||||
"authorUsername": "kamranahmedse",
|
||||
"updatedAt": "2020-07-01T19:59:14.191Z",
|
||||
"createdAt": "2020-07-01T19:59:14.191Z"
|
||||
},
|
||||
{
|
||||
"id": "oauth",
|
||||
"title": "OAuth — Open Authorization",
|
||||
"description": "Learn and understand what is OAuth and how it works",
|
||||
"url": "/guides/oauth",
|
||||
"fileName": "oauth",
|
||||
"fileName": "oauth.md",
|
||||
"isPro": false,
|
||||
"authorUsername": "kamranahmedse",
|
||||
"updatedAt": "2020-06-28T19:59:14.191Z",
|
||||
"createdAt": "2020-06-28T19:59:14.191Z"
|
||||
},
|
||||
{
|
||||
"id": "jwt-authentication",
|
||||
"title": "JWT Authentication",
|
||||
"description": "Understand what is JWT authentication and how is it implemented",
|
||||
"url": "/guides/jwt-authentication",
|
||||
"fileName": "jwt-authentication",
|
||||
"fileName": "jwt-authentication.md",
|
||||
"isPro": false,
|
||||
"authorUsername": "kamranahmedse",
|
||||
"updatedAt": "2020-06-20T19:59:14.191Z",
|
||||
"createdAt": "2020-06-20T19:59:14.191Z"
|
||||
},
|
||||
{
|
||||
"id": "token-authentication",
|
||||
"title": "Token Based Authentication",
|
||||
"description": "Understand what is token based authentication and how it is implemented",
|
||||
"url": "/guides/token-authentication",
|
||||
"fileName": "token-authentication",
|
||||
"fileName": "token-authentication.md",
|
||||
"isPro": false,
|
||||
"authorUsername": "kamranahmedse",
|
||||
"updatedAt": "2020-06-02T20:59:14.191Z",
|
||||
"createdAt": "2020-06-02T20:59:14.191Z"
|
||||
},
|
||||
{
|
||||
"id": "session-authentication",
|
||||
"title": "Session Based Authentication",
|
||||
"description": "Understand what is session based authentication and how it is implemented",
|
||||
"url": "/guides/session-authentication",
|
||||
"fileName": "session-authentication",
|
||||
"fileName": "session-authentication.md",
|
||||
"isPro": false,
|
||||
"authorUsername": "kamranahmedse",
|
||||
"updatedAt": "2020-05-26T20:59:14.191Z",
|
||||
"createdAt": "2020-05-26T20:59:14.191Z"
|
||||
},
|
||||
{
|
||||
"id": "basic-authentication",
|
||||
"title": "Basic Authentication",
|
||||
"description": "Understand what is basic authentication and how it is implemented",
|
||||
"url": "/guides/basic-authentication",
|
||||
"fileName": "basic-authentication",
|
||||
"fileName": "basic-authentication.md",
|
||||
"isPro": false,
|
||||
"authorUsername": "kamranahmedse",
|
||||
"updatedAt": "2020-05-19T20:59:14.191Z",
|
||||
"createdAt": "2020-05-19T20:59:14.191Z"
|
||||
},
|
||||
{
|
||||
"id": "character-encodings",
|
||||
"title": "Character Encodings",
|
||||
"description": "Covers the basics of character encodings and explains ASCII vs Unicode",
|
||||
"url": "/guides/character-encodings",
|
||||
"fileName": "character-encodings",
|
||||
"fileName": "character-encodings.md",
|
||||
"isPro": false,
|
||||
"authorUsername": "kamranahmedse",
|
||||
"updatedAt": "2020-05-14T20:59:14.191Z",
|
||||
"createdAt": "2020-05-14T20:59:14.191Z"
|
||||
},
|
||||
{
|
||||
"id": "unfamiliar-codebase",
|
||||
"title": "Unfamiliar Codebase",
|
||||
"description": "Tips on getting getting familiar with an unfamiliar codebase",
|
||||
"url": "/guides/unfamiliar-codebase",
|
||||
"fileName": "unfamiliar-codebase",
|
||||
"fileName": "unfamiliar-codebase.md",
|
||||
"isPro": false,
|
||||
"authorUsername": "kamranahmedse",
|
||||
"updatedAt": "2020-05-04T20:59:14.191Z",
|
||||
"createdAt": "2020-05-04T20:59:14.191Z"
|
||||
},
|
||||
{
|
||||
"id": "why-build-it-and-they-will-come-wont-work-anymore",
|
||||
"title": "Build it and they will come?",
|
||||
"description": "Why “build it and they will come” alone won’t work anymore",
|
||||
"url": "/guides/why-build-it-and-they-will-come-wont-work-anymore",
|
||||
"fileName": "why-build-it-and-they-will-come-wont-work-anymore",
|
||||
"fileName": "why-build-it-and-they-will-come-wont-work-anymore.md",
|
||||
"isPro": false,
|
||||
"authorUsername": "spekulatius",
|
||||
"updatedAt": "2020-05-04T12:59:14.191Z",
|
||||
"createdAt": "2020-05-04T12:59:14.191Z"
|
||||
},
|
||||
{
|
||||
"id": "dhcp-in-one-picture",
|
||||
"title": "DHCP in One Picture",
|
||||
"description": "Here is what happens when a new device joins the network.",
|
||||
"url": "/guides/dhcp-in-one-picture",
|
||||
"fileName": "dhcp-in-one-picture",
|
||||
"fileName": "dhcp-in-one-picture.md",
|
||||
"isPro": false,
|
||||
"authorUsername": "kamranahmedse",
|
||||
"updatedAt": "2020-04-28T15:48:21.191Z",
|
||||
"createdAt": "2020-04-28T15:48:21.191Z"
|
||||
},
|
||||
{
|
||||
"id": "ssl-tls-https-ssh",
|
||||
"title": "SSL vs TLS vs SSH",
|
||||
"description": "Quick tidbit on the differences between SSL, TLS, HTTPS and SSH",
|
||||
"url": "/guides/ssl-tls-https-ssh",
|
||||
"fileName": "ssl-tls-https-ssh",
|
||||
"fileName": "ssl-tls-https-ssh.md",
|
||||
"isPro": false,
|
||||
"authorUsername": "kamranahmedse",
|
||||
"updatedAt": "2020-04-22T15:48:21.191Z",
|
||||
"createdAt": "2020-04-22T15:48:21.191Z"
|
||||
},
|
||||
{
|
||||
"id": "asymptotic-notation",
|
||||
"title": "Asymptotic Notation",
|
||||
"description": "Learn the basics of measuring the time and space complexity of algorithms",
|
||||
"url": "/guides/asymptotic-notation",
|
||||
"fileName": "asymptotic-notation",
|
||||
"fileName": "asymptotic-notation.md",
|
||||
"isPro": false,
|
||||
"authorUsername": "kamranahmedse",
|
||||
"updatedAt": "2020-04-03T15:48:21.191Z",
|
||||
"createdAt": "2020-04-03T15:48:21.191Z"
|
||||
},
|
||||
{
|
||||
"id": "big-o-notation",
|
||||
"title": "Big-O Notation",
|
||||
"description": "Easy to understand explanation of Big-O notation without any fancy terms",
|
||||
"url": "/guides/big-o-notation",
|
||||
"fileName": "big-o-notation",
|
||||
"fileName": "big-o-notation.md",
|
||||
"isPro": false,
|
||||
"authorUsername": "kamranahmedse",
|
||||
"updatedAt": "2020-03-15T15:48:21.191Z",
|
||||
"createdAt": "2020-03-15T15:48:21.191Z"
|
||||
},
|
||||
{
|
||||
"id": "random-numbers",
|
||||
"title": "Random Numbers: Are they?",
|
||||
"description": "Learn how they are generated and why they may not be truly random.",
|
||||
"url": "/guides/random-numbers",
|
||||
"fileName": "random-numbers",
|
||||
"fileName": "random-numbers.md",
|
||||
"isPro": false,
|
||||
"authorUsername": "kamranahmedse",
|
||||
"updatedAt": "2020-03-14T15:48:21.191Z",
|
||||
"createdAt": "2020-03-14T15:48:21.191Z"
|
||||
},
|
||||
{
|
||||
"id": "scaling-databases",
|
||||
"title": "Scaling Databases",
|
||||
"description": "Learn the ups and downs of different database scaling strategies",
|
||||
"url": "/guides/scaling-databases",
|
||||
"fileName": "scaling-databases",
|
||||
"fileName": "scaling-databases.md",
|
||||
"isPro": false,
|
||||
"authorUsername": "kamranahmedse",
|
||||
"updatedAt": "2020-02-18T15:48:21.191Z",
|
||||
"createdAt": "2020-02-18T15:48:21.191Z"
|
||||
},
|
||||
{
|
||||
"id": "what-is-internet",
|
||||
"title": "How does the internet work?",
|
||||
"description": "Learn the basics of internet and everything involved with this short video series",
|
||||
"url": "/guides/what-is-internet",
|
||||
"fileName": "what-is-internet",
|
||||
"fileName": "what-is-internet.md",
|
||||
"isPro": false,
|
||||
"authorUsername": "dmytrobol",
|
||||
"updatedAt": "2020-02-29T15:48:21.191Z",
|
||||
"createdAt": "2020-02-29T15:48:21.191Z"
|
||||
},
|
||||
{
|
||||
"id": "torrent-client",
|
||||
"title": "Building a BitTorrent Client",
|
||||
"description": "Learn everything you need to know about BitTorrent by writing a client in Go",
|
||||
"url": "/guides/torrent-client",
|
||||
"fileName": "torrent-client",
|
||||
"fileName": "torrent-client.md",
|
||||
"isPro": false,
|
||||
"authorUsername": "jesse",
|
||||
"updatedAt": "2020-01-17T15:48:21.191Z",
|
||||
@ -181,30 +199,33 @@
|
||||
"canonical": "https://blog.jse.li/posts/torrent/"
|
||||
},
|
||||
{
|
||||
"id": "levels-of-seniority",
|
||||
"title": "Levels of Seniority",
|
||||
"description": "How to Step Up as a Junior, Mid Level or a Senior Developer?",
|
||||
"url": "/guides/levels-of-seniority",
|
||||
"fileName": "levels-of-seniority",
|
||||
"fileName": "levels-of-seniority.md",
|
||||
"isPro": false,
|
||||
"authorUsername": "kamranahmedse",
|
||||
"updatedAt": "2019-12-03T12:13:00.860Z",
|
||||
"createdAt": "2019-12-03T12:13:00.860Z"
|
||||
},
|
||||
{
|
||||
"id": "design-patterns-for-humans",
|
||||
"title": "Design Patterns for Humans",
|
||||
"description": "A language agnostic, ultra-simplified explanation to design patterns",
|
||||
"url": "/guides/design-patterns-for-humans",
|
||||
"fileName": "design-patterns-for-humans",
|
||||
"fileName": "design-patterns-for-humans.md",
|
||||
"isPro": false,
|
||||
"authorUsername": "kamranahmedse",
|
||||
"updatedAt": "2019-10-09T12:00:00.860Z",
|
||||
"createdAt": "2019-01-23T17:00:00.860Z"
|
||||
},
|
||||
{
|
||||
"id": "journey-to-http2",
|
||||
"title": "Journey to HTTP/2",
|
||||
"description": "The evolution of HTTP. How it all started and where we stand today",
|
||||
"url": "/guides/journey-to-http2",
|
||||
"fileName": "journey-to-http2",
|
||||
"fileName": "journey-to-http2.md",
|
||||
"isPro": false,
|
||||
"authorUsername": "kamranahmedse",
|
||||
"createdAt": "2018-12-04T12:00:00.860Z",
|
||||
@ -212,40 +233,44 @@
|
||||
"isDraft": true
|
||||
},
|
||||
{
|
||||
"id": "dns-in-one-picture",
|
||||
"title": "DNS in One Picture",
|
||||
"description": "Quick illustrative guide on how a website is found on the internet.",
|
||||
"url": "/guides/dns-in-one-picture",
|
||||
"fileName": "dns-in-one-picture",
|
||||
"fileName": "dns-in-one-picture.md",
|
||||
"isPro": false,
|
||||
"authorUsername": "kamranahmedse",
|
||||
"updatedAt": "2018-12-04T12:00:00.860Z",
|
||||
"createdAt": "2018-12-04T17:00:00.860Z"
|
||||
},
|
||||
{
|
||||
"id": "http-caching",
|
||||
"title": "HTTP Caching",
|
||||
"description": "Everything you need to know about web caching",
|
||||
"url": "/guides/http-caching",
|
||||
"fileName": "http-caching",
|
||||
"fileName": "http-caching.md",
|
||||
"isPro": false,
|
||||
"authorUsername": "kamranahmedse",
|
||||
"createdAt": "2018-11-29T17:00:00.860Z",
|
||||
"updatedAt": "2018-11-29T17:00:00.860Z"
|
||||
},
|
||||
{
|
||||
"id": "history-of-javascript",
|
||||
"title": "Brief History of JavaScript",
|
||||
"description": "How JavaScript was introduced and evolved over the years",
|
||||
"url": "/guides/history-of-javascript",
|
||||
"fileName": "history-of-javascript",
|
||||
"fileName": "history-of-javascript.md",
|
||||
"isPro": false,
|
||||
"authorUsername": "kamranahmedse",
|
||||
"createdAt": "2017-10-28T17:00:00.860Z",
|
||||
"updatedAt": "2017-10-28T17:00:00.860Z"
|
||||
},
|
||||
{
|
||||
"id": "proxy-servers",
|
||||
"title": "Proxy Servers",
|
||||
"description": "How do proxy servers work and what are forward and reverse proxies?",
|
||||
"url": "/guides/proxy-servers",
|
||||
"fileName": "proxy-servers",
|
||||
"fileName": "proxy-servers.md",
|
||||
"isPro": false,
|
||||
"authorUsername": "ebrahimbharmal007",
|
||||
"createdAt": "2020-07-24T12:40:18",
|
||||
|
34
lib/guide.ts
34
lib/guide.ts
@ -4,6 +4,7 @@ import { NextApiRequest } from 'next';
|
||||
import { AuthorType, findAuthorByUsername } from './author';
|
||||
|
||||
export type GuideType = {
|
||||
id: string;
|
||||
title: string;
|
||||
description: string;
|
||||
url: string;
|
||||
@ -18,6 +19,19 @@ export type GuideType = {
|
||||
author?: AuthorType;
|
||||
};
|
||||
|
||||
export function getGuideById(id: string): GuideType | undefined {
|
||||
const allGuides = getAllGuides();
|
||||
const foundGuide = allGuides.find(guide => guide.id === id);
|
||||
if (!foundGuide) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
...foundGuide,
|
||||
author: findAuthorByUsername(foundGuide.authorUsername)
|
||||
};
|
||||
}
|
||||
|
||||
export function getAllGuides(limit: number = 0): GuideType[] {
|
||||
return (guides as GuideType[])
|
||||
.filter(guide => !guide.isDraft)
|
||||
@ -29,23 +43,3 @@ export function getAllGuides(limit: number = 0): GuideType[] {
|
||||
}))
|
||||
.slice(0, limit ? limit : guides.length);
|
||||
}
|
||||
|
||||
|
||||
export function getRequestedGuide(req: NextApiRequest): GuideType | undefined {
|
||||
const allGuides = getAllGuides();
|
||||
const guide = allGuides.find(guide => guide.url === req.url);
|
||||
if (!guide) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
try {
|
||||
return {
|
||||
...guide,
|
||||
author: findAuthorByUsername(guide.authorUsername)
|
||||
};
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { NextApiRequest } from 'next';
|
||||
import roadmaps from '../content/roadmaps.json';
|
||||
|
||||
export type RoadmapType = {
|
||||
|
@ -5,17 +5,34 @@ import { UpdatesBanner } from '../../components/updates-banner';
|
||||
import { Footer } from '../../components/footer';
|
||||
import { ContentPageHeader } from '../../components/content-page-header';
|
||||
import MdRenderer from '../../components/md-renderer';
|
||||
import { getAllGuides, getGuideById, GuideType } from '../../lib/guide';
|
||||
import siteConfig from '../../content/site.json';
|
||||
|
||||
export default function Guide() {
|
||||
const GuideContent = require(`../../content/guides/build-it.md`).default;
|
||||
type GuideProps = {
|
||||
guide: GuideType;
|
||||
};
|
||||
|
||||
export default function Guide(props: GuideProps) {
|
||||
const { guide } = props;
|
||||
const GuideContent = require(`../../content/guides/${guide.fileName}`).default;
|
||||
|
||||
return (
|
||||
<Box bg='white' minH='100vh'>
|
||||
<GlobalHeader />
|
||||
<Box mb='60px'>
|
||||
<ContentPageHeader
|
||||
title={'Build it and they will come?'}
|
||||
subtitle={'Why “build it and they will come” alone won’t work anymore'}
|
||||
title={guide.title}
|
||||
subtitle={guide.description}
|
||||
formattedDate={guide.formattedUpdatedAt}
|
||||
author={{
|
||||
twitter: guide?.author?.twitter!,
|
||||
picture: guide?.author?.picture!,
|
||||
name: guide?.author?.name!
|
||||
}}
|
||||
subLink={{
|
||||
text: 'Improve this Guide',
|
||||
url: `${siteConfig.url.repo}/tree/master/content/guides/${guide.fileName}`
|
||||
}}
|
||||
/>
|
||||
<Container maxW={'container.md'} position='relative'>
|
||||
<MdRenderer>
|
||||
@ -30,3 +47,37 @@ export default function Guide() {
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
type StaticPathItem = {
|
||||
params: {
|
||||
guide: string
|
||||
}
|
||||
};
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const guides = getAllGuides();
|
||||
const paramsList: StaticPathItem[] = guides.map(guide => ({
|
||||
params: { 'guide': guide.id }
|
||||
}));
|
||||
|
||||
return {
|
||||
paths: paramsList,
|
||||
fallback: false
|
||||
};
|
||||
}
|
||||
|
||||
type ContextType = {
|
||||
params: {
|
||||
guide: string
|
||||
}
|
||||
};
|
||||
|
||||
export async function getStaticProps(context: ContextType) {
|
||||
const guideId: string = context?.params?.guide;
|
||||
|
||||
return {
|
||||
props: {
|
||||
guide: getGuideById(guideId)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
BIN
public/authors/dmytrobol.png
Normal file
BIN
public/authors/dmytrobol.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 844 KiB |
BIN
public/authors/ebrahimbharmal007.png
Normal file
BIN
public/authors/ebrahimbharmal007.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
BIN
public/authors/jesse.png
Normal file
BIN
public/authors/jesse.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.3 KiB |
BIN
public/authors/kamranahmedse.jpeg
Normal file
BIN
public/authors/kamranahmedse.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 41 KiB |
BIN
public/authors/lesovsky.jpeg
Normal file
BIN
public/authors/lesovsky.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
BIN
public/authors/spekulatius.jpg
Normal file
BIN
public/authors/spekulatius.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.8 KiB |
Reference in New Issue
Block a user