diff --git a/components/content-page-header.tsx b/components/content-page-header.tsx index d9ad7ac4e..f3a974cf3 100644 --- a/components/content-page-header.tsx +++ b/components/content-page-header.tsx @@ -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 ( - + - - - Kamran Ahmed - - · + {author?.name && ( + <> + + + {author.name} + + · + + )} - Monday, May 4, 2021 - · - Improve this Guide + {formattedDate} + {subLink?.text && ( + <> + · + {subLink.text} + + )} {title} diff --git a/content/authors.json b/content/authors.json index 3fd701d98..f16e45d06 100644 --- a/content/authors.json +++ b/content/authors.json @@ -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" } ] diff --git a/content/guides.json b/content/guides.json index 6fc60b97a..b62cdb08d 100644 --- a/content/guides.json +++ b/content/guides.json @@ -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", diff --git a/lib/guide.ts b/lib/guide.ts index cd7d43271..2da766daf 100644 --- a/lib/guide.ts +++ b/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; -} diff --git a/lib/roadmap.ts b/lib/roadmap.ts index 428b26e8e..2d821b195 100644 --- a/lib/roadmap.ts +++ b/lib/roadmap.ts @@ -1,4 +1,3 @@ -import { NextApiRequest } from 'next'; import roadmaps from '../content/roadmaps.json'; export type RoadmapType = { diff --git a/pages/guides/[guide].tsx b/pages/guides/[guide].tsx index af071a79f..039b84c28 100644 --- a/pages/guides/[guide].tsx +++ b/pages/guides/[guide].tsx @@ -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 ( @@ -30,3 +47,37 @@ export default function Guide() { ); } + +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) + } + }; +} diff --git a/public/authors/dmytrobol.png b/public/authors/dmytrobol.png new file mode 100644 index 000000000..5bdc96cb8 Binary files /dev/null and b/public/authors/dmytrobol.png differ diff --git a/public/authors/ebrahimbharmal007.png b/public/authors/ebrahimbharmal007.png new file mode 100644 index 000000000..148e9f2be Binary files /dev/null and b/public/authors/ebrahimbharmal007.png differ diff --git a/public/authors/jesse.png b/public/authors/jesse.png new file mode 100644 index 000000000..a02fc7972 Binary files /dev/null and b/public/authors/jesse.png differ diff --git a/public/authors/kamranahmedse.jpeg b/public/authors/kamranahmedse.jpeg new file mode 100644 index 000000000..5c743b583 Binary files /dev/null and b/public/authors/kamranahmedse.jpeg differ diff --git a/public/authors/lesovsky.jpeg b/public/authors/lesovsky.jpeg new file mode 100644 index 000000000..c62c8b458 Binary files /dev/null and b/public/authors/lesovsky.jpeg differ diff --git a/public/authors/spekulatius.jpg b/public/authors/spekulatius.jpg new file mode 100644 index 000000000..9061fe242 Binary files /dev/null and b/public/authors/spekulatius.jpg differ